Reimplement entity caps caching
This commit is contained in:
parent
6a1c20a548
commit
7a30921a9c
|
@ -5,6 +5,7 @@ import org.mercury_im.messenger.data.di.RepositoryModule;
|
|||
import org.mercury_im.messenger.di.module.AndroidPersistenceModule;
|
||||
import org.mercury_im.messenger.di.module.AppModule;
|
||||
import org.mercury_im.messenger.service.MercuryConnectionService;
|
||||
import org.mercury_im.messenger.store.MercuryEntityCapsStore;
|
||||
import org.mercury_im.messenger.ui.MainActivity;
|
||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
||||
import org.mercury_im.messenger.ui.chat.ChatInputFragment;
|
||||
|
@ -68,4 +69,6 @@ public interface AppComponent {
|
|||
|
||||
void inject(MercuryConnectionService service);
|
||||
|
||||
|
||||
void inject(MercuryEntityCapsStore store);
|
||||
}
|
||||
|
|
|
@ -68,9 +68,9 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
|||
holder.enabled.setOnCheckedChangeListener((compoundButton, checked) ->
|
||||
viewModel.setAccountEnabled(account, checked));
|
||||
|
||||
connection.getState()
|
||||
viewModel.getDisposable().add(connection.getState()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(state -> holder.status.setText(state.toString()));
|
||||
.subscribe(state -> holder.status.setText(state.toString())));
|
||||
|
||||
setClickListenersOnViewHolder(holder);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Map;
|
|||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import lombok.Getter;
|
||||
|
||||
public class AccountsViewModel extends AndroidViewModel {
|
||||
|
||||
|
@ -47,6 +48,10 @@ public class AccountsViewModel extends AndroidViewModel {
|
|||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
public CompositeDisposable getDisposable() {
|
||||
return compositeDisposable;
|
||||
}
|
||||
|
||||
public LiveData<List<MercuryConnection>> getConnections() {
|
||||
return connections;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ import org.mercury_im.messenger.R;
|
|||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.entity.IAccount;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
@ -74,7 +77,8 @@ public class LoginViewModel extends AndroidViewModel {
|
|||
}
|
||||
|
||||
public synchronized void login() {
|
||||
if (!loginButtonEnabled.getValue()) {
|
||||
Boolean loginEnabled = loginButtonEnabled.getValue();
|
||||
if (loginEnabled != null && !loginEnabled) {
|
||||
// Prevent race condition where account would be logged in twice
|
||||
return;
|
||||
}
|
||||
|
@ -92,6 +96,7 @@ public class LoginViewModel extends AndroidViewModel {
|
|||
}
|
||||
|
||||
private void signalLoginSuccessful() {
|
||||
Logger.getAnonymousLogger().log(Level.INFO, "Signal Login Successful");
|
||||
loginCompleted.setValue(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.mercury_im.messenger.data.di;
|
|||
|
||||
import org.mercury_im.messenger.data.mapping.AccountMapping;
|
||||
import org.mercury_im.messenger.data.mapping.DirectChatMapping;
|
||||
import org.mercury_im.messenger.data.mapping.EntityCapsMapping;
|
||||
import org.mercury_im.messenger.data.mapping.GroupChatMapping;
|
||||
import org.mercury_im.messenger.data.mapping.MessagePayloadMapping;
|
||||
import org.mercury_im.messenger.data.mapping.MessageMapping;
|
||||
|
@ -57,4 +58,10 @@ public class MappingModule {
|
|||
static MessagePayloadMapping provideMessageContentMapping() {
|
||||
return new MessagePayloadMapping();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static EntityCapsMapping provideEntityCapsMapping() {
|
||||
return new EntityCapsMapping();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package org.mercury_im.messenger.data.di;
|
|||
|
||||
import org.mercury_im.messenger.data.mapping.AccountMapping;
|
||||
import org.mercury_im.messenger.data.mapping.DirectChatMapping;
|
||||
import org.mercury_im.messenger.data.mapping.EntityCapsMapping;
|
||||
import org.mercury_im.messenger.data.mapping.GroupChatMapping;
|
||||
import org.mercury_im.messenger.data.mapping.MessageMapping;
|
||||
import org.mercury_im.messenger.data.mapping.PeerMapping;
|
||||
import org.mercury_im.messenger.data.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.data.repository.EntityCapsRepository;
|
||||
import org.mercury_im.messenger.data.repository.GroupChatRepository;
|
||||
import org.mercury_im.messenger.data.repository.MessageRepository;
|
||||
import org.mercury_im.messenger.data.repository.PeerRepository;
|
||||
|
@ -90,11 +92,12 @@ public class RepositoryModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
static XmppEntityCapsRepository provideCapsRepository(
|
||||
static EntityCapsRepository provideCapsRepository(
|
||||
ReactiveEntityStore<Persistable> data,
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler,
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
|
||||
return new XmppEntityCapsRepository(data, ioScheduler, uiScheduler);
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler,
|
||||
EntityCapsMapping entityCapsMapping) {
|
||||
return new XmppEntityCapsRepository(data, ioScheduler, uiScheduler, entityCapsMapping);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -104,8 +107,9 @@ public class RepositoryModule {
|
|||
DirectChatRepository directChatRepository,
|
||||
GroupChatRepository groupChatRepository,
|
||||
MessageRepository messageRepository,
|
||||
PeerRepository peerRepository) {
|
||||
PeerRepository peerRepository,
|
||||
XmppEntityCapsRepository entityCapsRepository) {
|
||||
return new Repositories(accountRepository, directChatRepository, groupChatRepository,
|
||||
messageRepository, peerRepository);
|
||||
messageRepository, peerRepository, entityCapsRepository);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.mercury_im.messenger.data.mapping;
|
||||
|
||||
import org.mercury_im.messenger.data.model.EntityCapsModel;
|
||||
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
|
||||
import org.mercury_im.messenger.entity.caps.IEntityCapsRecord;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
public class EntityCapsMapping extends AbstractMapping<EntityCapsRecord, EntityCapsModel> {
|
||||
|
||||
@Inject
|
||||
public EntityCapsMapping() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityCapsRecord newEntity(@NonNull EntityCapsModel model) {
|
||||
return new IEntityCapsRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityCapsModel newModel(@NonNull EntityCapsRecord entity) {
|
||||
return new EntityCapsModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityCapsModel mapToModel(@NonNull EntityCapsRecord entity, @NonNull EntityCapsModel model) {
|
||||
model.setNodeVer(entity.getNodeVer());
|
||||
model.setXml(entity.getXml());
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityCapsRecord mapToEntity(@NonNull EntityCapsModel model, @NonNull EntityCapsRecord entity) {
|
||||
entity.setNodeVer(model.getNodeVer());
|
||||
entity.setXml(model.getXml());
|
||||
return entity;
|
||||
}
|
||||
}
|
|
@ -1,21 +1,91 @@
|
|||
package org.mercury_im.messenger.data.repository;
|
||||
|
||||
import org.mercury_im.messenger.data.mapping.EntityCapsMapping;
|
||||
import org.mercury_im.messenger.data.model.EntityCapsModel;
|
||||
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
|
||||
import org.mercury_im.messenger.util.ThreadUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.query.Expression;
|
||||
import io.requery.query.ResultDelegate;
|
||||
import io.requery.reactivex.ReactiveEntityStore;
|
||||
import io.requery.reactivex.ReactiveResult;
|
||||
|
||||
public class XmppEntityCapsRepository extends RequeryRepository {
|
||||
public class XmppEntityCapsRepository extends RequeryRepository implements EntityCapsRepository {
|
||||
|
||||
private final EntityCapsMapping entityCapsMapping;
|
||||
|
||||
@Inject
|
||||
public XmppEntityCapsRepository(
|
||||
ReactiveEntityStore<Persistable> data,
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler subscriberScheduler,
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler observerScheduler) {
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler observerScheduler,
|
||||
EntityCapsMapping mapping) {
|
||||
super(data, subscriberScheduler, observerScheduler);
|
||||
this.entityCapsMapping = mapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<Map<String, EntityCapsRecord>> observeAllEntityCapsRecords() {
|
||||
return data().select(EntityCapsModel.class).get()
|
||||
.observableResult()
|
||||
.map(result -> result.toMap(EntityCapsModel.NODE_VER, new ConcurrentHashMap<>()))
|
||||
.map(this::mapModelsToEntities)
|
||||
.subscribeOn(subscriberScheduler())
|
||||
.observeOn(observerScheduler());
|
||||
}
|
||||
|
||||
private Map<String, EntityCapsRecord> mapModelsToEntities(Map<String, EntityCapsModel> models) {
|
||||
Map<String, EntityCapsRecord> entities = new ConcurrentHashMap<>();
|
||||
for (String key : models.keySet()) {
|
||||
entities.put(key, entityCapsMapping.toEntity(models.get(key)));
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
private Map<String, EntityCapsModel> mapEntitiesToModels(Map<String, EntityCapsRecord> entities) {
|
||||
Map<String, EntityCapsModel> models = new ConcurrentHashMap<>();
|
||||
for (String key : entities.keySet()) {
|
||||
models.put(key, entityCapsMapping.toModel(entities.get(key)));
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<EntityCapsRecord> observeEntityCapsRecords() {
|
||||
return data().select(EntityCapsModel.class)
|
||||
.get().observableResult()
|
||||
.flatMap(ReactiveResult::observable)
|
||||
.map(entityCapsMapping::toEntity)
|
||||
.subscribeOn(subscriberScheduler())
|
||||
.observeOn(observerScheduler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<EntityCapsRecord> maybeGetEntityCapsRecord(String nodeVer) {
|
||||
return data().select(EntityCapsModel.class)
|
||||
.where(EntityCapsModel.NODE_VER.eq(nodeVer))
|
||||
.get().maybe()
|
||||
.map(entityCapsMapping::toEntity)
|
||||
.subscribeOn(subscriberScheduler())
|
||||
.observeOn(observerScheduler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable insertEntityCapsRecord(EntityCapsRecord entityCapsRecord) {
|
||||
return data().upsert(entityCapsMapping.toModel(entityCapsRecord))
|
||||
.ignoreElement()
|
||||
.subscribeOn(subscriberScheduler())
|
||||
.observeOn(observerScheduler());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.mercury_im.messenger.data.di;
|
|||
|
||||
|
||||
import org.mercury_im.messenger.data.mapping.AccountMappingTest;
|
||||
import org.mercury_im.messenger.data.mapping.EntityCapsMappingTest;
|
||||
import org.mercury_im.messenger.data.mapping.PeerMappingTest;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
@ -15,4 +16,6 @@ public interface MappingTestComponent {
|
|||
void inject(AccountMappingTest test);
|
||||
|
||||
void inject(PeerMappingTest test);
|
||||
|
||||
void inject(EntityCapsMappingTest test);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package org.mercury_im.messenger.data.mapping;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mercury_im.messenger.data.di.DaggerMappingTestComponent;
|
||||
import org.mercury_im.messenger.data.model.EntityCapsModel;
|
||||
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
|
||||
import org.mercury_im.messenger.entity.caps.IEntityCapsRecord;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
|
||||
public class EntityCapsMappingTest {
|
||||
|
||||
@Inject
|
||||
EntityCapsMapping mapping;
|
||||
|
||||
public EntityCapsMappingTest() {
|
||||
DaggerMappingTestComponent.create().inject(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapEntityToModelTest() {
|
||||
EntityCapsRecord entity = new IEntityCapsRecord();
|
||||
entity.setNodeVer("thisisahash");
|
||||
entity.setXml("<xml/>");
|
||||
|
||||
EntityCapsModel model = mapping.toModel(entity);
|
||||
|
||||
assertEquals(entity.getNodeVer(), model.getNodeVer());
|
||||
assertEquals(entity.getXml(), model.getXml());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapModelToEntityTest() {
|
||||
EntityCapsModel model = new EntityCapsModel();
|
||||
model.setNodeVer("q07IKJEyjvHSyhy//CH0CxmKi8w=");
|
||||
model.setXml("<query xmlns='http://jabber.org/protocol/disco#info'" +
|
||||
" node='http://psi-im.org#q07IKJEyjvHSyhy//CH0CxmKi8w='>" +
|
||||
" <identity xml:lang='en' category='client' name='Psi 0.11' type='pc'/>" +
|
||||
" <identity xml:lang='el' category='client' name='Ψ 0.11' type='pc'/>" +
|
||||
" <feature var='http://jabber.org/protocol/caps'/>" +
|
||||
" <feature var='http://jabber.org/protocol/disco#info'/>" +
|
||||
" <feature var='http://jabber.org/protocol/disco#items'/>" +
|
||||
" <feature var='http://jabber.org/protocol/muc'/>" +
|
||||
" <x xmlns='jabber:x:data' type='result'>" +
|
||||
" <field var='FORM_TYPE' type='hidden'>" +
|
||||
" <value>urn:xmpp:dataforms:softwareinfo</value>" +
|
||||
" </field>" +
|
||||
" <field var='ip_version'>" +
|
||||
" <value>ipv4</value>" +
|
||||
" <value>ipv6</value>" +
|
||||
" </field>" +
|
||||
" <field var='os'>" +
|
||||
" <value>Mac</value>" +
|
||||
" </field>" +
|
||||
" <field var='os_version'>" +
|
||||
" <value>10.5.1</value>" +
|
||||
" </field>" +
|
||||
" <field var='software'>" +
|
||||
" <value>Psi</value>" +
|
||||
" </field>" +
|
||||
" <field var='software_version'>" +
|
||||
" <value>0.11</value>" +
|
||||
" </field>" +
|
||||
" </x>" +
|
||||
" </query>");
|
||||
|
||||
EntityCapsRecord entity = mapping.toEntity(model);
|
||||
|
||||
assertEquals(model.getNodeVer(), entity.getNodeVer());
|
||||
assertEquals(model.getXml(), entity.getXml());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.mercury_im.messenger.data.repository;
|
||||
|
||||
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
public interface EntityCapsRepository {
|
||||
|
||||
Observable<Map<String, EntityCapsRecord>> observeAllEntityCapsRecords();
|
||||
|
||||
Observable<EntityCapsRecord> observeEntityCapsRecords();
|
||||
|
||||
Maybe<EntityCapsRecord> maybeGetEntityCapsRecord(String nodeVer);
|
||||
|
||||
Completable insertEntityCapsRecord(EntityCapsRecord entityCapsRecord);
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
package org.mercury_im.messenger.data.repository;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class Repositories {
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
|
@ -9,18 +13,21 @@ public class Repositories {
|
|||
private final GroupChatRepository groupChatRepository;
|
||||
private final MessageRepository messageRepository;
|
||||
private final PeerRepository peerRepository;
|
||||
private final EntityCapsRepository entityCapsRepository;
|
||||
|
||||
@Inject
|
||||
public Repositories(AccountRepository accountRepository,
|
||||
DirectChatRepository directChatRepository,
|
||||
GroupChatRepository groupChatRepository,
|
||||
MessageRepository messageRepository,
|
||||
PeerRepository peerRepository) {
|
||||
PeerRepository peerRepository,
|
||||
EntityCapsRepository entityCapsRepository) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.directChatRepository = directChatRepository;
|
||||
this.groupChatRepository = groupChatRepository;
|
||||
this.messageRepository = messageRepository;
|
||||
this.peerRepository = peerRepository;
|
||||
this.entityCapsRepository = entityCapsRepository;
|
||||
}
|
||||
|
||||
public AccountRepository getAccountRepository() {
|
||||
|
@ -42,4 +49,8 @@ public class Repositories {
|
|||
public PeerRepository getPeerRepository() {
|
||||
return peerRepository;
|
||||
}
|
||||
|
||||
public EntityCapsRepository getEntityCapsRepository() {
|
||||
return entityCapsRepository;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package org.mercury_im.messenger.logging;
|
||||
|
||||
public class Tags {
|
||||
|
||||
public static final String TAG_XMPP = "MercuryXMPP";
|
||||
public static final String TAG_DB = "MercuryDB";
|
||||
public static final String TAG_ANDROID = "MercuryAndroid";
|
||||
public static final String TAG_DOMAIN = "MercuryDomain";
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package org.mercury_im.messenger.store;
|
||||
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.mercury_im.messenger.data.repository.EntityCapsRepository;
|
||||
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
|
||||
import org.mercury_im.messenger.entity.caps.IEntityCapsRecord;
|
||||
import org.mercury_im.messenger.logging.Tags;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
@Singleton
|
||||
public class MercuryEntityCapsStore implements EntityCapsPersistentCache {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(Tags.TAG_DOMAIN);
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
private final EntityCapsRepository repository;
|
||||
|
||||
@Inject
|
||||
public MercuryEntityCapsStore(EntityCapsRepository entityCapsRepository) {
|
||||
this.repository = entityCapsRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
|
||||
LOGGER.log(Level.INFO, "MercuryEntityCapsStore: addDiscoverInfoByNodePersistent: " + nodeVer);
|
||||
EntityCapsRecord record = new IEntityCapsRecord();
|
||||
record.setNodeVer(nodeVer);
|
||||
record.setXml(info.toXML().toString());
|
||||
|
||||
disposable.add(repository.insertEntityCapsRecord(record).subscribe());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscoverInfo lookup(String nodeVer) {
|
||||
LOGGER.log(Level.INFO, "MercuryEntityCapsStore: lookup: " + nodeVer);
|
||||
return repository.maybeGetEntityCapsRecord(nodeVer)
|
||||
.map(this::parseDiscoverInfo)
|
||||
.onErrorComplete()
|
||||
.blockingGet();
|
||||
}
|
||||
|
||||
private DiscoverInfo parseDiscoverInfo(EntityCapsRecord record) throws Exception {
|
||||
XmlPullParser parser = PacketParserUtils.getParserFor(new StringReader(record.getXml()));
|
||||
return (DiscoverInfo) PacketParserUtils.parseIQ(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emptyCache() {
|
||||
LOGGER.log(Level.INFO, "MercuryEntityCapsStore: emptyCache.");
|
||||
// Not needed?
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ 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;
|
||||
|
@ -31,6 +32,7 @@ public class AddAccount {
|
|||
}
|
||||
|
||||
private Completable loginAndStoreAccountIfSuccessful(Account account) {
|
||||
LOGGER.log(Level.INFO, "loginAndStoreIfSuccessful");
|
||||
return logIntoAccount(account).flatMap(connection ->
|
||||
insertEnabledAccountIntoDatabase(account).flatMap(insertedAccount ->
|
||||
updateAccountIdInConnectionSingle(insertedAccount, connection)))
|
||||
|
@ -77,8 +79,4 @@ public class AddAccount {
|
|||
connection.getAccount().setId(account.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import io.reactivex.subjects.BehaviorSubject;
|
|||
|
||||
public class MercuryConnection {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger("MercuryConnection");
|
||||
private static final XmppConnectionFactory connectionFactory = new XmppConnectionFactory();
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
@ -53,22 +54,25 @@ public class MercuryConnection {
|
|||
connection.addConnectionListener(new ConnectionListener() {
|
||||
@Override
|
||||
public void connected(XMPPConnection connection) {
|
||||
LOGGER.log(Level.FINER, "connected");
|
||||
state.onNext(ConnectionState.connected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||
LOGGER.log(Level.FINER, "authenticated. resumed? " + resumed);
|
||||
state.onNext(ConnectionState.authenticated);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
Logger.getLogger(MercuryConnection.class.getName()).log(Level.INFO, "connectionClosed.");
|
||||
LOGGER.log(Level.FINER, "connectionClosed");
|
||||
state.onNext(ConnectionState.closed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
LOGGER.log(Level.WARNING, "connectionClosedOnError");
|
||||
state.onNext(ConnectionState.closedOnError);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package org.mercury_im.messenger.xmpp;
|
||||
|
||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||
import org.mercury_im.messenger.Messenger;
|
||||
import org.jivesoftware.smack.ReconnectionListener;
|
||||
import org.jivesoftware.smack.ReconnectionManager;
|
||||
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
||||
import org.mercury_im.messenger.data.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.data.repository.Repositories;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.store.MercuryEntityCapsStore;
|
||||
import org.mercury_im.messenger.usecase.LogIntoAccount;
|
||||
import org.mercury_im.messenger.usecase.RosterStoreBinder;
|
||||
import org.mercury_im.messenger.util.Optional;
|
||||
|
@ -21,7 +24,6 @@ import javax.inject.Inject;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
@ -29,19 +31,32 @@ import io.reactivex.subjects.BehaviorSubject;
|
|||
@Singleton
|
||||
public class MercuryConnectionManager {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(MercuryConnectionManager.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger("ConnectionManager");
|
||||
|
||||
private final Map<UUID, MercuryConnection> connections = new ConcurrentHashMap<>();
|
||||
private final BehaviorSubject<Map<UUID, MercuryConnection>> connectionsSubject = BehaviorSubject.createDefault(connections);
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
|
||||
private final RosterStoreBinder rosterStoreBinder;
|
||||
private final MercuryEntityCapsStore entityCapsStore;
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
static {
|
||||
ReconnectionManager.setEnabledPerDefault(true);
|
||||
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public MercuryConnectionManager(Repositories repositories, RosterStoreBinder rosterStoreBinder) {
|
||||
public MercuryConnectionManager(Repositories repositories,
|
||||
RosterStoreBinder rosterStoreBinder,
|
||||
MercuryEntityCapsStore entityCapsStore) {
|
||||
this.accountRepository = repositories.getAccountRepository();
|
||||
this.rosterStoreBinder = rosterStoreBinder;
|
||||
this.entityCapsStore = entityCapsStore;
|
||||
|
||||
EntityCapsManager.setPersistentCache(entityCapsStore);
|
||||
}
|
||||
|
||||
public List<MercuryConnection> getConnections() {
|
||||
|
@ -86,6 +101,18 @@ public class MercuryConnectionManager {
|
|||
|
||||
public void bindConnection(MercuryConnection connection) {
|
||||
rosterStoreBinder.setRosterStoreOn(connection);
|
||||
ReconnectionManager.getInstanceFor((AbstractXMPPConnection) connection.getConnection())
|
||||
.addReconnectionListener(new ReconnectionListener() {
|
||||
@Override
|
||||
public void reconnectingIn(int seconds) {
|
||||
LOGGER.log(Level.FINER, "Reconnecting connection " + connection.getAccount().getAddress() + " in " + seconds + " seconds.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectionFailed(Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Reconnection of connection " + connection.getAccount().getAddress() + " failed.", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
||||
|
@ -105,19 +132,19 @@ public class MercuryConnectionManager {
|
|||
}
|
||||
|
||||
private void handleAccountDisabled(MercuryConnection connection) {
|
||||
LOGGER.log(Level.INFO, "HandleAccountDisabled: " + connection.getAccount().getAddress());
|
||||
shutdownConnection(connection);
|
||||
LOGGER.log(Level.FINER, "HandleAccountDisabled: " + connection.getAccount().getAddress());
|
||||
connectionDisconnect(connection);
|
||||
}
|
||||
|
||||
private void handleAccountEnabled(MercuryConnection connection) {
|
||||
LOGGER.log(Level.INFO, "HandleAccountEnabled: " + connection.getAccount().getAddress());
|
||||
LOGGER.log(Level.FINER, "HandleAccountEnabled: " + connection.getAccount().getAddress());
|
||||
connectionLogin(connection);
|
||||
}
|
||||
|
||||
private void connectionLogin(MercuryConnection connection) {
|
||||
disposable.add(LogIntoAccount.with(connection).executeAndPossiblyThrow()
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribe(() -> LOGGER.log(Level.INFO, "Logged in."),
|
||||
.subscribe(() -> LOGGER.log(Level.FINER, "Logged in."),
|
||||
error -> LOGGER.log(Level.SEVERE, "Connection error!", error)));
|
||||
}
|
||||
|
||||
|
@ -126,17 +153,18 @@ public class MercuryConnectionManager {
|
|||
}
|
||||
|
||||
private void disconnectAndRemoveConnection(MercuryConnection connection) {
|
||||
shutdownConnection(connection);
|
||||
connectionDisconnect(connection);
|
||||
removeConnection(connection);
|
||||
}
|
||||
|
||||
private void shutdownConnection(MercuryConnection connection) {
|
||||
private void connectionDisconnect(MercuryConnection connection) {
|
||||
if (connection.getConnection().isAuthenticated()) {
|
||||
((AbstractXMPPConnection) connection.getConnection()).disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeConnection(MercuryConnection connection) {
|
||||
LOGGER.log(Level.FINER, "Remove Connection: " + connection.getAccount().getAddress());
|
||||
connections.remove(connection.getAccount().getId());
|
||||
connectionsSubject.onNext(connections);
|
||||
connection.dispose();
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package org.mercury_im.messenger.entity.caps;
|
||||
|
||||
public interface EntityCapsRecord {
|
||||
|
||||
String getNodeVer();
|
||||
|
||||
void setNodeVer(String nodeVer);
|
||||
|
||||
String getXml();
|
||||
|
||||
void setXml(String xml);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.mercury_im.messenger.entity.caps;
|
||||
|
||||
public class IEntityCapsRecord implements EntityCapsRecord {
|
||||
|
||||
private String nodeVer;
|
||||
private String xml;
|
||||
|
||||
@Override
|
||||
public String getNodeVer() {
|
||||
return nodeVer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeVer(String nodeVer) {
|
||||
this.nodeVer = nodeVer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getXml() {
|
||||
return xml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setXml(String xml) {
|
||||
this.xml = xml;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue