Wip
This commit is contained in:
parent
f58ad142cc
commit
b56b451a4b
|
@ -10,6 +10,7 @@ import org.mercury_im.messenger.di.component.DaggerAppComponent;
|
|||
import org.mercury_im.messenger.di.module.AppModule;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.service.MercuryConnectionService;
|
||||
import org.mercury_im.messenger.xmpp.CsiManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -56,7 +57,7 @@ public class MercuryImApplication extends Application {
|
|||
}
|
||||
|
||||
private void setupClientStateIndication() {
|
||||
clientStateHandler.addClientStateListener(messenger);
|
||||
clientStateHandler.addClientStateListener(new CsiManager(messenger.getConnectionManager()));
|
||||
registerActivityLifecycleCallbacks(clientStateHandler);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
|||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
return oldItems.get(oldItemPosition).getAccount().getId() == newItems.get(newItemPosition).getAccount().getId();
|
||||
return oldItems.get(oldItemPosition).getAccountId().equals(newItems.get(newItemPosition).getAccountId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,12 +17,15 @@ 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 org.mercury_im.messenger.xmpp.MercuryConnection;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
@ -86,6 +89,14 @@ public class LoginViewModel extends AndroidViewModel {
|
|||
Account account = new IAccount();
|
||||
account.setAddress(username.asUnescapedString());
|
||||
account.setPassword(password);
|
||||
MercuryConnection connection = messenger.getConnectionManager().createConnection(account);
|
||||
disposable.add(Completable.fromAction(() -> {
|
||||
connection.connect().login();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe()
|
||||
);
|
||||
disposable.add(messenger.addAccount()
|
||||
.execute(account)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
package org.mercury_im.messenger;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
|
||||
import org.mercury_im.messenger.data.repository.Repositories;
|
||||
import org.mercury_im.messenger.usecase.AddAccount;
|
||||
import org.mercury_im.messenger.usecase.RosterStoreBinder;
|
||||
import org.mercury_im.messenger.xmpp.MercuryConnection;
|
||||
import org.mercury_im.messenger.xmpp.MercuryConnectionManager;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
@ -18,7 +13,7 @@ import io.reactivex.disposables.CompositeDisposable;
|
|||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
@Singleton
|
||||
public class Messenger implements ClientStateListener {
|
||||
public class Messenger {
|
||||
|
||||
public static final String TAG = "MercuryIM";
|
||||
private static final Logger LOGGER = Logger.getLogger(Messenger.class.getName());
|
||||
|
@ -46,41 +41,4 @@ public class Messenger implements ClientStateListener {
|
|||
.subscribe(connectionManager::registerConnections));
|
||||
}
|
||||
|
||||
public AddAccount addAccount() {
|
||||
return new AddAccount(repositories.getAccountRepository(), this.connectionManager);
|
||||
}
|
||||
|
||||
// CSI
|
||||
|
||||
@Override
|
||||
public void onClientInForeground() {
|
||||
LOGGER.log(Level.INFO, "CSI: active");
|
||||
for (MercuryConnection connection : connectionManager.getConnections()) {
|
||||
tryCsiActive(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientInBackground() {
|
||||
LOGGER.log(Level.INFO, "CSI: inactive");
|
||||
for (MercuryConnection connection : connectionManager.getConnections()) {
|
||||
tryCsiInactive(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryCsiActive(MercuryConnection connection) {
|
||||
try {
|
||||
ClientStateIndicationManager.active(connection.getConnection());
|
||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING, "Sending CSI state 'active' failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryCsiInactive(MercuryConnection connection) {
|
||||
try {
|
||||
ClientStateIndicationManager.inactive(connection.getConnection());
|
||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING, "Sending CSI state 'inactive' failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -28,21 +29,21 @@ public class MercuryRosterStore implements RosterStore {
|
|||
|
||||
private final PeerRepository peerRepository;
|
||||
private final AccountRepository accountRepository;
|
||||
private Account account;
|
||||
private UUID accountId;
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private final Map<String, RosterPacket.Item> itemMap = new HashMap<>();
|
||||
private String rosterVersion;
|
||||
|
||||
public MercuryRosterStore(Account account, PeerRepository rosterRepository, AccountRepository accountRepository) {
|
||||
this.account = account;
|
||||
public MercuryRosterStore(UUID accountId, PeerRepository rosterRepository, AccountRepository accountRepository) {
|
||||
this.accountId = accountId;
|
||||
this.peerRepository = rosterRepository;
|
||||
this.accountRepository = accountRepository;
|
||||
LOGGER.log(Level.INFO, "Construct Roster Store for " + account.getId());
|
||||
LOGGER.log(Level.INFO, "Construct Roster Store for " + accountId);
|
||||
}
|
||||
|
||||
public void subscribe() {
|
||||
disposable.add(peerRepository.observeAllContactsOfAccount(account)
|
||||
disposable.add(peerRepository.observeAllContactsOfAccount(accountId)
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe(contactsList -> {
|
||||
itemMap.clear();
|
||||
|
@ -96,7 +97,7 @@ public class MercuryRosterStore implements RosterStore {
|
|||
}
|
||||
|
||||
private void writeEntryToDatabase(RosterPacket.Item item) {
|
||||
disposable.add(peerRepository.getOrCreatePeer(account, item.getJid().asUnescapedString())
|
||||
disposable.add(peerRepository.getOrCreatePeer(accountId, item.getJid().asUnescapedString())
|
||||
.map(peer -> toEntity(item, peer))
|
||||
.flatMap(peerRepository::upsertPeer)
|
||||
.subscribe(
|
||||
|
@ -139,7 +140,7 @@ public class MercuryRosterStore implements RosterStore {
|
|||
public boolean removeEntry(Jid bareJid, String version) {
|
||||
LOGGER.log(Level.INFO, "Remove entry " + bareJid.toString());
|
||||
|
||||
disposable.add(peerRepository.deletePeer(account.getId(), bareJid.asEntityBareJidOrThrow().asEntityBareJidString())
|
||||
disposable.add(peerRepository.deletePeer(accountId, bareJid.asEntityBareJidOrThrow().asEntityBareJidString())
|
||||
.subscribe(
|
||||
() -> LOGGER.log(Level.FINE, "Deletion of contact " + bareJid.toString() + " successful"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred deleting contact " + bareJid.toString(), error)
|
||||
|
@ -185,7 +186,7 @@ public class MercuryRosterStore implements RosterStore {
|
|||
}
|
||||
|
||||
public Peer toEntity(RosterPacket.Item item, Peer peer) {
|
||||
peer.setAccount(account);
|
||||
peer.setAccount(accountRepository.getAccount(accountId).blockingGet());
|
||||
peer.setAddress(item.getJid().asEntityBareJidOrThrow().asEntityBareJidString());
|
||||
peer.setName(item.getName());
|
||||
if (item.getItemType() != null) {
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
package org.mercury_im.messenger.usecase;
|
||||
|
||||
import org.mercury_im.messenger.data.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.xmpp.MercuryConnection;
|
||||
import org.mercury_im.messenger.xmpp.MercuryConnectionManager;
|
||||
|
||||
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());
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
private final MercuryConnectionManager connectionManager;
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
public AddAccount(AccountRepository accountRepository, MercuryConnectionManager connectionManager) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
public Completable execute(Account account) {
|
||||
return loginAndStoreAccountIfSuccessful(account);
|
||||
}
|
||||
|
||||
private Completable loginAndStoreAccountIfSuccessful(Account account) {
|
||||
LOGGER.log(Level.INFO, "loginAndStoreIfSuccessful");
|
||||
return logIntoAccount(account).flatMap(connection ->
|
||||
insertEnabledAccountIntoDatabase(account).flatMap(insertedAccount ->
|
||||
updateAccountIdInConnectionSingle(insertedAccount, connection)))
|
||||
.map(this::addConnectionToMessenger)
|
||||
.ignoreElement();
|
||||
}
|
||||
|
||||
private Single<MercuryConnection> logIntoAccount(Account account) {
|
||||
return getOrCreateConnectionSingle(account)
|
||||
.doAfterSuccess(con -> LogIntoAccount.with(con).executeAndPossiblyThrow())
|
||||
.subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
private Single<MercuryConnection> getOrCreateConnectionSingle(Account account) {
|
||||
return Single.fromCallable(() -> getOrCreateConnection(account));
|
||||
}
|
||||
|
||||
private MercuryConnection getOrCreateConnection(Account account) {
|
||||
MercuryConnection connection = connectionManager.getConnection(account);
|
||||
if (connection == null) {
|
||||
connection = new MercuryConnection(accountRepository, account);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private Single<Account> insertEnabledAccountIntoDatabase(Account account) {
|
||||
account.setEnabled(true);
|
||||
return accountRepository.upsertAccount(account);
|
||||
}
|
||||
|
||||
private Completable addConnectionToMessenger(MercuryConnection connection) {
|
||||
return Completable.fromAction(() -> connectionManager.registerConnection(connection));
|
||||
}
|
||||
|
||||
private Single<MercuryConnection> updateAccountIdInConnectionSingle(Account account, MercuryConnection connection) {
|
||||
return Single.fromCallable(() -> {
|
||||
updateAccountIdInConnection(account, connection);
|
||||
return connection;
|
||||
});
|
||||
}
|
||||
|
||||
private void updateAccountIdInConnection(Account account, MercuryConnection connection) {
|
||||
if (connection != null) {
|
||||
connection.getAccount().setId(account.getId());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -50,14 +50,14 @@ public class LogIntoAccount {
|
|||
doAuthenticateIfNecessary();
|
||||
return ConnectionResult.success;
|
||||
} catch (SASLErrorException e) {
|
||||
LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + connection.getAccount().getAddress(), e);
|
||||
LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + connection.getAccountId(), e);
|
||||
return ConnectionResult.credential_error;
|
||||
} catch (SmackException.ConnectionException e) {
|
||||
LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + connection.getAccount().getAddress(), e);
|
||||
LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + connection.getAccountId(), e);
|
||||
return ConnectionResult.server_error;
|
||||
}
|
||||
catch (IOException | XMPPException | SmackException | InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING, "Error connecting to account " + connection.getAccount().getAddress(), e);
|
||||
LOGGER.log(Level.WARNING, "Error connecting to account " + connection.getAccountId(), e);
|
||||
return ConnectionResult.other_error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.mercury_im.messenger.entity.Account;
|
|||
import org.mercury_im.messenger.store.MercuryRosterStore;
|
||||
import org.mercury_im.messenger.xmpp.MercuryConnection;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class RosterStoreBinder {
|
||||
|
@ -22,12 +24,12 @@ public class RosterStoreBinder {
|
|||
|
||||
public void setRosterStoreOn(MercuryConnection connection) {
|
||||
MercuryRosterStore store =
|
||||
createRosterStore(connection.getAccount(), accountRepository, peerRepository);
|
||||
createRosterStore(connection.getAccountId(), 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);
|
||||
private MercuryRosterStore createRosterStore(UUID accountId, AccountRepository accountRepository, PeerRepository peerRepository) {
|
||||
return new MercuryRosterStore(accountId, peerRepository, accountRepository);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package org.mercury_im.messenger.xmpp;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
|
||||
import org.mercury_im.messenger.ClientStateListener;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class CsiManager implements ClientStateListener {
|
||||
|
||||
private final MercuryConnectionManager connectionManager;
|
||||
private static final Logger LOGGER = Logger.getLogger(CsiManager.class.getName());
|
||||
|
||||
public CsiManager(MercuryConnectionManager connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientInForeground() {
|
||||
LOGGER.log(Level.INFO, "CSI: active");
|
||||
for (MercuryConnection connection : connectionManager.getConnections()) {
|
||||
tryCsiActive(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientInBackground() {
|
||||
LOGGER.log(Level.INFO, "CSI: inactive");
|
||||
for (MercuryConnection connection : connectionManager.getConnections()) {
|
||||
tryCsiInactive(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryCsiActive(MercuryConnection connection) {
|
||||
try {
|
||||
ClientStateIndicationManager.active(connection.getConnection());
|
||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING, "Sending CSI state 'active' failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryCsiInactive(MercuryConnection connection) {
|
||||
try {
|
||||
ClientStateIndicationManager.inactive(connection.getConnection());
|
||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
||||
LOGGER.log(Level.WARNING, "Sending CSI state 'inactive' failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,19 +5,18 @@ import org.jivesoftware.smack.ConnectionListener;
|
|||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.mercury_im.messenger.data.repository.AccountRepository;
|
||||
import org.jivesoftware.smack.sasl.SASLErrorException;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.util.Optional;
|
||||
import org.mercury_im.messenger.xmpp.exception.InvalidCredentialsException;
|
||||
import org.mercury_im.messenger.xmpp.exception.ServerUnreachableException;
|
||||
import org.mercury_im.messenger.xmpp.state.ConnectionState;
|
||||
import org.mercury_im.messenger.xmpp.state.ConnectivityState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import lombok.Getter;
|
||||
|
||||
|
@ -46,19 +45,43 @@ public class MercuryConnection {
|
|||
return state;
|
||||
}
|
||||
|
||||
public void connect() throws InterruptedException, XMPPException, SmackException, IOException {
|
||||
public MercuryConnection connect() throws ServerUnreachableException {
|
||||
if (getConnection().isConnected()) {
|
||||
return;
|
||||
return this;
|
||||
}
|
||||
((AbstractXMPPConnection) getConnection()).connect();
|
||||
doConnect();
|
||||
return this;
|
||||
}
|
||||
|
||||
public void login() throws InterruptedException, IOException, SmackException, XMPPException {
|
||||
private MercuryConnection doConnect() throws ServerUnreachableException {
|
||||
AbstractXMPPConnection connection = (AbstractXMPPConnection) getConnection();
|
||||
try {
|
||||
connection.connect();
|
||||
return this;
|
||||
} catch (SmackException.EndpointConnectionException e) {
|
||||
connection.disconnect();
|
||||
throw new ServerUnreachableException("Cannot connect to server " + connection.getXMPPServiceDomain().asUnescapedString(), e);
|
||||
} catch (IOException | InterruptedException | XMPPException | SmackException e) {
|
||||
throw new AssertionError("Unexpected exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void login() throws ServerUnreachableException, InvalidCredentialsException {
|
||||
if (getConnection().isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
connect();
|
||||
((AbstractXMPPConnection) getConnection()).login();
|
||||
doLogin();
|
||||
}
|
||||
|
||||
private void doLogin() throws InvalidCredentialsException, ServerUnreachableException {
|
||||
try {
|
||||
connect();
|
||||
((AbstractXMPPConnection) getConnection()).login();
|
||||
} catch (SASLErrorException e) {
|
||||
throw new InvalidCredentialsException("Credentials of account " + accountId + " are invalid.", e);
|
||||
} catch (InterruptedException | XMPPException | SmackException | IOException e) {
|
||||
throw new AssertionError("Unexpected exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final ConnectionListener connectionListener = new ConnectionListener() {
|
||||
|
|
|
@ -101,11 +101,14 @@ public class MercuryConnectionManager {
|
|||
return connections.get(id);
|
||||
}
|
||||
|
||||
public MercuryConnection createConnection(Account account) {
|
||||
return new MercuryConnection(connectionFactory.createConnection(account), account);
|
||||
}
|
||||
|
||||
public void registerConnections(List<Account> accounts) {
|
||||
for (Account account : accounts) {
|
||||
if (!connections.containsKey(account.getId())) {
|
||||
MercuryConnection connection = new MercuryConnection(
|
||||
connectionFactory.createConnection(account), account);
|
||||
MercuryConnection connection = createConnection(account);
|
||||
registerConnection(connection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package org.mercury_im.messenger.xmpp.exception;
|
||||
|
||||
public class InvalidCredentialsException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidCredentialsException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.mercury_im.messenger.xmpp.exception;
|
||||
|
||||
public class ServerUnreachableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ServerUnreachableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
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());
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit a71ce2ca36faab3bd026dc492b0b8ab8266440d9
|
||||
Subproject commit e79710840be6d6b3301e078a23688eafaa06013c
|
Loading…
Reference in New Issue