218 lines
8.6 KiB
Java
218 lines
8.6 KiB
Java
package org.mercury_im.messenger.core.stores;
|
|
|
|
import org.jivesoftware.smack.roster.packet.RosterPacket;
|
|
import org.jxmpp.jid.Jid;
|
|
import org.mercury_im.messenger.xmpp.model.AccountModel;
|
|
import org.mercury_im.messenger.xmpp.model.ContactModel;
|
|
import org.mercury_im.messenger.xmpp.model.EntityModel;
|
|
import org.mercury_im.messenger.xmpp.repository.RequeryAccountRepository;
|
|
import org.mercury_im.messenger.xmpp.repository.RosterRepository;
|
|
import org.mercury_im.messenger.xmpp.enums.SubscriptionDirection;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import io.reactivex.disposables.CompositeDisposable;
|
|
import io.reactivex.schedulers.Schedulers;
|
|
|
|
public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.RosterStore {
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(RosterStore.class.getName());
|
|
|
|
private final RosterRepository rosterRepository;
|
|
private final RequeryAccountRepository accountRepository;
|
|
private AccountModel account;
|
|
private CompositeDisposable disposable = null;
|
|
|
|
private final Map<Jid, RosterPacket.Item> itemMap = new HashMap<>();
|
|
private String rosterVersion;
|
|
|
|
@Inject
|
|
public RosterStore(RosterRepository rosterRepository, RequeryAccountRepository accountRepository) {
|
|
this.rosterRepository = rosterRepository;
|
|
this.accountRepository = accountRepository;
|
|
}
|
|
|
|
public void subscribe() {
|
|
LOGGER.log(Level.INFO, "Subscribing...");
|
|
if (disposable != null) {
|
|
return;
|
|
}
|
|
disposable = new CompositeDisposable();
|
|
|
|
disposable.add(rosterRepository.getAllContactsOfAccount(account)
|
|
.observeOn(Schedulers.computation())
|
|
.subscribe(contactsList -> {
|
|
itemMap.clear();
|
|
for (ContactModel contactModel : contactsList) {
|
|
itemMap.put(contactModel.getEntity().getJid(), fromModel(contactModel));
|
|
LOGGER.log(Level.INFO, "Populate itemMap with " + contactsList.toList().size() + " items");
|
|
|
|
}
|
|
},
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred while updating roster cache", error)));
|
|
|
|
disposable.add(rosterRepository.getRosterVersion(account)
|
|
.observeOn(Schedulers.computation())
|
|
.subscribe(
|
|
result -> setRosterVersion(result),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred updating cached roster version", error)));
|
|
}
|
|
|
|
public void unsubscribe() {
|
|
if (disposable == null) {
|
|
return;
|
|
}
|
|
disposable.dispose();
|
|
disposable = null;
|
|
}
|
|
|
|
public void setAccountId(long accountId) {
|
|
this.account = accountRepository.getAccount(accountId)
|
|
.doOnSubscribe(subscribe -> LOGGER.log(Level.FINE, "Fetching account " + accountId))
|
|
.blockingFirst().first();
|
|
}
|
|
|
|
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) {
|
|
return itemMap.get(bareJid);
|
|
}
|
|
|
|
@Override
|
|
public String getRosterVersion() {
|
|
return rosterVersion != null ? rosterVersion : "";
|
|
}
|
|
|
|
@Override
|
|
public boolean addEntry(RosterPacket.Item item, String version) {
|
|
LOGGER.log(Level.INFO, "Add entry " + item.toXML().toString());
|
|
// Update database
|
|
ContactModel contact = toModel(item);
|
|
disposable.add(rosterRepository.upsertContact(contact)
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + contact, error)
|
|
));
|
|
disposable.add(rosterRepository.updateRosterVersion(account, version)
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
|
|
));
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean resetEntries(Collection<RosterPacket.Item> items, String version) {
|
|
LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray()));
|
|
// Update database
|
|
// TODO: Delete other contacts
|
|
for (RosterPacket.Item item : items) {
|
|
ContactModel model = toModel(item);
|
|
disposable.add(rosterRepository.upsertContact(model)
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + model, error)
|
|
));
|
|
}
|
|
|
|
disposable.add(rosterRepository.updateRosterVersion(account, version)
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
|
|
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());
|
|
|
|
disposable.add(rosterRepository.deleteContact(account.getId(), bareJid.asEntityBareJidOrThrow())
|
|
.subscribe(
|
|
() -> LOGGER.log(Level.FINE, "Deletion of contact " + bareJid.toString() + " successful"),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred deleting contact " + bareJid.toString(), error)
|
|
));
|
|
disposable.add(rosterRepository.updateRosterVersion(account, version)
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
|
|
));
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void resetStore() {
|
|
LOGGER.log(Level.INFO, "Reset Store");
|
|
|
|
disposable.add(rosterRepository.deleteAllContactsOfAccount(account)
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Successfully reset store."),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred resetting store", error)
|
|
));
|
|
disposable.add(rosterRepository.updateRosterVersion(account, "")
|
|
.subscribe(
|
|
success -> LOGGER.log(Level.FINE, "Successfully reset roster version"),
|
|
error -> LOGGER.log(Level.WARNING, "An error occurred resetting roster version", error)
|
|
));
|
|
}
|
|
|
|
public RosterPacket.Item fromModel(ContactModel contactModel) {
|
|
RosterPacket.Item item = new RosterPacket.Item(
|
|
contactModel.getEntity().getJid(),
|
|
contactModel.getRostername());
|
|
if (contactModel.getSub_direction() != null) {
|
|
item.setItemType(convert(contactModel.getSub_direction()));
|
|
}
|
|
item.setApproved(contactModel.isSub_approved());
|
|
item.setSubscriptionPending(contactModel.isSub_pending());
|
|
return item;
|
|
}
|
|
|
|
public ContactModel toModel(RosterPacket.Item item) {
|
|
ContactModel contact = new ContactModel();
|
|
|
|
contact.setRostername(item.getName());
|
|
if (item.getItemType() != null) {
|
|
contact.setSub_direction(convert(item.getItemType()));
|
|
}
|
|
contact.setSub_approved(item.isApproved());
|
|
contact.setSub_pending(item.isSubscriptionPending());
|
|
|
|
EntityModel entity = new EntityModel();
|
|
entity.setAccount(account);
|
|
entity.setJid(item.getJid().asEntityBareJidOrThrow());
|
|
|
|
contact.setEntity(entity);
|
|
|
|
return contact;
|
|
}
|
|
|
|
public SubscriptionDirection convert(RosterPacket.ItemType type) {
|
|
return SubscriptionDirection.valueOf(type.toString());
|
|
|
|
}
|
|
|
|
public RosterPacket.ItemType convert(SubscriptionDirection direction) {
|
|
return RosterPacket.ItemType.fromString(direction.toString());
|
|
}
|
|
}
|