This commit is contained in:
Paul Schaub 2020-01-04 22:56:34 +01:00
parent dc50bf9468
commit 84b5461c11
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
14 changed files with 182 additions and 79 deletions

View file

@ -15,6 +15,8 @@ import org.jxmpp.stringprep.XmppStringprepException;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.Messenger;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.IAccount;
import javax.inject.Inject;
@ -77,10 +79,11 @@ public class LoginViewModel extends AndroidViewModel {
return;
}
loginButtonEnabled.setValue(false);
Account account = new IAccount();
account.setAddress(username.asUnescapedString());
account.setPassword(password);
disposable.add(messenger.addAccount()
.setAddress(username.asEntityBareJidString())
.setPassword(password)
.execute()
.execute(account)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnComplete(this::signalLoginSuccessful)

View file

@ -6,6 +6,7 @@ import org.mercury_im.messenger.data.di.InMemoryDatabaseComponent;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.IAccount;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -117,4 +118,14 @@ public class AccountRepositoryTest {
Thread.sleep(1000);
d.dispose();
}
@Test(expected = NoSuchElementException.class)
public void updateMissingEntityFails() {
Account missingAccount = new IAccount();
missingAccount.setAddress("this@account.is.missing");
missingAccount.setPassword("inTheDatabase");
accountRepository.updateAccount(missingAccount)
.blockingGet();
}
}

View file

@ -0,0 +1,17 @@
package org.mercury_im.messenger;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.xmpp.MercuryConnection;
import java.util.UUID;
interface ConnectionRegistry {
default MercuryConnection getConnection(Account account) {
return getConnection(account.getId());
}
MercuryConnection getConnection(UUID accountId);
void addConnection(MercuryConnection connection);
}

View file

