Start work on new message sending logic
This commit is contained in:
parent
9ea08b11da
commit
0adbcc94b0
|
@ -8,6 +8,7 @@ import org.mercury_im.messenger.android.ui.roster.contacts.AndroidContactListVie
|
||||||
import org.mercury_im.messenger.core.di.module.OpenPgpModule;
|
import org.mercury_im.messenger.core.di.module.OpenPgpModule;
|
||||||
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
|
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
|
||||||
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
|
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
|
||||||
|
import org.mercury_im.messenger.core.di.module.StanzaIdSourceFactoryModule;
|
||||||
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
|
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
|
||||||
import org.mercury_im.messenger.core.viewmodel.account.detail.AccountDetailsViewModel;
|
import org.mercury_im.messenger.core.viewmodel.account.detail.AccountDetailsViewModel;
|
||||||
import org.mercury_im.messenger.core.viewmodel.account.list.AccountListViewModel;
|
import org.mercury_im.messenger.core.viewmodel.account.list.AccountListViewModel;
|
||||||
|
@ -48,7 +49,8 @@ import dagger.Component;
|
||||||
XmppTcpConnectionFactoryModule.class,
|
XmppTcpConnectionFactoryModule.class,
|
||||||
RxMercuryMessageStoreFactoryModule.class,
|
RxMercuryMessageStoreFactoryModule.class,
|
||||||
OpenPgpModule.class,
|
OpenPgpModule.class,
|
||||||
RxMercuryRosterStoreFactoryModule.class
|
RxMercuryRosterStoreFactoryModule.class,
|
||||||
|
StanzaIdSourceFactoryModule.class
|
||||||
})
|
})
|
||||||
public interface AppComponent {
|
public interface AppComponent {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.mercury_im.messenger.data.converter;
|
package org.mercury_im.messenger.data.converter;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
|
||||||
import org.jxmpp.jid.EntityJid;
|
import org.jxmpp.jid.EntityJid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
|
||||||
|
@ -27,18 +26,15 @@ public class EntityJidConverter implements Converter<EntityJid, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String convertToPersisted(EntityJid value) {
|
public String convertToPersisted(EntityJid value) {
|
||||||
|
if (value == null) return null;
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityJid convertToMapped(Class<? extends EntityJid> type, @Nullable String value) {
|
public EntityJid convertToMapped(Class<? extends EntityJid> type, @Nullable String value) {
|
||||||
switch (type.getName()) {
|
if (value == null) {
|
||||||
case "EntityFullJid":
|
return null;
|
||||||
return JidCreate.entityFullFromOrThrowUnchecked(value);
|
|
||||||
case "EntityBareJid":
|
|
||||||
return JidCreate.entityBareFromOrThrowUnchecked(value);
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown jid type encountered: " + type.getName());
|
|
||||||
}
|
}
|
||||||
|
return JidCreate.entityFromOrThrowUnchecked(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.mercury_im.messenger.data.mapping;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.chat_markers.ChatMarkersState;
|
||||||
|
import org.mercury_im.messenger.entity.message.ChatMarkerState;
|
||||||
|
|
||||||
|
public class ChatMarkerMapping {
|
||||||
|
|
||||||
|
public static ChatMarkersState toSmackChatMarker(ChatMarkerState mercuryChatMarker) {
|
||||||
|
switch (mercuryChatMarker) {
|
||||||
|
case markable:
|
||||||
|
return ChatMarkersState.markable;
|
||||||
|
case received:
|
||||||
|
return ChatMarkersState.received;
|
||||||
|
case displayed:
|
||||||
|
return ChatMarkersState.displayed;
|
||||||
|
case acknowledged:
|
||||||
|
return ChatMarkersState.acknowledged;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Illegal ChatMarkersState: " + mercuryChatMarker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatMarkerState toMercuryChatMarker(ChatMarkersState smackChatMarker) {
|
||||||
|
switch (smackChatMarker) {
|
||||||
|
case markable:
|
||||||
|
return ChatMarkerState.markable;
|
||||||
|
case received:
|
||||||
|
return ChatMarkerState.received;
|
||||||
|
case displayed:
|
||||||
|
return ChatMarkerState.displayed;
|
||||||
|
case acknowledged:
|
||||||
|
return ChatMarkerState.acknowledged;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Illegal ChatMarkersState: " + smackChatMarker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ public class MessageMapping extends AbstractMapping<Message, MessageModel> {
|
||||||
@Override
|
@Override
|
||||||
public MessageModel mapToModel(Message entity, MessageModel model) {
|
public MessageModel mapToModel(Message entity, MessageModel model) {
|
||||||
model.setId(entity.getId());
|
model.setId(entity.getId());
|
||||||
|
model.setChatId(entity.getChatId());
|
||||||
model.setSender(entity.getSender());
|
model.setSender(entity.getSender());
|
||||||
model.setRecipient(entity.getRecipient());
|
model.setRecipient(entity.getRecipient());
|
||||||
model.setTimestamp(entity.getTimestamp());
|
model.setTimestamp(entity.getTimestamp());
|
||||||
|
@ -42,6 +43,7 @@ public class MessageMapping extends AbstractMapping<Message, MessageModel> {
|
||||||
@Override
|
@Override
|
||||||
public Message mapToEntity(MessageModel model, Message entity) {
|
public Message mapToEntity(MessageModel model, Message entity) {
|
||||||
entity.setId(model.getId());
|
entity.setId(model.getId());
|
||||||
|
entity.setChatId(model.getChatId());
|
||||||
entity.setSender(model.getSender());
|
entity.setSender(model.getSender());
|
||||||
entity.setRecipient(model.getRecipient());
|
entity.setRecipient(model.getRecipient());
|
||||||
entity.setTimestamp(model.getTimestamp());
|
entity.setTimestamp(model.getTimestamp());
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package org.mercury_im.messenger.data.model;
|
package org.mercury_im.messenger.data.model;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityJid;
|
||||||
import org.mercury_im.messenger.data.converter.EntityFullJidConverter;
|
import org.mercury_im.messenger.data.converter.EntityJidConverter;
|
||||||
import org.mercury_im.messenger.data.converter.MessageDirectionConverter;
|
import org.mercury_im.messenger.data.converter.MessageDirectionConverter;
|
||||||
import org.mercury_im.messenger.entity.Encryption;
|
import org.mercury_im.messenger.entity.Encryption;
|
||||||
|
import org.mercury_im.messenger.entity.message.ChatMarkerState;
|
||||||
|
import org.mercury_im.messenger.entity.message.MessageDeliveryState;
|
||||||
import org.mercury_im.messenger.entity.message.MessageDirection;
|
import org.mercury_im.messenger.entity.message.MessageDirection;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
|
@ -27,15 +29,16 @@ public abstract class AbstractMessageModel implements Persistable {
|
||||||
UUID id;
|
UUID id;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
|
@Convert(UUIDConverter.class)
|
||||||
UUID chatId;
|
UUID chatId;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
@Convert(EntityFullJidConverter.class)
|
@Convert(EntityJidConverter.class)
|
||||||
EntityFullJid sender;
|
EntityJid sender;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
@Convert(EntityFullJidConverter.class)
|
@Convert(EntityJidConverter.class)
|
||||||
EntityFullJid recipient;
|
EntityJid recipient;
|
||||||
|
|
||||||
@Column(name = "\"timestamp\"", nullable = false)
|
@Column(name = "\"timestamp\"", nullable = false)
|
||||||
Date timestamp;
|
Date timestamp;
|
||||||
|
@ -68,4 +71,10 @@ public abstract class AbstractMessageModel implements Persistable {
|
||||||
@Column
|
@Column
|
||||||
OpenPgpV4Fingerprint senderOXFingerprint;
|
OpenPgpV4Fingerprint senderOXFingerprint;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
ChatMarkerState chatMarkerState;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
MessageDeliveryState deliveryState;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.mercury_im.messenger.data.repository;
|
package org.mercury_im.messenger.data.repository;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
import org.mercury_im.messenger.data.mapping.DirectChatMapping;
|
import org.mercury_im.messenger.data.mapping.DirectChatMapping;
|
||||||
import org.mercury_im.messenger.data.mapping.GroupChatMapping;
|
import org.mercury_im.messenger.data.mapping.GroupChatMapping;
|
||||||
|
@ -10,7 +11,9 @@ import org.mercury_im.messenger.data.repository.dao.GroupChatDao;
|
||||||
import org.mercury_im.messenger.data.repository.dao.MessageDao;
|
import org.mercury_im.messenger.data.repository.dao.MessageDao;
|
||||||
import org.mercury_im.messenger.entity.chat.DirectChat;
|
import org.mercury_im.messenger.entity.chat.DirectChat;
|
||||||
import org.mercury_im.messenger.entity.chat.GroupChat;
|
import org.mercury_im.messenger.entity.chat.GroupChat;
|
||||||
|
import org.mercury_im.messenger.entity.message.ChatMarkerState;
|
||||||
import org.mercury_im.messenger.entity.message.Message;
|
import org.mercury_im.messenger.entity.message.Message;
|
||||||
|
import org.mercury_im.messenger.entity.message.MessageDeliveryState;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -105,7 +108,7 @@ public class RxMessageRepository
|
||||||
|
|
||||||
.from(MessageModel.class)
|
.from(MessageModel.class)
|
||||||
.where(MessageModel.BODY.like("%" + body + "%")
|
.where(MessageModel.BODY.like("%" + body + "%")
|
||||||
.and(MessageModel.CHAT_ID.eq(chat.getId())))
|
.and(MessageModel.CHAT_ID.eq(chat.getId())))
|
||||||
.get().observableResult()
|
.get().observableResult()
|
||||||
.map(ResultDelegate::toList)
|
.map(ResultDelegate::toList)
|
||||||
.map(this::messageModelsToEntities);
|
.map(this::messageModelsToEntities);
|
||||||
|
@ -117,7 +120,7 @@ public class RxMessageRepository
|
||||||
|
|
||||||
.from(MessageModel.class)
|
.from(MessageModel.class)
|
||||||
.where(MessageModel.BODY.like("%" + body + "%")
|
.where(MessageModel.BODY.like("%" + body + "%")
|
||||||
.and(MessageModel.CHAT_ID.eq(chat.getId())))
|
.and(MessageModel.CHAT_ID.eq(chat.getId())))
|
||||||
.get().observableResult()
|
.get().observableResult()
|
||||||
.map(ResultDelegate::toList)
|
.map(ResultDelegate::toList)
|
||||||
.map(this::messageModelsToEntities);
|
.map(this::messageModelsToEntities);
|
||||||
|
@ -146,6 +149,24 @@ public class RxMessageRepository
|
||||||
.get().single().ignoreElement();
|
.get().single().ignoreElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Completable markMessage(String stanzaId, EntityBareJid recipientJid, ChatMarkerState state) {
|
||||||
|
return data().update(MessageModel.class)
|
||||||
|
.set(MessageModel.CHAT_MARKER_STATE, state)
|
||||||
|
.where(MessageModel.LEGACY_ID.eq(stanzaId)
|
||||||
|
.and(MessageModel.RECIPIENT.eq(recipientJid)))
|
||||||
|
.get().single().ignoreElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Completable updateDeliveryState(UUID messageId, MessageDeliveryState deliveryState) {
|
||||||
|
return data().update(MessageModel.class)
|
||||||
|
.set(MessageModel.DELIVERY_STATE, deliveryState)
|
||||||
|
.where(MessageModel.ID.eq(messageId))
|
||||||
|
.get().single()
|
||||||
|
.ignoreElement();
|
||||||
|
}
|
||||||
|
|
||||||
private List<Message> messageModelsToEntities(List<MessageModel> models) {
|
private List<Message> messageModelsToEntities(List<MessageModel> models) {
|
||||||
List<Message> entities = new ArrayList<>(models.size());
|
List<Message> entities = new ArrayList<>(models.size());
|
||||||
for (MessageModel model : models) {
|
for (MessageModel model : models) {
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
apply plugin: 'java-library'
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
//main.java.srcDirs += "${buildDir}/generated/sources/annotationProcessor/java/main/"
|
||||||
|
test.java.srcDirs += "${buildDir}/generated/sources/annotationProcessor/java/test/"
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation project(':entity')
|
implementation project(':entity')
|
||||||
|
@ -20,7 +25,9 @@ dependencies {
|
||||||
|
|
||||||
// Dagger 2 for dependency injection
|
// Dagger 2 for dependency injection
|
||||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||||
|
testImplementation "com.google.dagger:dagger:$daggerVersion"
|
||||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||||
|
testAnnotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||||
|
|
||||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
||||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||||
|
|
|
@ -13,8 +13,13 @@ import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.connection.message.MessageConsignor;
|
||||||
|
import org.mercury_im.messenger.core.connection.message.OxMessageConsignor;
|
||||||
|
import org.mercury_im.messenger.core.connection.message.PlaintextMessageConsignor;
|
||||||
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
import org.mercury_im.messenger.core.exception.ConnectionNotFoundException;
|
import org.mercury_im.messenger.core.exception.ConnectionNotFoundException;
|
||||||
import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException;
|
import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException;
|
||||||
|
import org.mercury_im.messenger.entity.chat.Chat;
|
||||||
import org.mercury_im.messenger.entity.contact.Peer;
|
import org.mercury_im.messenger.entity.contact.Peer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -34,12 +39,15 @@ public class Messenger {
|
||||||
private static final Logger LOGGER = Logger.getLogger(Messenger.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(Messenger.class.getName());
|
||||||
|
|
||||||
private final MercuryConnectionManager connectionManager;
|
private final MercuryConnectionManager connectionManager;
|
||||||
|
private final MessageRepository messageRepository;
|
||||||
private final SchedulersFacade schedulers;
|
private final SchedulersFacade schedulers;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Messenger(MercuryConnectionManager connectionManager,
|
public Messenger(MercuryConnectionManager connectionManager,
|
||||||
|
MessageRepository messageRepository,
|
||||||
SchedulersFacade schedulers) {
|
SchedulersFacade schedulers) {
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
|
this.messageRepository = messageRepository;
|
||||||
this.schedulers = schedulers;
|
this.schedulers = schedulers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,4 +135,16 @@ public class Messenger {
|
||||||
}
|
}
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MessageConsignor getMessageConsignor(Chat chat) {
|
||||||
|
switch (chat.getChatPreferences().getEncryption()) {
|
||||||
|
case plain:
|
||||||
|
return new PlaintextMessageConsignor(connectionManager, messageRepository, chat);
|
||||||
|
case ox_sign:
|
||||||
|
case ox_crypt:
|
||||||
|
case ox_signcrypt:
|
||||||
|
return new OxMessageConsignor(connectionManager, messageRepository, chat);
|
||||||
|
}
|
||||||
|
throw new AssertionError("Illegal Encryption Type: " + chat.getChatPreferences().getEncryption());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,6 @@ public class MercuryConnectionManager {
|
||||||
MercuryMessageStore mercuryMessageStore = messageStoreFactory.createMessageStore(account);
|
MercuryMessageStore mercuryMessageStore = messageStoreFactory.createMessageStore(account);
|
||||||
ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection());
|
ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection());
|
||||||
chatManager.addIncomingListener(mercuryMessageStore);
|
chatManager.addIncomingListener(mercuryMessageStore);
|
||||||
chatManager.addOutgoingListener(mercuryMessageStore);
|
|
||||||
}));
|
}));
|
||||||
cryptoManager.initialize(connection);
|
cryptoManager.initialize(connection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
package org.mercury_im.messenger.core.connection
|
|
||||||
|
|
||||||
|
|
||||||
import org.mercury_im.messenger.entity.message.Message as MercuryMessage;
|
|
||||||
import org.jivesoftware.smack.packet.Message as SmackMessage;
|
|
||||||
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
import io.reactivex.Completable
|
|
||||||
import io.reactivex.Single
|
|
||||||
import org.mercury_im.messenger.core.util.AppendCompletableToSingle
|
|
||||||
import org.mercury_im.messenger.entity.chat.Chat
|
|
||||||
|
|
||||||
class MessageCenter(private val composer: Composer,
|
|
||||||
private val persister: Persister,
|
|
||||||
private val encryptor: Encryptor,
|
|
||||||
private val sender: Sender) {
|
|
||||||
|
|
||||||
fun sendSingleTextMessage(chat: Chat, body: String): Single<UUID> {
|
|
||||||
val messageEntity = composer.createChatMessage(chat, body)
|
|
||||||
val messageId = persister.persistPendingMessage(messageEntity)
|
|
||||||
val smackMessage = encryptor.encrypt(messageEntity)
|
|
||||||
val sendCompletable = sender.send(smackMessage);
|
|
||||||
return messageId.compose(AppendCompletableToSingle(sendCompletable));
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Composer {
|
|
||||||
fun createChatMessage(chat: Chat, body: String): MercuryMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Persister {
|
|
||||||
fun persistPendingMessage(message: MercuryMessage): Single<UUID>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Encryptor {
|
|
||||||
fun encrypt(message: MercuryMessage): SmackMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Sender {
|
|
||||||
fun send(message: SmackMessage): Completable
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package org.mercury_im.messenger.core.connection;
|
|
||||||
|
|
||||||
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
|
||||||
import org.mercury_im.messenger.entity.message.Message;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import io.reactivex.Single;
|
|
||||||
|
|
||||||
public class MessagePersister implements MessageCenter.Persister {
|
|
||||||
|
|
||||||
private final MessageRepository messageRepository;
|
|
||||||
|
|
||||||
public MessagePersister(MessageRepository messageRepository) {
|
|
||||||
this.messageRepository = messageRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Single<UUID> persistPendingMessage(Message message) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mercury_im.messenger.core.connection;
|
package org.mercury_im.messenger.core.connection;
|
||||||
|
|
||||||
import org.jivesoftware.smack.ReconnectionManager;
|
import org.jivesoftware.smack.ReconnectionManager;
|
||||||
|
import org.jivesoftware.smack.SmackConfiguration;
|
||||||
import org.jivesoftware.smack.roster.Roster;
|
import org.jivesoftware.smack.roster.Roster;
|
||||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
import org.jivesoftware.smackx.iqversion.VersionManager;
|
import org.jivesoftware.smackx.iqversion.VersionManager;
|
||||||
|
@ -10,7 +11,7 @@ import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
||||||
public class SmackConfig {
|
public class SmackConfig {
|
||||||
|
|
||||||
static void staticConfiguration() {
|
static void staticConfiguration() {
|
||||||
//SmackConfiguration.DEBUG = true;
|
SmackConfiguration.DEBUG = true;
|
||||||
ReconnectionManager.setEnabledPerDefault(true);
|
ReconnectionManager.setEnabledPerDefault(true);
|
||||||
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
package org.mercury_im.messenger.core.connection;
|
package org.mercury_im.messenger.core.connection;
|
||||||
|
|
||||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSourceFactory;
|
||||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
import org.mercury_im.messenger.entity.Account;
|
import org.mercury_im.messenger.entity.Account;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class XmppTcpConnectionFactory implements XmppConnectionFactory {
|
public class XmppTcpConnectionFactory implements XmppConnectionFactory {
|
||||||
|
|
||||||
private static final int CONNECTION_TIMEOUT = 30 * 1000;
|
private static final int CONNECTION_TIMEOUT = 30 * 1000;
|
||||||
|
|
||||||
|
private final StanzaIdSourceFactory stanzaIdSourceFactory;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public XmppTcpConnectionFactory(StanzaIdSourceFactory stanzaIdSourceFactory) {
|
||||||
|
this.stanzaIdSourceFactory = stanzaIdSourceFactory;
|
||||||
|
}
|
||||||
|
|
||||||
public AbstractXMPPConnection createConnection(Account account) {
|
public AbstractXMPPConnection createConnection(Account account) {
|
||||||
try {
|
try {
|
||||||
XMPPTCPConnectionConfiguration.Builder configBuilder =
|
XMPPTCPConnectionConfiguration.Builder configBuilder =
|
||||||
XMPPTCPConnectionConfiguration.builder()
|
XMPPTCPConnectionConfiguration.builder()
|
||||||
|
.setStanzaIdSourceFactory(stanzaIdSourceFactory)
|
||||||
.setConnectTimeout(CONNECTION_TIMEOUT)
|
.setConnectTimeout(CONNECTION_TIMEOUT)
|
||||||
.setXmppAddressAndPassword(account.getAddress(), account.getPassword());
|
.setXmppAddressAndPassword(account.getAddress(), account.getPassword());
|
||||||
if (account.getHost() != null) {
|
if (account.getHost() != null) {
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.mercury_im.messenger.core.connection.message;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
|
import org.mercury_im.messenger.entity.chat.Chat;
|
||||||
|
|
||||||
|
public abstract class AbstractMessageConsignor implements MessageConsignor {
|
||||||
|
|
||||||
|
protected final MessageComposer messageComposer;
|
||||||
|
|
||||||
|
protected final MercuryConnectionManager connectionManager;
|
||||||
|
protected final MessageRepository messageRepository;
|
||||||
|
protected final Chat chat;
|
||||||
|
|
||||||
|
public AbstractMessageConsignor(MessageComposer composer,
|
||||||
|
MercuryConnectionManager connectionManager,
|
||||||
|
MessageRepository messageRepository,
|
||||||
|
Chat chat) {
|
||||||
|
this.messageComposer = composer;
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
|
this.messageRepository = messageRepository;
|
||||||
|
this.chat = chat;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,27 +1,33 @@
|
||||||
package org.mercury_im.messenger.core.connection;
|
package org.mercury_im.messenger.core.connection.message;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.id.StandardStanzaIdSource;
|
||||||
import org.mercury_im.messenger.entity.chat.Chat;
|
import org.mercury_im.messenger.entity.chat.Chat;
|
||||||
import org.mercury_im.messenger.entity.message.Message;
|
import org.mercury_im.messenger.entity.message.Message;
|
||||||
import org.mercury_im.messenger.entity.message.MessageDeliveryState;
|
import org.mercury_im.messenger.entity.message.MessageDeliveryState;
|
||||||
import org.mercury_im.messenger.entity.message.MessageDirection;
|
import org.mercury_im.messenger.entity.message.MessageDirection;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class MercuryMessageComposer implements MessageCenter.Composer {
|
public class MessageComposer {
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message createChatMessage(Chat chat, String body) {
|
public Message createChatMessage(Chat chat, String body) {
|
||||||
|
UUID messageId = UUID.randomUUID();
|
||||||
Message message = new Message();
|
Message message = new Message();
|
||||||
|
message.setId(messageId);
|
||||||
|
message.setChatId(chat.getId());
|
||||||
|
|
||||||
|
message.setLegacyStanzaId(new StandardStanzaIdSource().getNewStanzaId());
|
||||||
|
message.setOriginId(messageId.toString());
|
||||||
|
|
||||||
message.setBody(body);
|
message.setBody(body);
|
||||||
message.setSender(chat.getAccount().getJid());
|
message.setSender(chat.getAccount().getJid());
|
||||||
message.setRecipient(chat.getAddress());
|
message.setRecipient(chat.getJid());
|
||||||
message.setDeliveryState(MessageDeliveryState.pending_delivery);
|
message.setDeliveryState(MessageDeliveryState.pending_delivery);
|
||||||
message.setDirection(MessageDirection.outgoing);
|
message.setDirection(MessageDirection.outgoing);
|
||||||
message.setRead(false);
|
message.setRead(false);
|
||||||
|
message.setTimestamp(new Date());
|
||||||
|
|
||||||
UUID messageId = UUID.randomUUID();
|
|
||||||
message.setId(messageId);
|
|
||||||
message.setOriginId(messageId.toString());
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package org.mercury_im.messenger.core.connection.message;
|
||||||
|
|
||||||
|
public interface MessageConsignee {
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.mercury_im.messenger.core.connection.message;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.entity.chat.Chat;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
public interface MessageConsignor {
|
||||||
|
|
||||||
|
Single<UUID> sendTextMessage(Chat chat, String body);
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package org.mercury_im.messenger.core.connection.message;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
|
import org.mercury_im.messenger.entity.chat.Chat;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
public class OxMessageConsignor extends AbstractMessageConsignor {
|
||||||
|
|
||||||
|
public OxMessageConsignor(MercuryConnectionManager connectionManager, MessageRepository messageRepository, Chat chat) {
|
||||||
|
this(new MessageComposer(), connectionManager, messageRepository, chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OxMessageConsignor(MessageComposer composer, MercuryConnectionManager connectionManager, MessageRepository messageRepository, Chat chat) {
|
||||||
|
super(composer, connectionManager, messageRepository, chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<UUID> sendTextMessage(Chat chat, String body) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package org.mercury_im.messenger.core.connection.message;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.chat2.ChatManager;
|
||||||
|
import org.jivesoftware.smack.packet.MessageBuilder;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||||
|
import org.jivesoftware.smackx.muc.MultiUserChatManager;
|
||||||
|
import org.jivesoftware.smackx.sid.element.OriginIdElement;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
|
import org.mercury_im.messenger.core.util.AppendCompletableToSingle;
|
||||||
|
import org.mercury_im.messenger.entity.chat.Chat;
|
||||||
|
import org.mercury_im.messenger.entity.chat.DirectChat;
|
||||||
|
import org.mercury_im.messenger.entity.chat.GroupChat;
|
||||||
|
import org.mercury_im.messenger.entity.message.Message;
|
||||||
|
import org.mercury_im.messenger.entity.message.MessageDeliveryState;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
public class PlaintextMessageConsignor extends AbstractMessageConsignor {
|
||||||
|
|
||||||
|
public PlaintextMessageConsignor(MercuryConnectionManager connectionManager, MessageRepository messageRepository, Chat chat) {
|
||||||
|
this(new MessageComposer(), connectionManager, messageRepository, chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaintextMessageConsignor(MessageComposer composer,
|
||||||
|
MercuryConnectionManager connectionManager,
|
||||||
|
MessageRepository messageRepository,
|
||||||
|
Chat chat) {
|
||||||
|
super(composer, connectionManager, messageRepository, chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<UUID> sendTextMessage(Chat chat, String body) {
|
||||||
|
Message message = messageComposer.createChatMessage(chat, body);
|
||||||
|
MessageBuilder messageBuilder = commonMessageBuilder(message);
|
||||||
|
|
||||||
|
Completable deliverMessage;
|
||||||
|
if (chat instanceof DirectChat) {
|
||||||
|
deliverMessage = sendDirectChatMessage((DirectChat) chat, messageBuilder);
|
||||||
|
} else if (chat instanceof GroupChat) {
|
||||||
|
deliverMessage = sendGroupChatMessage((GroupChat) chat, messageBuilder);
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unknown chat type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Single<UUID> deliverAndStore = messageRepository.insertMessage(message)
|
||||||
|
.map(Message::getId)
|
||||||
|
.compose(new AppendCompletableToSingle<>(deliverMessage))
|
||||||
|
.flatMap(messageId -> messageRepository.updateDeliveryState(messageId, MessageDeliveryState.delivered_to_server)
|
||||||
|
.toSingle(() -> messageId));
|
||||||
|
|
||||||
|
return deliverAndStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageBuilder commonMessageBuilder(Message message) {
|
||||||
|
return MessageBuilder.buildMessage(message.getLegacyStanzaId())
|
||||||
|
.ofType(org.jivesoftware.smack.packet.Message.Type.chat)
|
||||||
|
.addExtension(new OriginIdElement(message.getOriginId()))
|
||||||
|
.to(chat.getJid())
|
||||||
|
.from(chat.getAccount().getJid())
|
||||||
|
.setBody(message.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Completable sendDirectChatMessage(DirectChat chat, MessageBuilder messageBuilder) {
|
||||||
|
return Completable.fromAction(() -> {
|
||||||
|
MercuryConnection connection = connectionManager.getConnection(chat.getAccount());
|
||||||
|
ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection());
|
||||||
|
org.jivesoftware.smack.chat2.Chat smackChat = chatManager.chatWith(chat.getJid().asEntityBareJid());
|
||||||
|
|
||||||
|
smackChat.send(messageBuilder.build());
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Completable sendGroupChatMessage(GroupChat chat, MessageBuilder messageBuilder) {
|
||||||
|
return Completable.fromAction(() -> {
|
||||||
|
MercuryConnection connection = connectionManager.getConnection(chat.getAccount());
|
||||||
|
MultiUserChatManager multiUserChatManager = MultiUserChatManager.getInstanceFor(connection.getConnection());
|
||||||
|
MultiUserChat muc = multiUserChatManager.getMultiUserChat(chat.getJid().asEntityBareJid());
|
||||||
|
if (!muc.isJoined()) {
|
||||||
|
muc.join(Resourcepart.from(chat.getNickname()));
|
||||||
|
}
|
||||||
|
muc.sendMessage(messageBuilder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
package org.mercury_im.messenger.core.data.repository;
|
package org.mercury_im.messenger.core.data.repository;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.entity.chat.DirectChat;
|
import org.mercury_im.messenger.entity.chat.DirectChat;
|
||||||
import org.mercury_im.messenger.entity.chat.GroupChat;
|
import org.mercury_im.messenger.entity.chat.GroupChat;
|
||||||
|
import org.mercury_im.messenger.entity.message.ChatMarkerState;
|
||||||
import org.mercury_im.messenger.entity.message.Message;
|
import org.mercury_im.messenger.entity.message.Message;
|
||||||
|
import org.mercury_im.messenger.entity.message.MessageDeliveryState;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
@ -29,4 +33,8 @@ public interface MessageRepository {
|
||||||
Single<Message> updateMessage(Message message);
|
Single<Message> updateMessage(Message message);
|
||||||
|
|
||||||
Completable deleteMessage(Message message);
|
Completable deleteMessage(Message message);
|
||||||
|
|
||||||
|
Completable markMessage(String stanzaId, EntityBareJid xmppAddressOfChatPartner, ChatMarkerState received);
|
||||||
|
|
||||||
|
Completable updateDeliveryState(UUID messageId, MessageDeliveryState deliveryState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.mercury_im.messenger.core.di.module;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.id.StandardStanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSourceFactory;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class StanzaIdSourceFactoryModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static StanzaIdSourceFactory provideStanzaIdSourceFactory() {
|
||||||
|
return new StandardStanzaIdSource.Factory();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package org.mercury_im.messenger.core.di.module;
|
package org.mercury_im.messenger.core.di.module;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSourceFactory;
|
||||||
import org.mercury_im.messenger.core.connection.XmppConnectionFactory;
|
import org.mercury_im.messenger.core.connection.XmppConnectionFactory;
|
||||||
import org.mercury_im.messenger.core.connection.XmppTcpConnectionFactory;
|
import org.mercury_im.messenger.core.connection.XmppTcpConnectionFactory;
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ public class XmppTcpConnectionFactoryModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static XmppConnectionFactory provideConnectionFactory() {
|
static XmppConnectionFactory provideConnectionFactory(StanzaIdSourceFactory stanzaIdSourceFactory) {
|
||||||
return new XmppTcpConnectionFactory();
|
return new XmppTcpConnectionFactory(stanzaIdSourceFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class MercuryMessageStore implements IncomingChatMessageListener, OutgoingChatMessageListener, OxMessageListener {
|
public class MercuryMessageStore implements IncomingChatMessageListener, OxMessageListener {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(MercuryMessageStore.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(MercuryMessageStore.class.getName());
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
||||||
message.setDirection(MessageDirection.incoming);
|
message.setDirection(MessageDirection.incoming);
|
||||||
DelayInformation delayInformation = DelayInformation.from(smackMessage);
|
DelayInformation delayInformation = DelayInformation.from(smackMessage);
|
||||||
message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date());
|
message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date());
|
||||||
message.setSender(from.asEntityBareJidString());
|
message.setSender(from);
|
||||||
message.setRecipient(smackMessage.getTo().asBareJid().toString());
|
message.setRecipient(smackMessage.getTo().asEntityJidOrThrow());
|
||||||
message.setXml(smackMessage.toXML().toString());
|
message.setXml(smackMessage.toXML().toString());
|
||||||
if (smackMessage.getBody() != null) {
|
if (smackMessage.getBody() != null) {
|
||||||
message.setBody(smackMessage.getBody());
|
message.setBody(smackMessage.getBody());
|
||||||
|
@ -75,25 +75,6 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
||||||
disposable.add(writeMessageToStore(from, message));
|
disposable.add(writeMessageToStore(from, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newOutgoingMessage(EntityBareJid to,
|
|
||||||
MessageBuilder smackMessage,
|
|
||||||
org.jivesoftware.smack.chat2.Chat smackChat) {
|
|
||||||
if (smackMessage.hasExtension(ExplicitMessageEncryptionElement.QNAME)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setDirection(MessageDirection.outgoing);
|
|
||||||
message.setTimestamp(new Date());
|
|
||||||
message.setSender(account.getAddress());
|
|
||||||
message.setRecipient(to.asBareJid().toString());
|
|
||||||
message.setXml(smackMessage.build().toXML().toString());
|
|
||||||
if (smackMessage.getBody() != null) {
|
|
||||||
message.setBody(smackMessage.getBody());
|
|
||||||
}
|
|
||||||
disposable.add(writeMessageToStore(to, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Disposable writeMessageToStore(EntityBareJid peer, Message message) {
|
private Disposable writeMessageToStore(EntityBareJid peer, Message message) {
|
||||||
return peerRepository.getOrCreatePeer(account, peer)
|
return peerRepository.getOrCreatePeer(account, peer)
|
||||||
.flatMap(directChatRepository::getOrCreateChatWithPeer)
|
.flatMap(directChatRepository::getOrCreateChatWithPeer)
|
||||||
|
@ -115,8 +96,8 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
||||||
message.setDirection(MessageDirection.incoming);
|
message.setDirection(MessageDirection.incoming);
|
||||||
DelayInformation delayInformation = DelayInformation.from(smackMessage);
|
DelayInformation delayInformation = DelayInformation.from(smackMessage);
|
||||||
message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date());
|
message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date());
|
||||||
message.setSender(contact.getJid().toString());
|
message.setSender(contact.getJid().asEntityJidOrThrow());
|
||||||
message.setRecipient(smackMessage.getTo().asBareJid().toString());
|
message.setRecipient(smackMessage.getTo().asEntityJidOrThrow());
|
||||||
message.setXml(smackMessage.toXML().toString());
|
message.setXml(smackMessage.toXML().toString());
|
||||||
org.jivesoftware.smack.packet.Message.Body body = decryptedPayload.getExtension(org.jivesoftware.smack.packet.Message.Body.ELEMENT,
|
org.jivesoftware.smack.packet.Message.Body body = decryptedPayload.getExtension(org.jivesoftware.smack.packet.Message.Body.ELEMENT,
|
||||||
org.jivesoftware.smack.packet.Message.Body.NAMESPACE);
|
org.jivesoftware.smack.packet.Message.Body.NAMESPACE);
|
||||||
|
|
|
@ -117,11 +117,11 @@ public class LoginViewModel implements MercuryViewModel {
|
||||||
|
|
||||||
Account account = createAccountEntity();
|
Account account = createAccountEntity();
|
||||||
|
|
||||||
MercuryConnection connection = connectionManager.createConnection(account);
|
//MercuryConnection connection = connectionManager.createConnection(account);
|
||||||
addDisposable(accountRepository.upsertAccount(account).ignoreElement()
|
addDisposable(accountRepository.upsertAccount(account).ignoreElement()
|
||||||
.andThen(connection.connect())
|
//.andThen(connection.connect())
|
||||||
.andThen(connection.login())
|
//.andThen(connection.login())
|
||||||
.andThen(connectionManager.registerConnection(connection))
|
//.andThen(connectionManager.registerConnection(connection))
|
||||||
.subscribeOn(schedulers.getNewThread())
|
.subscribeOn(schedulers.getNewThread())
|
||||||
.observeOn(schedulers.getUiScheduler())
|
.observeOn(schedulers.getUiScheduler())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
import io.reactivex.functions.Function;
|
||||||
import io.reactivex.subjects.BehaviorSubject;
|
import io.reactivex.subjects.BehaviorSubject;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@ -35,8 +36,6 @@ public class ChatViewModel implements MercuryViewModel {
|
||||||
@Getter
|
@Getter
|
||||||
private BehaviorSubject<Optional<Peer>> peer = BehaviorSubject.create();
|
private BehaviorSubject<Optional<Peer>> peer = BehaviorSubject.create();
|
||||||
|
|
||||||
private Single<DirectChat> directChat;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private BehaviorSubject<DirectChat> chat = BehaviorSubject.create();
|
private BehaviorSubject<DirectChat> chat = BehaviorSubject.create();
|
||||||
|
|
||||||
|
@ -62,13 +61,20 @@ public class ChatViewModel implements MercuryViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(UUID accountId, EntityBareJid contactJid) {
|
public void init(UUID accountId, EntityBareJid contactJid) {
|
||||||
Single<Peer> peerSingle = contactRepository.getOrCreatePeer(accountId, contactJid);
|
contactRepository.getOrCreatePeer(accountId, contactJid)
|
||||||
peerSingle.flatMapObservable(contactRepository::observePeer).subscribe(peer);
|
.flatMapObservable(contactRepository::observePeer)
|
||||||
directChat = peerSingle.flatMap(directChatRepository::getOrCreateChatWithPeer);
|
.subscribe(peer);
|
||||||
|
|
||||||
directChat.toObservable().compose(schedulers.executeUiSafeObservable()).subscribe(chat);
|
peer.compose(schedulers.executeUiSafeObservable())
|
||||||
|
.subscribe();
|
||||||
|
|
||||||
Observable<List<Message>> allMessagesObservable = directChat.flatMapObservable(messageRepository::observeMessages);
|
peer.filter(Optional::isPresent).map(Optional::getItem)
|
||||||
|
.flatMap(p -> directChatRepository.getOrCreateChatWithPeer(p).toObservable())
|
||||||
|
.subscribe(chat);
|
||||||
|
|
||||||
|
chat.compose(schedulers.executeUiSafeObservable()).subscribe();
|
||||||
|
|
||||||
|
Observable<List<Message>> allMessagesObservable = chat.flatMap(messageRepository::observeMessages);
|
||||||
messageQueryObservable.onNext(allMessagesObservable);
|
messageQueryObservable.onNext(allMessagesObservable);
|
||||||
messages = Observable.switchOnNext(messageQueryObservable);
|
messages = Observable.switchOnNext(messageQueryObservable);
|
||||||
contactDisplayName = peer.filter(Optional::isPresent).map(Optional::getItem)
|
contactDisplayName = peer.filter(Optional::isPresent).map(Optional::getItem)
|
||||||
|
@ -77,9 +83,9 @@ public class ChatViewModel implements MercuryViewModel {
|
||||||
|
|
||||||
public void onQueryTextChanged(String query) {
|
public void onQueryTextChanged(String query) {
|
||||||
if (query.trim().isEmpty()) {
|
if (query.trim().isEmpty()) {
|
||||||
messageQueryObservable.onNext(directChat.flatMapObservable(messageRepository::observeMessages));
|
messageQueryObservable.onNext(chat.flatMap(messageRepository::observeMessages));
|
||||||
} else {
|
} else {
|
||||||
messageQueryObservable.onNext(directChat.flatMapObservable(c -> messageRepository.findMessagesWithBody(c, query)));
|
messageQueryObservable.onNext(chat.flatMap(c -> messageRepository.findMessagesWithBody(c, query)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +101,10 @@ public class ChatViewModel implements MercuryViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(String body) {
|
public void sendMessage(String body) {
|
||||||
addDisposable(messenger.sendEncryptedMessage(peer.getValue().getItem(), body)
|
addDisposable(messenger.getMessageConsignor(chat.getValue())
|
||||||
.compose(schedulers.executeUiSafeCompletable())
|
.sendTextMessage(chat.getValue(), body)
|
||||||
.subscribe(() -> LOGGER.log(Level.INFO, "Successfully sent encrypted message."),
|
.compose(schedulers.executeUiSafeSingle())
|
||||||
e -> LOGGER.log(Level.SEVERE, "Error sending encrypted message.", e)));
|
.subscribe(messageId -> LOGGER.log(Level.INFO, "Successfully sent message."),
|
||||||
|
e -> LOGGER.log(Level.WARNING, "Error sending message.", e)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package org.mercury_im.messenger.learning_tests.dagger;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
|
||||||
|
public class DaggerTest {
|
||||||
|
|
||||||
|
@dagger.Component(modules = {SingletonModule.class})
|
||||||
|
@Singleton
|
||||||
|
public interface Component {
|
||||||
|
|
||||||
|
void inject(Consumer consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class NewInstanceModule {
|
||||||
|
|
||||||
|
private int DEPENDENCY_INDEX = 0;
|
||||||
|
private final String MODULE_NAME;
|
||||||
|
|
||||||
|
public NewInstanceModule(String moduleName) {
|
||||||
|
this.MODULE_NAME = moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
Dependency provideDependency() {
|
||||||
|
return new Dependency(DEPENDENCY_INDEX++, MODULE_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class SingletonModule {
|
||||||
|
private int DEPENDENCY_INDEX = 0;
|
||||||
|
private final String MODULE_NAME;
|
||||||
|
|
||||||
|
public SingletonModule(String moduleName) {
|
||||||
|
this.MODULE_NAME = moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Dependency provideDependency() {
|
||||||
|
return new Dependency(DEPENDENCY_INDEX++, MODULE_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Dependency {
|
||||||
|
|
||||||
|
final int index;
|
||||||
|
final String moduleName;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Dependency(int index, String moduleName) {
|
||||||
|
this.index = index;
|
||||||
|
this.moduleName = moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModuleName() {
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Consumer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Dependency dependency;
|
||||||
|
|
||||||
|
public Consumer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dependency getDependency() {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
Component component0 = DaggerDaggerTest_Component.builder().singletonModule(new SingletonModule("First")).build();
|
||||||
|
|
||||||
|
Consumer consumer0 = new Consumer();
|
||||||
|
Consumer consumer1 = new Consumer();
|
||||||
|
|
||||||
|
component0.inject(consumer0);
|
||||||
|
component0.inject(consumer1);
|
||||||
|
|
||||||
|
Component component1 = DaggerDaggerTest_Component.builder().singletonModule(new SingletonModule("Second")).build();
|
||||||
|
|
||||||
|
Consumer consumer2 = new Consumer();
|
||||||
|
Consumer consumer3 = new Consumer();
|
||||||
|
component1.inject(consumer2);
|
||||||
|
component1.inject(consumer3);
|
||||||
|
|
||||||
|
assertEquals(0, consumer0.getDependency().getIndex());
|
||||||
|
assertEquals(1, consumer1.getDependency().getIndex());
|
||||||
|
assertEquals(0, consumer2.getDependency().getIndex());
|
||||||
|
assertEquals(1, consumer3.getDependency().getIndex());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.mercury_im.messenger.learning_tests.rx;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.subjects.BehaviorSubject;
|
||||||
|
import io.reactivex.subjects.Subject;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertNotNull;
|
||||||
|
|
||||||
|
public class BehaviourSubjectSubscriptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() throws InterruptedException {
|
||||||
|
Observable<String> observable = Observable.just("One", "Two", "Three");
|
||||||
|
BehaviorSubject<String> behaviorSubject = BehaviorSubject.create();
|
||||||
|
|
||||||
|
observable.subscribe(behaviorSubject);
|
||||||
|
behaviorSubject.subscribe(System.out::println);
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
String s = behaviorSubject.getValue();
|
||||||
|
assertNotNull(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package org.mercury_im.messenger.entity.chat;
|
package org.mercury_im.messenger.entity.chat;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.mercury_im.messenger.entity.Account;
|
import org.mercury_im.messenger.entity.Account;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -15,11 +17,15 @@ import lombok.Data;
|
||||||
public abstract class Chat {
|
public abstract class Chat {
|
||||||
UUID id;
|
UUID id;
|
||||||
Account account;
|
Account account;
|
||||||
ChatPreferences chatPreferences;
|
ChatPreferences chatPreferences = new ChatPreferences();
|
||||||
|
|
||||||
public Chat() {
|
public Chat() {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String getAddress();
|
public abstract String getAddress();
|
||||||
|
|
||||||
|
public EntityJid getJid() {
|
||||||
|
return JidCreate.entityFromOrThrowUnchecked(getAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.mercury_im.messenger.entity.chat;
|
package org.mercury_im.messenger.entity.chat;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.entity.Encryption;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +14,7 @@ public class ChatPreferences {
|
||||||
boolean sendTypingNotificationsEnabled;
|
boolean sendTypingNotificationsEnabled;
|
||||||
boolean readNotificationsSupported;
|
boolean readNotificationsSupported;
|
||||||
boolean sendReadNotificationsEnabled;
|
boolean sendReadNotificationsEnabled;
|
||||||
|
Encryption encryption = Encryption.plain; // TODO: Fix
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class NotificationPreferences {
|
public static class NotificationPreferences {
|
||||||
|
|
|
@ -16,6 +16,7 @@ public class GroupChat extends Chat {
|
||||||
Set<Peer> participants;
|
Set<Peer> participants;
|
||||||
String roomAddress;
|
String roomAddress;
|
||||||
String roomName;
|
String roomName;
|
||||||
|
String nickname = "NICK"; // TODO: Fix
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.mercury_im.messenger.entity.message;
|
||||||
|
|
||||||
|
public enum ChatMarkerState {
|
||||||
|
markable,
|
||||||
|
received,
|
||||||
|
displayed,
|
||||||
|
acknowledged
|
||||||
|
}
|
|
@ -1,10 +1,9 @@
|
||||||
package org.mercury_im.messenger.entity.message;
|
package org.mercury_im.messenger.entity.message;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityJid;
|
||||||
import org.mercury_im.messenger.entity.Encryption;
|
import org.mercury_im.messenger.entity.Encryption;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -13,8 +12,8 @@ import lombok.Data;
|
||||||
public class Message {
|
public class Message {
|
||||||
UUID id;
|
UUID id;
|
||||||
UUID chatId;
|
UUID chatId;
|
||||||
EntityFullJid sender;
|
EntityJid sender;
|
||||||
EntityFullJid recipient;
|
EntityJid recipient;
|
||||||
|
|
||||||
String body;
|
String body;
|
||||||
|
|
||||||
|
@ -34,6 +33,7 @@ public class Message {
|
||||||
Encryption encryption;
|
Encryption encryption;
|
||||||
boolean received;
|
boolean received;
|
||||||
boolean read;
|
boolean read;
|
||||||
|
boolean pending;
|
||||||
|
|
||||||
public boolean isIncoming() {
|
public boolean isIncoming() {
|
||||||
return getDirection() == MessageDirection.incoming;
|
return getDirection() == MessageDirection.incoming;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#Sun Sep 01 01:05:38 CEST 2019
|
#Mon Jul 27 15:17:47 CEST 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1267729430f2c53f966b98febf16ef7f262b94d7
|
Subproject commit 30030941307262173ac7347e11235a8cadf68787
|
|
@ -86,7 +86,7 @@ ext {
|
||||||
rxAndroidVersion = "2.1.1"
|
rxAndroidVersion = "2.1.1"
|
||||||
|
|
||||||
// Dagger 2
|
// Dagger 2
|
||||||
daggerVersion = '2.25.4'
|
daggerVersion = '2.28.3'
|
||||||
|
|
||||||
// Lombok
|
// Lombok
|
||||||
lombokVersion = '1.18.12'
|
lombokVersion = '1.18.12'
|
||||||
|
|
Loading…
Reference in New Issue