Mercury-IM/domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStore.java

238 lines
9.9 KiB
Java
Raw Normal View History

2020-06-09 21:52:53 +02:00
package org.mercury_im.messenger.core.store.roster;
2019-12-21 05:34:19 +01:00
import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jivesoftware.smack.roster.rosterstore.RosterStore;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
2020-06-09 21:52:53 +02:00
import org.mercury_im.messenger.core.SchedulersFacade;
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.PeerRepository;
2019-12-21 05:34:19 +01:00
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.contact.Peer;
import org.mercury_im.messenger.entity.contact.SubscriptionDirection;
2020-06-06 18:45:20 +02:00
import org.mercury_im.messenger.core.util.Optional;
2019-12-21 05:34:19 +01:00
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
2020-05-11 16:31:07 +02:00
import java.util.UUID;
2019-12-21 05:34:19 +01:00
import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
2020-05-31 22:32:33 +02:00
import io.reactivex.subjects.BehaviorSubject;
2019-12-21 05:34:19 +01:00
public class MercuryRosterStore implements RosterStore {
private static final Logger LOGGER = Logger.getLogger(RosterStore.class.getName());
private final PeerRepository peerRepository;
private final AccountRepository accountRepository;
2020-05-31 22:32:33 +02:00
private final UUID accountId;
private final BehaviorSubject<Optional<Account>> account;
2019-12-21 05:34:19 +01:00
private final CompositeDisposable disposable = new CompositeDisposable();
private final Map<String, RosterPacket.Item> itemMap = new HashMap<>();
private String rosterVersion;
2020-06-09 21:52:53 +02:00
private final SchedulersFacade schedulers;
2019-12-21 05:34:19 +01:00
2020-06-09 21:52:53 +02:00
public MercuryRosterStore(UUID accountId, PeerRepository rosterRepository, AccountRepository accountRepository, SchedulersFacade schedulers) {
2020-05-11 16:31:07 +02:00
this.accountId = accountId;
2020-05-31 22:32:33 +02:00
this.account = BehaviorSubject.create();
2019-12-21 05:34:19 +01:00
this.peerRepository = rosterRepository;
this.accountRepository = accountRepository;
2020-06-09 21:52:53 +02:00
this.schedulers = schedulers;
2020-05-11 16:31:07 +02:00
LOGGER.log(Level.INFO, "Construct Roster Store for " + accountId);
2020-05-31 22:32:33 +02:00
subscribe();
2019-12-21 05:34:19 +01:00
}
public void subscribe() {
2020-06-09 21:52:53 +02:00
// Subscribe database to behaviorSubject for quick access
2020-05-31 22:32:33 +02:00
accountRepository.observeAccount(accountId)
2020-06-09 21:52:53 +02:00
.subscribeOn(schedulers.getIoScheduler())
.observeOn(schedulers.getIoScheduler())
2020-05-31 22:32:33 +02:00
.subscribe(account);
2020-06-09 21:52:53 +02:00
2020-05-11 16:31:07 +02:00
disposable.add(peerRepository.observeAllContactsOfAccount(accountId)
2020-06-09 21:52:53 +02:00
.subscribeOn(schedulers.getIoScheduler())
.observeOn(schedulers.getIoScheduler())
2019-12-21 05:34:19 +01:00
.subscribe(contactsList -> {
itemMap.clear();
for (Peer contactModel : contactsList) {
itemMap.put(contactModel.getAddress(), fromEntity(contactModel));
LOGGER.log(Level.INFO, "Populate itemMap with " + contactsList.size() + " items");
}
},
error -> LOGGER.log(Level.WARNING, "An error occurred while updating roster cache", error)));
2020-05-31 22:32:33 +02:00
disposable.add(accountRepository.getAccount(accountId)
.map(Account::getRosterVersion)
2020-06-09 21:52:53 +02:00
.subscribeOn(schedulers.getIoScheduler())
.observeOn(schedulers.getIoScheduler())
2020-05-31 22:32:33 +02:00
.subscribe(this::setRosterVersion,
2019-12-21 05:34:19 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred updating cached roster version", error)));
2020-05-31 22:32:33 +02:00
2019-12-21 05:34:19 +01:00
}
public void unsubscribe() {
disposable.dispose();
}
private void setRosterVersion(String rosterVersion) {
this.rosterVersion = rosterVersion;
}
@Override
public List<RosterPacket.Item> getEntries() {
return new ArrayList<>(itemMap.values());
}
@Override
public RosterPacket.Item getEntry(Jid bareJid) {
2019-12-22 02:06:51 +01:00
return itemMap.get(bareJid.asUnescapedString());
2019-12-21 05:34:19 +01:00
}
@Override
public String getRosterVersion() {
return rosterVersion != null ? rosterVersion : "";
}
@Override
public boolean addEntry(RosterPacket.Item item, String version) {
2019-12-22 02:06:51 +01:00
writeEntryToDatabase(item);
2020-05-31 22:32:33 +02:00
writeRosterVersionToDatabase(version);
2019-12-22 02:06:51 +01:00
return true;
}
private void writeEntryToDatabase(RosterPacket.Item item) {
2020-05-11 16:31:07 +02:00
disposable.add(peerRepository.getOrCreatePeer(accountId, item.getJid().asUnescapedString())
2019-12-22 02:06:51 +01:00
.map(peer -> toEntity(item, peer))
2020-01-04 22:56:34 +01:00
.flatMap(peerRepository::upsertPeer)
2020-05-31 22:32:33 +02:00
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
2019-12-22 02:06:51 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + item.getJid().asUnescapedString(), error)
2019-12-21 05:34:19 +01:00
));
2019-12-22 02:06:51 +01:00
}
private void writeRosterVersionToDatabase(String version) {
2020-05-31 22:32:33 +02:00
disposable.add(accountRepository.updateRosterVersion(accountId, version)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
2020-05-31 22:32:33 +02:00
() -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
2019-12-21 05:34:19 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
));
}
@Override
public boolean resetEntries(Collection<RosterPacket.Item> items, String version) {
LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray()));
// Update database
2020-06-09 21:52:53 +02:00
disposable.add(peerRepository.deleteAllPeers(accountId).subscribe());
2019-12-21 05:34:19 +01:00
for (RosterPacket.Item item : items) {
2019-12-22 02:06:51 +01:00
writeEntryToDatabase(item);
2019-12-21 05:34:19 +01:00
}
2020-05-31 22:32:33 +02:00
disposable.add(accountRepository.updateRosterVersion(accountId, version)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
2020-05-31 22:32:33 +02:00
() -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
2019-12-21 05:34:19 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
));
return true;
}
@Override
public boolean removeEntry(Jid bareJid, String version) {
LOGGER.log(Level.INFO, "Remove entry " + bareJid.toString());
2020-05-11 16:31:07 +02:00
disposable.add(peerRepository.deletePeer(accountId, bareJid.asEntityBareJidOrThrow().asEntityBareJidString())
2020-05-31 22:32:33 +02:00
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
() -> LOGGER.log(Level.FINE, "Deletion of contact " + bareJid.toString() + " successful"),
error -> LOGGER.log(Level.WARNING, "An error occurred deleting contact " + bareJid.toString(), error)
));
2020-05-31 22:32:33 +02:00
disposable.add(accountRepository.updateRosterVersion(accountId, version)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
2020-05-31 22:32:33 +02:00
() -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
2019-12-21 05:34:19 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
));
return true;
}
@Override
public void resetStore() {
LOGGER.log(Level.INFO, "Reset Store");
2020-05-31 22:32:33 +02:00
disposable.add(peerRepository.deleteAllPeers(accountId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
2020-05-31 22:32:33 +02:00
() -> LOGGER.log(Level.FINE, "Successfully reset store."),
2019-12-21 05:34:19 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred resetting store", error)
));
2020-05-31 22:32:33 +02:00
disposable.add(accountRepository.updateRosterVersion(accountId, "")
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
2019-12-21 05:34:19 +01:00
.subscribe(
2020-05-31 22:32:33 +02:00
() -> LOGGER.log(Level.FINE, "Successfully reset roster version"),
2019-12-21 05:34:19 +01:00
error -> LOGGER.log(Level.WARNING, "An error occurred resetting roster version", error)
));
}
public RosterPacket.Item fromEntity(Peer contactModel) {
RosterPacket.Item item = new RosterPacket.Item(
JidCreate.entityBareFromOrThrowUnchecked(contactModel.getAddress()),
contactModel.getName());
if (contactModel.getSubscriptionDirection() != null) {
item.setItemType(convert(contactModel.getSubscriptionDirection()));
}
item.setApproved(contactModel.isSubscriptionApproved());
item.setSubscriptionPending(contactModel.isSubscriptionPending());
List<String> groupNames = contactModel.getGroupNames();
if (groupNames != null) {
for (String groupName : groupNames) {
item.addGroupName(groupName);
}
2020-06-05 13:45:53 +02:00
}
2019-12-21 05:34:19 +01:00
return item;
}
2019-12-22 02:06:51 +01:00
public Peer toEntity(RosterPacket.Item item, Peer peer) {
2020-05-31 22:32:33 +02:00
peer.setAccount(account.getValue().getItem());
2019-12-21 05:34:19 +01:00
peer.setAddress(item.getJid().asEntityBareJidOrThrow().asEntityBareJidString());
peer.setName(item.getName());
if (item.getItemType() != null) {
peer.setSubscriptionDirection(convert(item.getItemType()));
}
peer.setSubscriptionApproved(item.isApproved());
peer.setSubscriptionPending(item.isSubscriptionPending());
2020-06-05 13:45:53 +02:00
peer.setGroupNames(new ArrayList<>(item.getGroupNames()));
2019-12-21 05:34:19 +01:00
return peer;
}
public SubscriptionDirection convert(RosterPacket.ItemType type) {
return SubscriptionDirection.valueOf(type.toString());
}
public RosterPacket.ItemType convert(SubscriptionDirection direction) {
return RosterPacket.ItemType.fromString(direction.toString());
}
}