Mercury-IM/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java

133 lines
4.5 KiB
Java

package org.mercury_im.messenger.usecase;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLErrorException;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import org.mercury_im.messenger.Messenger;
import org.mercury_im.messenger.data.repository.AccountRepository;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.IAccount;
import org.mercury_im.messenger.exception.IllegalUsernameException;
import org.mercury_im.messenger.xmpp.MercuryConnection;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.Completable;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;
public class AddAccount {
private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName());
private String username;
private String server;
private BareJid address;
private String password;
private Account account;
private final AccountRepository accountRepository;
private final Messenger messenger;
public AddAccount(AccountRepository accountRepository, Messenger messenger) {
this.accountRepository = accountRepository;
this.messenger = messenger;
}
public void setAddress(String address) {
try {
this.address = JidCreate.entityBareFrom(address);
} catch (XmppStringprepException e) {
this.address = null;
throw new IllegalUsernameException(e);
}
}
public boolean isAddressSet() {
return address != null;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isPasswordSet() {
return password != null;
}
public Single<Account> insertAccountIntoDatabase() {
Account account = new IAccount();
account.setAddress(address.asUnescapedString());
account.setPassword(password);
return accountRepository.insertAccount(account).doAfterSuccess(this::setAccount);
}
private void setAccount(Account account) {
this.account = account;
}
public Single<ConnectionResult> enableAccountAndLogin(Account account) {
return enableAccount(account).andThen(login(account));
}
private Completable enableAccount(Account account) {
account.setEnabled(true);
return accountRepository.upsertAccount(account)
.doAfterSuccess(this::setAccount)
.ignoreElement();
}
private Single<ConnectionResult> login(Account account) {
return Single.fromCallable(() -> {
MercuryConnection connection = getOrCreateConnection(account);
return authenticateIfNecessary(connection);
}).subscribeOn(Schedulers.io());
}
private MercuryConnection getOrCreateConnection(Account account) {
MercuryConnection connection = messenger.getConnection(account);
if (connection == null) {
connection = new MercuryConnection(account);
messenger.addConnection(connection);
}
return connection;
}
private ConnectionResult authenticateIfNecessary(MercuryConnection connection) {
try {
doAuthenticateIfNecessary(connection);
return ConnectionResult.success;
} catch (SASLErrorException e) {
LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + account.getAddress(), e);
return ConnectionResult.credential_error;
} catch (SmackException.ConnectionException e) {
LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + account.getAddress(), e);
return ConnectionResult.server_error;
}
catch (IOException | XMPPException | SmackException | InterruptedException e) {
LOGGER.log(Level.WARNING, "Error connecting to account " + account.getAddress(), e);
return ConnectionResult.other_error;
}
}
private void doAuthenticateIfNecessary(MercuryConnection connection)
throws InterruptedException, XMPPException, SmackException, IOException {
if (!connection.getConnection().isAuthenticated()) {
((AbstractXMPPConnection) connection.getConnection()).connect().login();
}
}
public enum ConnectionResult {
success,
credential_error,
server_error,
other_error
}
}