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

129 lines
4.2 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.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.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.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
public class AddAccount {
private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName());
public enum ConnectionResult {
success,
credential_error,
server_error,
other_error
}
private Account account;
private MercuryConnection connection;
private final AccountRepository accountRepository;
private final Messenger messenger;
private final CompositeDisposable disposable = new CompositeDisposable();
public AddAccount(AccountRepository accountRepository, Messenger messenger) {
this.accountRepository = accountRepository;
this.messenger = messenger;
this.account = new IAccount();
}
public AddAccount setAddress(String address) {
this.account.setAddress(address);
return this;
}
public AddAccount setPassword(String password) {
this.account.setPassword(password);
return this;
}
public Completable execute() {
return loginAndStoreAccountIfSuccessful();
}
public Completable loginAndStoreAccountIfSuccessful() {
return logIntoAccount()
.andThen(insertEnabledAccountIntoDatabase()).ignoreElement()
.andThen(addConnectionToMessenger());
}
private Single<Account> insertEnabledAccountIntoDatabase() {
account.setEnabled(true);
return accountRepository.upsertAccount(account)
.map(this::updateAccount);
}
private Completable addConnectionToMessenger() {
return Completable.fromAction(() -> messenger.addConnection(connection));
}
private Account updateAccount(Account account) {
this.account = account;
updateAccountIdInConnection(account);
return account;
}
private void updateAccountIdInConnection(Account account) {
if (connection != null) {
connection.getAccount().setId(account.getId());
}
}
private Completable logIntoAccount() {
return Completable.fromAction(
() -> {
getOrCreateConnection();
doAuthenticateIfNecessary();
})
.subscribeOn(Schedulers.io());
}
private void getOrCreateConnection() {
connection = messenger.getConnection(account);
if (connection == null) {
connection = new MercuryConnection(account);
}
}
private ConnectionResult authenticateIfNecessary() {
try {
doAuthenticateIfNecessary();
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()
throws InterruptedException, XMPPException, SmackException, IOException {
if (!connection.getConnection().isAuthenticated()) {
((AbstractXMPPConnection) connection.getConnection()).connect().login();
}
}
}