diff --git a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java index 700247a..c707188 100644 --- a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java +++ b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java @@ -15,6 +15,8 @@ import org.mercury_im.messenger.persistence.room.RoomModule; import org.mercury_im.messenger.persistence.room.RoomRepositoryModule; import org.mercury_im.messenger.service.XmppConnectionService; +import javax.inject.Inject; + public class MercuryImApplication extends Application { public static final String TAG = "Mercury-IM"; @@ -26,6 +28,9 @@ public class MercuryImApplication extends Application { return INSTANCE; } + @Inject + ConnectionCenter connectionCenter; + @Override public void onCreate() { super.onCreate(); @@ -36,8 +41,6 @@ public class MercuryImApplication extends Application { initializeNotificationChannels(this); - ConnectionCenter.get(); - Intent serviceIntent = new Intent(getApplicationContext(), XmppConnectionService.class); serviceIntent.setAction(XmppConnectionService.ACTION_START); diff --git a/core/src/main/java/org/mercury_im/messenger/core/ConnectionCenter.java b/core/src/main/java/org/mercury_im/messenger/core/ConnectionCenter.java index 0dc8307..90c621f 100644 --- a/core/src/main/java/org/mercury_im/messenger/core/ConnectionCenter.java +++ b/core/src/main/java/org/mercury_im/messenger/core/ConnectionCenter.java @@ -3,33 +3,77 @@ package org.mercury_im.messenger.core; import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; +import org.jivesoftware.smackx.caps.EntityCapsManager; import org.mercury_im.messenger.persistence.model.AccountModel; +import org.mercury_im.messenger.persistence.repository.AccountRepository; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import javax.inject.Inject; import javax.inject.Singleton; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.functions.Consumer; +import io.reactivex.schedulers.Schedulers; + @Singleton public class ConnectionCenter { - private static ConnectionCenter INSTANCE; + // Injected + private final AccountRepository accountRepository; + private final EntityCapsStore entityCapsStore; - private final Map connectionMap = new HashMap<>(); + // Connections + private final Map connectionMap = + Collections.synchronizedMap(new HashMap<>()); + + // Disposable for rx + private final CompositeDisposable disposable = new CompositeDisposable(); + + private final AtomicBoolean started = new AtomicBoolean(false); @Inject - EntityCapsStore capsStore; - - private ConnectionCenter() { + public ConnectionCenter(EntityCapsStore capsStore, AccountRepository accountRepository) { + this.accountRepository = accountRepository; + this.entityCapsStore = capsStore; + EntityCapsManager.setPersistentCache(capsStore); } - public static ConnectionCenter get() { - if (INSTANCE == null) { - INSTANCE = new ConnectionCenter(); + /** + * Start up the center by subscribing to changes of the {@link AccountModel accounts} in the + * database. For each new {@link AccountModel} it creates a {@link MercuryConnection} and + * stores it in the {@link #connectionMap}. + */ + @SuppressWarnings("unchecked") + public synchronized void startUp() { + + if (started.getAndSet(true)) { + // already started. + return; } - return INSTANCE; + + // otherwise subscribe to accounts and create connections. + disposable.add(accountRepository.getAllAccounts() + .observeOn(Schedulers.io()) + .subscribeOn(Schedulers.computation()) + .subscribe((Consumer>) accounts -> { + for (AccountModel account : accounts) { + if (connectionMap.get(account.getId()) != null) { + continue; + } + MercuryConnection connection = createConnection(account); + connectionMap.put(account.getId(), connection); + } + })); + } + + public MercuryConnection getConnection(AccountModel account) { + return getConnection(account.getId()); } public MercuryConnection getConnection(long accountId) { @@ -45,6 +89,8 @@ public class ConnectionCenter { .setHost(accountModel.getJid().getDomain().toString()) .setXmppAddressAndPassword(accountModel.getJid(), accountModel.getPassword()) .setConnectTimeout(2 * 60 * 1000) + .setEnabledSSLCiphers(MercuryConfiguration.enabledCiphers) + .setEnabledSSLProtocols(MercuryConfiguration.enabledProtocols) .build(); AbstractXMPPConnection tcpConnection = new XMPPTCPConnection(configuration); diff --git a/core/src/main/java/org/mercury_im/messenger/core/EntityCapsStore.java b/core/src/main/java/org/mercury_im/messenger/core/EntityCapsStore.java index 40d2e47..a7fe306 100644 --- a/core/src/main/java/org/mercury_im/messenger/core/EntityCapsStore.java +++ b/core/src/main/java/org/mercury_im/messenger/core/EntityCapsStore.java @@ -26,8 +26,6 @@ import io.reactivex.schedulers.Schedulers; public class EntityCapsStore implements EntityCapsPersistentCache { - private static final Logger LOGGER = Logger.getLogger(EntityCapsStore.class.getName()); - private final EntityCapsRepository entityCapsRepository; private final Map discoverInfoMap = new HashMap<>(); @@ -36,8 +34,6 @@ public class EntityCapsStore implements EntityCapsPersistentCache { @Inject public EntityCapsStore(EntityCapsRepository repository) { this.entityCapsRepository = repository; - EntityCapsManager.setPersistentCache(this); - LOGGER.log(Level.INFO, "EntityCapsStore set."); } private void populateFromDatabase() { diff --git a/core/src/main/java/org/mercury_im/messenger/core/MercuryConfiguration.java b/core/src/main/java/org/mercury_im/messenger/core/MercuryConfiguration.java new file mode 100644 index 0000000..c0f1f6e --- /dev/null +++ b/core/src/main/java/org/mercury_im/messenger/core/MercuryConfiguration.java @@ -0,0 +1,28 @@ +package org.mercury_im.messenger.core; + +public class MercuryConfiguration { + + public static final String[] enabledCiphers = { + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES256-SHA384", + "ECDHE-RSA-AES128-SHA256", + "ECDHE-RSA-AES256-SHA", + "ECDHE-RSA-AES128-SHA", + "DHE-RSA-AES256-GCM-SHA384", + "DHE-RSA-AES128-GCM-SHA256", + "DHE-RSA-AES256-SHA256", + "DHE-RSA-AES128-SHA256", + "DHE-RSA-AES256-SHA", + "DHE-RSA-CAMELLIA256-SHA", + "DHE-RSA-AES128-SHA", + "DHE-RSA-SEED-SHA", + "DHE-RSA-CAMELLIA128-SHA" + }; + + public static final String[] enabledProtocols = { + "TLSv1.1", + "TLSv1.2", + "TLSv1.3" + }; +} diff --git a/core/src/main/java/org/mercury_im/messenger/core/di/CenterModule.java b/core/src/main/java/org/mercury_im/messenger/core/di/CenterModule.java index debfdfd..abe3a10 100644 --- a/core/src/main/java/org/mercury_im/messenger/core/di/CenterModule.java +++ b/core/src/main/java/org/mercury_im/messenger/core/di/CenterModule.java @@ -1,7 +1,10 @@ package org.mercury_im.messenger.core.di; import org.mercury_im.messenger.core.ConnectionCenter; +import org.mercury_im.messenger.core.EntityCapsStore; +import org.mercury_im.messenger.persistence.repository.EntityCapsRepository; +import javax.inject.Inject; import javax.inject.Singleton; import dagger.Module; @@ -12,9 +15,14 @@ public class CenterModule { @Singleton @Provides - static ConnectionCenter provideConnectionCenter() { - return ConnectionCenter.get(); + static ConnectionCenter provideConnectionCenter(EntityCapsStore capsStore) { + return new ConnectionCenter(capsStore); } + @Singleton + @Provides + static EntityCapsStore providerEntityCapsStore(EntityCapsRepository capsRepository) { + return new EntityCapsStore(capsRepository); + } }