2020-06-06 18:45:20 +02:00
|
|
|
package org.mercury_im.messenger.core.xmpp;
|
2019-12-26 08:46:55 +01:00
|
|
|
|
2020-06-05 16:35:16 +02:00
|
|
|
import org.jivesoftware.smack.chat2.ChatManager;
|
2020-05-31 22:32:33 +02:00
|
|
|
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
2020-06-06 18:45:20 +02:00
|
|
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
|
|
|
import org.mercury_im.messenger.core.data.repository.DirectChatRepository;
|
|
|
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
|
|
|
import org.mercury_im.messenger.core.data.repository.PeerRepository;
|
|
|
|
import org.mercury_im.messenger.core.data.repository.Repositories;
|
|
|
|
import org.mercury_im.messenger.core.xmpp.state.ConnectionPoolState;
|
2019-12-26 12:14:52 +01:00
|
|
|
import org.mercury_im.messenger.entity.Account;
|
2020-06-06 18:45:20 +02:00
|
|
|
import org.mercury_im.messenger.core.store.MercuryEntityCapsStore;
|
|
|
|
import org.mercury_im.messenger.core.store.MercuryMessageStore;
|
|
|
|
import org.mercury_im.messenger.core.usecase.RosterStoreBinder;
|
|
|
|
import org.mercury_im.messenger.core.util.Optional;
|
|
|
|
import org.mercury_im.messenger.core.xmpp.state.ConnectionState;
|
2019-12-26 12:14:52 +01:00
|
|
|
|
2020-01-05 15:54:44 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
2019-12-26 12:14:52 +01:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.UUID;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
|
|
import javax.inject.Inject;
|
2020-01-06 01:27:11 +01:00
|
|
|
import javax.inject.Singleton;
|
2019-12-26 12:14:52 +01:00
|
|
|
|
2020-06-06 16:45:20 +02:00
|
|
|
import io.reactivex.Completable;
|
2019-12-26 12:14:52 +01:00
|
|
|
import io.reactivex.Observable;
|
|
|
|
import io.reactivex.disposables.CompositeDisposable;
|
2020-05-05 22:08:04 +02:00
|
|
|
import io.reactivex.disposables.Disposable;
|
2020-01-06 01:27:11 +01:00
|
|
|
import io.reactivex.schedulers.Schedulers;
|
2020-01-05 23:13:58 +01:00
|
|
|
import io.reactivex.subjects.BehaviorSubject;
|
2019-12-26 12:14:52 +01:00
|
|
|
|
2020-01-06 01:27:11 +01:00
|
|
|
@Singleton
|
2019-12-26 08:46:55 +01:00
|
|
|
public class MercuryConnectionManager {
|
2019-12-26 12:14:52 +01:00
|
|
|
|
2020-01-06 03:41:37 +01:00
|
|
|
private static final Logger LOGGER = Logger.getLogger("ConnectionManager");
|
2020-06-06 18:54:56 +02:00
|
|
|
private final XmppConnectionFactory connectionFactory;
|
2019-12-26 12:14:52 +01:00
|
|
|
|
|
|
|
private final AccountRepository accountRepository;
|
2020-01-06 01:27:11 +01:00
|
|
|
private final RosterStoreBinder rosterStoreBinder;
|
2020-01-06 03:41:37 +01:00
|
|
|
private final MercuryEntityCapsStore entityCapsStore;
|
2020-06-05 16:35:16 +02:00
|
|
|
private final PeerRepository peerRepository;
|
|
|
|
private final DirectChatRepository directChatRepository;
|
|
|
|
private final MessageRepository messageRepository;
|
2019-12-26 12:14:52 +01:00
|
|
|
|
2020-05-23 12:01:31 +02:00
|
|
|
private final Map<UUID, MercuryConnection> connectionsMap = new ConcurrentHashMap<>();
|
|
|
|
private final Map<UUID, Disposable> connectionDisposables = new ConcurrentHashMap<>();
|
|
|
|
private final BehaviorSubject<ConnectionPoolState> connectionPoolObservable =
|
|
|
|
BehaviorSubject.createDefault(new ConnectionPoolState());
|
|
|
|
|
2019-12-26 12:14:52 +01:00
|
|
|
private final CompositeDisposable disposable = new CompositeDisposable();
|
|
|
|
|
2020-01-06 03:41:37 +01:00
|
|
|
static {
|
2020-05-23 12:01:31 +02:00
|
|
|
SmackConfig.staticConfiguration();
|
2020-01-06 03:41:37 +01:00
|
|
|
}
|
|
|
|
|
2019-12-26 12:14:52 +01:00
|
|
|
@Inject
|
2020-01-06 03:41:37 +01:00
|
|
|
public MercuryConnectionManager(Repositories repositories,
|
|
|
|
RosterStoreBinder rosterStoreBinder,
|
2020-06-06 18:54:56 +02:00
|
|
|
MercuryEntityCapsStore entityCapsStore,
|
|
|
|
XmppConnectionFactory connectionFactory) {
|
2020-01-06 01:27:11 +01:00
|
|
|
this.accountRepository = repositories.getAccountRepository();
|
|
|
|
this.rosterStoreBinder = rosterStoreBinder;
|
2020-01-06 03:41:37 +01:00
|
|
|
this.entityCapsStore = entityCapsStore;
|
2020-06-05 16:35:16 +02:00
|
|
|
this.peerRepository = repositories.getPeerRepository();
|
|
|
|
this.directChatRepository = repositories.getDirectChatRepository();
|
|
|
|
this.messageRepository = repositories.getMessageRepository();
|
2020-06-06 18:54:56 +02:00
|
|
|
this.connectionFactory = connectionFactory;
|
2020-01-06 03:41:37 +01:00
|
|
|
|
2020-05-31 22:32:33 +02:00
|
|
|
EntityCapsManager.setPersistentCache(entityCapsStore);
|
2020-05-23 12:01:31 +02:00
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void start() {
|
|
|
|
accountRepository.observeAllAccounts()
|
2020-06-06 16:45:20 +02:00
|
|
|
.subscribe(accounts -> doRegisterConnections(accounts));
|
2019-12-26 12:14:52 +01:00
|
|
|
}
|
|
|
|
|
2020-01-05 15:54:44 +01:00
|
|
|
public List<MercuryConnection> getConnections() {
|
2020-05-23 12:01:31 +02:00
|
|
|
return new ArrayList<>(connectionsMap.values());
|
2020-01-05 15:54:44 +01:00
|
|
|
}
|
|
|
|
|
2020-05-15 17:05:11 +02:00
|
|
|
public Observable<ConnectionPoolState> observeConnectionPool() {
|
2020-05-23 12:01:31 +02:00
|
|
|
return connectionPoolObservable;
|
2020-05-05 22:08:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-05 15:54:44 +01:00
|
|
|
public MercuryConnection getConnection(Account account) {
|
|
|
|
return getConnection(account.getId());
|
|
|
|
}
|
|
|
|
|
|
|
|
public MercuryConnection getConnection(UUID id) {
|
2020-05-23 12:01:31 +02:00
|
|
|
return connectionsMap.get(id);
|
2020-01-05 15:54:44 +01:00
|
|
|
}
|
|
|
|
|
2020-05-11 16:31:07 +02:00
|
|
|
public MercuryConnection createConnection(Account account) {
|
|
|
|
return new MercuryConnection(connectionFactory.createConnection(account), account);
|
|
|
|
}
|
|
|
|
|
2020-06-06 16:45:20 +02:00
|
|
|
public void doRegisterConnections(List<Account> accounts) {
|
2020-01-06 01:27:11 +01:00
|
|
|
for (Account account : accounts) {
|
2020-05-23 12:01:31 +02:00
|
|
|
if (!connectionsMap.containsKey(account.getId())) {
|
2020-05-11 16:31:07 +02:00
|
|
|
MercuryConnection connection = createConnection(account);
|
2020-06-06 16:45:20 +02:00
|
|
|
doRegisterConnection(connection);
|
2020-05-05 22:08:04 +02:00
|
|
|
}
|
2020-01-06 01:27:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-06 16:45:20 +02:00
|
|
|
public Completable registerConnection(MercuryConnection connection) {
|
|
|
|
return Completable.fromAction(() -> doRegisterConnection(connection));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void doRegisterConnection(MercuryConnection connection) {
|
2020-05-05 22:08:04 +02:00
|
|
|
LOGGER.log(Level.INFO, "Register Connection " + connection.getAccountId());
|
2020-01-05 23:13:58 +01:00
|
|
|
putConnection(connection);
|
2020-01-06 01:27:11 +01:00
|
|
|
disposable.add(accountRepository
|
2020-05-05 22:08:04 +02:00
|
|
|
.observeAccount(connection.getAccountId())
|
2020-01-06 01:27:11 +01:00
|
|
|
.subscribeOn(Schedulers.newThread())
|
|
|
|
.observeOn(Schedulers.newThread())
|
|
|
|
.subscribe(event ->
|
|
|
|
handleOptionalAccountChangedEvent(connection, event)));
|
2019-12-26 12:14:52 +01:00
|
|
|
}
|
|
|
|
|
2020-01-05 23:13:58 +01:00
|
|
|
private void putConnection(MercuryConnection connection) {
|
2020-05-23 12:01:31 +02:00
|
|
|
connectionsMap.put(connection.getAccountId(), connection);
|
2020-05-05 22:08:04 +02:00
|
|
|
connectionDisposables.put(connection.getAccountId(), connection.observeConnection().subscribe(s ->
|
2020-05-23 12:01:31 +02:00
|
|
|
connectionPoolObservable.onNext(updatePoolState(connectionPoolObservable.getValue(), s))));
|
2020-01-06 01:27:11 +01:00
|
|
|
bindConnection(connection);
|
2020-01-05 23:13:58 +01:00
|
|
|
}
|
|
|
|
|
2020-05-05 22:08:04 +02:00
|
|
|
private ConnectionPoolState updatePoolState(ConnectionPoolState poolState, ConnectionState conState) {
|
|
|
|
Map<UUID, ConnectionState> states = poolState.getConnectionStates();
|
|
|
|
states.put(conState.getId(), conState);
|
|
|
|
return new ConnectionPoolState(states);
|
|
|
|
}
|
|
|
|
|
2020-01-06 01:27:11 +01:00
|
|
|
public void bindConnection(MercuryConnection connection) {
|
2020-05-31 22:32:33 +02:00
|
|
|
rosterStoreBinder.setRosterStoreOn(connection);
|
2020-06-05 16:35:16 +02:00
|
|
|
accountRepository.getAccount(connection.getAccountId())
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.subscribe(account -> {
|
|
|
|
MercuryMessageStore mercuryMessageStore = new MercuryMessageStore(account, peerRepository, directChatRepository, messageRepository);
|
|
|
|
ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection());
|
|
|
|
chatManager.addIncomingListener(mercuryMessageStore);
|
|
|
|
chatManager.addOutgoingListener(mercuryMessageStore);
|
|
|
|
});
|
|
|
|
|
2020-01-05 15:54:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
2019-12-26 12:14:52 +01:00
|
|
|
if (event.isPresent()) {
|
|
|
|
handleAccountChangedEvent(connection, event.getItem());
|
|
|
|
} else {
|
|
|
|
handleAccountRemoved(connection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleAccountChangedEvent(MercuryConnection connection, Account account) {
|
|
|
|
if (account.isEnabled()) {
|
|
|
|
handleAccountEnabled(connection);
|
|
|
|
} else {
|
|
|
|
handleAccountDisabled(connection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleAccountDisabled(MercuryConnection connection) {
|
2020-05-05 22:08:04 +02:00
|
|
|
LOGGER.log(Level.FINER, "HandleAccountDisabled: " + connection.getAccountId());
|
2020-05-27 22:34:27 +02:00
|
|
|
disposable.add(connection.shutdown().subscribeOn(Schedulers.newThread()).subscribe());
|
2019-12-26 12:14:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleAccountEnabled(MercuryConnection connection) {
|
2020-05-05 22:08:04 +02:00
|
|
|
LOGGER.log(Level.FINER, "HandleAccountEnabled: " + connection.getAccountId());
|
2020-01-05 15:54:44 +01:00
|
|
|
connectionLogin(connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void connectionLogin(MercuryConnection connection) {
|
2020-05-27 22:34:27 +02:00
|
|
|
disposable.add(connection.connect().andThen(connection.login())
|
2020-05-31 22:32:33 +02:00
|
|
|
.subscribeOn(Schedulers.io())
|
2020-01-06 03:41:37 +01:00
|
|
|
.subscribe(() -> LOGGER.log(Level.FINER, "Logged in."),
|
2019-12-26 12:14:52 +01:00
|
|
|
error -> LOGGER.log(Level.SEVERE, "Connection error!", error)));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleAccountRemoved(MercuryConnection connection) {
|
2020-05-27 22:34:27 +02:00
|
|
|
LOGGER.log(Level.FINER, "HandleAccountRemove: " + connection.getAccountId());
|
2020-01-05 15:54:44 +01:00
|
|
|
disconnectAndRemoveConnection(connection);
|
2019-12-26 12:14:52 +01:00
|
|
|
}
|
|
|
|
|
2020-01-05 23:13:58 +01:00
|
|
|
private void disconnectAndRemoveConnection(MercuryConnection connection) {
|
2020-05-27 22:34:27 +02:00
|
|
|
disposable.add(connection.shutdown().subscribeOn(Schedulers.newThread()).subscribe());
|
2020-01-05 23:13:58 +01:00
|
|
|
removeConnection(connection);
|
|
|
|
}
|
|
|
|
|
2019-12-26 12:14:52 +01:00
|
|
|
private void removeConnection(MercuryConnection connection) {
|
2020-05-05 22:08:04 +02:00
|
|
|
LOGGER.log(Level.FINER, "Remove Connection: " + connection.getAccountId());
|
2020-05-23 12:01:31 +02:00
|
|
|
connectionsMap.remove(connection.getAccountId());
|
2020-05-05 22:08:04 +02:00
|
|
|
connectionDisposables.remove(connection.getAccountId()).dispose();
|
2020-05-23 12:01:31 +02:00
|
|
|
connectionPoolObservable.onNext(updatePoolState(connectionPoolObservable.getValue()));
|
2020-05-05 22:08:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private ConnectionPoolState updatePoolState(ConnectionPoolState value) {
|
|
|
|
Map<UUID, ConnectionState> states = value.getConnectionStates();
|
2020-05-23 12:01:31 +02:00
|
|
|
for (UUID id : connectionsMap.keySet()) {
|
2020-05-05 22:08:04 +02:00
|
|
|
if (!states.containsKey(id)) {
|
|
|
|
states.remove(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new ConnectionPoolState(states);
|
2019-12-26 12:14:52 +01:00
|
|
|
}
|
|
|
|
|
2020-06-06 18:45:20 +02:00
|
|
|
public void doShutdownAllConnections() {
|
|
|
|
for (MercuryConnection connection : getConnections()) {
|
|
|
|
connection.doShutdown();
|
|
|
|
}
|
|
|
|
}
|
2019-12-26 08:46:55 +01:00
|
|
|
}
|