@ -1,14 +1,11 @@
package org.mercury_im.messenger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
import org.mercury_im.messenger.data.repository.Repositories;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.store.MercuryRosterStore;
import org.mercury_im.messenger.usecase.AddAccount;
import org.mercury_im.messenger.usecase.ConnectAccountsOnStartup;
import org.mercury_im.messenger.usecase.RosterStoreBinder;
import org.mercury_im.messenger.xmpp.MercuryConnection;
import java.util.HashMap;
@ -19,11 +16,10 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import io.reactivex.Scheduler;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
public class Messenger implements ClientStateListener {
public class Messenger implements ConnectionRegistry, ClientStateListener {
public static final String TAG = "MercuryIM";
private static final Logger LOGGER = Logger.getLogger(Messenger.class.getName());
@ -31,15 +27,18 @@ public class Messenger implements ClientStateListener {
private final Map<UUID, MercuryConnection> connections = new HashMap<>();
private Repositories repositories;
private final RosterStoreBinder rosterStoreBinder;
private CompositeDisposable disposable = new CompositeDisposable();
@Inject
public Messenger(Repositories repositories) {
this.repositories = repositories;
initialLogin();
this.rosterStoreBinder = new RosterStoreBinder(repositories.getAccountRepository(), repositories.getPeerRepository());
performInitialLogin();
}
public void initialLogin() {
public void performInitialLogin() {
disposable.add(repositories.getAccountRepository().observeAllAccounts().firstOrError()
.subscribeOn(Schedulers.newThread())
.subscribe(initialAccounts -> ConnectAccountsOnStartup
@ -47,19 +46,18 @@ public class Messenger implements ClientStateListener {
.execute()));
}
@Override
public void addConnection(MercuryConnection connection) {
connections.put(connection.getAccount().getId(), connection);
initRosterStore(connection);
}
private void initRosterStore(MercuryConnection connection) {
Roster.getInstanceFor(connection.getConnection())
.setRosterStore(new MercuryRosterStore(connection.getAccount(),
repositories.getPeerRepository(), repositories.getAccountRepository()));
@Override
public MercuryConnection getConnection(UUID accountId) {
return connections.get(accountId);
}
public MercuryConnection getConnection(Account account) {
return connections.get(account.getId());
public void bindConnection(MercuryConnection connection) {
rosterStoreBinder.setRosterStoreOn(connection);
}
public AddAccount addAccount() {

View file

@ -98,7 +98,7 @@ public class MercuryRosterStore implements RosterStore {
private void writeEntryToDatabase(RosterPacket.Item item) {
disposable.add(peerRepository.getOrCreatePeer(account, item.getJid().asUnescapedString())
.map(peer -> toEntity(item, peer))
.flatMap(peerRepository::updatePeer)
.flatMap(peerRepository::upsertPeer)
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + item.getJid().asUnescapedString(), error)

View file

@ -3,7 +3,6 @@ package org.mercury_im.messenger.usecase;
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.util.logging.Logger;
@ -17,9 +16,6 @@ public class AddAccount {
private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName());
private Account account;
private MercuryConnection connection;
private final AccountRepository accountRepository;
private final Messenger messenger;
@ -28,63 +24,62 @@ public class AddAccount {
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 Completable execute(Account account) {
return loginAndStoreAccountIfSuccessful(account);
}
public AddAccount setPassword(String password) {
this.account.setPassword(password);
return this;
private Completable loginAndStoreAccountIfSuccessful(Account account) {
return logIntoAccount(account).flatMap(connection ->
insertEnabledAccountIntoDatabase(account).flatMap(insertedAccount ->
updateAccountIdInConnectionSingle(insertedAccount, connection)))
.map(this::addConnectionToMessenger)
.ignoreElement();
}
public Completable execute() {
return loginAndStoreAccountIfSuccessful();
private Single<MercuryConnection> logIntoAccount(Account account) {
return getOrCreateConnectionSingle(account)
.doAfterSuccess(con -> LogIntoAccount.with(con).executeAndPossiblyThrow())
.subscribeOn(Schedulers.io());
}
public Completable loginAndStoreAccountIfSuccessful() {
return logIntoAccount()
.andThen(insertEnabledAccountIntoDatabase()).ignoreElement()
.andThen(addConnectionToMessenger());
private Single<MercuryConnection> getOrCreateConnectionSingle(Account account) {
return Single.fromCallable(() -> getOrCreateConnection(account));
}
private Single<Account> insertEnabledAccountIntoDatabase() {
private MercuryConnection getOrCreateConnection(Account account) {
MercuryConnection connection = messenger.getConnection(account);
if (connection == null) {
connection = new MercuryConnection(account);
}
return connection;
}
private Single<Account> insertEnabledAccountIntoDatabase(Account account) {
account.setEnabled(true);
return accountRepository.upsertAccount(account)
.map(this::updateAccount);
return accountRepository.upsertAccount(account);
}
private Completable addConnectionToMessenger() {
private Completable addConnectionToMessenger(MercuryConnection connection) {
return Completable.fromAction(() -> messenger.addConnection(connection));
}
private Account updateAccount(Account account) {
this.account = account;
updateAccountIdInConnection(account);
return account;
private Single<MercuryConnection> updateAccountIdInConnectionSingle(Account account, MercuryConnection connection) {
return Single.fromCallable(() -> {
updateAccountIdInConnection(account, connection);
return connection;
});
}
private void updateAccountIdInConnection(Account account) {
private void updateAccountIdInConnection(Account account, MercuryConnection connection) {
if (connection != null) {
connection.getAccount().setId(account.getId());
}
}
private Completable logIntoAccount() {
return Completable.fromAction(this::getOrCreateConnection)
.andThen(LogIntoAccount.with(connection).executeAndPossiblyThrow())
.subscribeOn(Schedulers.io());
}
private void getOrCreateConnection() {
connection = messenger.getConnection(account);
if (connection == null) {
connection = new MercuryConnection(account);
}
}
}

View file

@ -0,0 +1,17 @@
package org.mercury_im.messenger.usecase;
import io.reactivex.Completable;
public interface AddAccountUseCase {
AddAccountTask create();
Completable execute(AddAccountTask task);
interface AddAccountTask {
void setAddress(String address);
void setPassword(String password);
}
}

View file

@ -31,6 +31,9 @@ public class LogIntoAccount {
}
public static LogIntoAccount with(MercuryConnection connection) {
if (connection == null) {
throw new NullPointerException("MercuryConnection cannot be null.");
}
return new LogIntoAccount(connection);
}
@ -62,7 +65,9 @@ public class LogIntoAccount {
private void doAuthenticateIfNecessary()
throws InterruptedException, XMPPException, SmackException, IOException {
if (!connection.getConnection().isAuthenticated()) {
LOGGER.log(Level.INFO, "Logging in");
((AbstractXMPPConnection) connection.getConnection()).connect().login();
LOGGER.log(Level.INFO, "Login complete");
}
}

View file

@ -0,0 +1,30 @@
package org.mercury_im.messenger.usecase;
import org.jivesoftware.smack.roster.Roster;
import org.mercury_im.messenger.data.repository.AccountRepository;
import org.mercury_im.messenger.data.repository.PeerRepository;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.store.MercuryRosterStore;
import org.mercury_im.messenger.xmpp.MercuryConnection;
public class RosterStoreBinder {
private final AccountRepository accountRepository;
private final PeerRepository peerRepository;
public RosterStoreBinder(AccountRepository accountRepository, PeerRepository peerRepository) {
this.accountRepository = accountRepository;
this.peerRepository = peerRepository;
}
public void setRosterStoreOn(MercuryConnection connection) {
MercuryRosterStore store =
createRosterStore(connection.getAccount(), accountRepository, peerRepository);
Roster roster = Roster.getInstanceFor(connection.getConnection());
roster.setRosterStore(store);
}
private MercuryRosterStore createRosterStore(Account account, AccountRepository accountRepository, PeerRepository peerRepository) {
return new MercuryRosterStore(account, peerRepository, accountRepository);
}
}

View file

@ -1,23 +0,0 @@
package org.mercury_im.messenger.usecase;
import org.mercury_im.messenger.entity.chat.DirectChat;
import org.mercury_im.messenger.entity.message.Message;
public class SendDirectMessage {
private final Message message;
private final DirectChat chat;
public SendDirectMessage(Message message, DirectChat chat) {
this.message = message;
this.chat = chat;
}
public Message getMessage() {
return message;
}
public DirectChat getChat() {
return chat;
}
}

View file

@ -0,0 +1,17 @@
package org.mercury_im.messenger.learning_tests.smack;
import org.junit.Test;
import org.mercury_im.messenger.usecase.AddAccountUseCase;
import java.util.UUID;
public class AddAccountUseCaseTest {
@Test
public void test() {
AddAccountUseCase useCase;
AddAccountUseCase.AddAccountTask task;
System.out.println(UUID.randomUUID());
}
}

View file

@ -0,0 +1,27 @@
package org.mercury_im.messenger.learning_tests.smack;
import org.junit.Test;
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 org.mercury_im.messenger.xmpp.MercuryConnectionManager;
import java.util.UUID;
public class ConnectionRegistrationTest {
AccountRepository accountRepository;
@Test
public void test() {
MercuryConnectionManager manager = new MercuryConnectionManager(accountRepository);
UUID accountId = UUID.randomUUID();
Account account = new IAccount(accountId);
account.setAddress("test@add.res");
account.setPassword("monomono");
MercuryConnection connection = new MercuryConnection(account);
manager.registerConnection(connection);
}
}

View file

@ -9,6 +9,8 @@ import java.util.UUID;
*/
public interface Account {
UUID UNASSIGNED = UUID.fromString("00000000-0000-0000-0000-000000000000");
void setId(UUID id);
UUID getId();

View file

@ -19,6 +19,10 @@ public class IAccount implements Account {
this.id = id;
}
public static Account createUnassignedAccount() {
return new IAccount(Account.UNASSIGNED);
}
@Override
public void setId(UUID id) {
this.id = id;