insert message states (displayed, received, error) into DB
This commit is contained in:
parent
9b62861a64
commit
be3a8dc5e1
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "03075d3509cc0d79cf5e733cff6b71fd",
|
"identityHash": "b6a7be8218829fd38f51dcd76cb9cccd",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "account",
|
"tableName": "account",
|
||||||
|
@ -1564,6 +1564,84 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"tableName": "message_state",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `messageVersionId` INTEGER NOT NULL, `fromBare` TEXT NOT NULL, `fromResource` TEXT, `type` TEXT NOT NULL, `errorCondition` TEXT, `errorText` TEXT, FOREIGN KEY(`messageVersionId`) REFERENCES `message_version`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "messageVersionId",
|
||||||
|
"columnName": "messageVersionId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "fromBare",
|
||||||
|
"columnName": "fromBare",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "fromResource",
|
||||||
|
"columnName": "fromResource",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "errorCondition",
|
||||||
|
"columnName": "errorCondition",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "errorText",
|
||||||
|
"columnName": "errorText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_message_state_messageVersionId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"messageVersionId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_message_state_messageVersionId` ON `${TABLE_NAME}` (`messageVersionId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "message_version",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"messageVersionId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"tableName": "message_content",
|
"tableName": "message_content",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `messageVersionId` INTEGER NOT NULL, `language` TEXT, `type` TEXT, `body` TEXT, `url` TEXT, FOREIGN KEY(`messageVersionId`) REFERENCES `message_version`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `messageVersionId` INTEGER NOT NULL, `language` TEXT, `type` TEXT, `body` TEXT, `url` TEXT, FOREIGN KEY(`messageVersionId`) REFERENCES `message_version`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
@ -2150,7 +2228,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '03075d3509cc0d79cf5e733cff6b71fd')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'b6a7be8218829fd38f51dcd76cb9cccd')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -38,6 +38,7 @@ import im.conversations.android.database.entity.DiscoIdentityEntity;
|
||||||
import im.conversations.android.database.entity.DiscoItemEntity;
|
import im.conversations.android.database.entity.DiscoItemEntity;
|
||||||
import im.conversations.android.database.entity.MessageContentEntity;
|
import im.conversations.android.database.entity.MessageContentEntity;
|
||||||
import im.conversations.android.database.entity.MessageEntity;
|
import im.conversations.android.database.entity.MessageEntity;
|
||||||
|
import im.conversations.android.database.entity.MessageStateEntity;
|
||||||
import im.conversations.android.database.entity.MessageVersionEntity;
|
import im.conversations.android.database.entity.MessageVersionEntity;
|
||||||
import im.conversations.android.database.entity.NickEntity;
|
import im.conversations.android.database.entity.NickEntity;
|
||||||
import im.conversations.android.database.entity.PresenceEntity;
|
import im.conversations.android.database.entity.PresenceEntity;
|
||||||
|
@ -68,6 +69,7 @@ import im.conversations.android.database.entity.RosterItemGroupEntity;
|
||||||
DiscoIdentityEntity.class,
|
DiscoIdentityEntity.class,
|
||||||
DiscoItemEntity.class,
|
DiscoItemEntity.class,
|
||||||
MessageEntity.class,
|
MessageEntity.class,
|
||||||
|
MessageStateEntity.class,
|
||||||
MessageContentEntity.class,
|
MessageContentEntity.class,
|
||||||
MessageVersionEntity.class,
|
MessageVersionEntity.class,
|
||||||
NickEntity.class,
|
NickEntity.class,
|
||||||
|
|
|
@ -35,6 +35,7 @@ public abstract class ChatDao {
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
// TODO do not create entity for 'error'
|
||||||
final var entity = new ChatEntity();
|
final var entity = new ChatEntity();
|
||||||
entity.accountId = account.id;
|
entity.accountId = account.id;
|
||||||
entity.address = address.toEscapedString();
|
entity.address = address.toEscapedString();
|
||||||
|
|
|
@ -10,19 +10,25 @@ import com.google.common.collect.Lists;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import im.conversations.android.database.entity.MessageContentEntity;
|
import im.conversations.android.database.entity.MessageContentEntity;
|
||||||
import im.conversations.android.database.entity.MessageEntity;
|
import im.conversations.android.database.entity.MessageEntity;
|
||||||
|
import im.conversations.android.database.entity.MessageStateEntity;
|
||||||
import im.conversations.android.database.entity.MessageVersionEntity;
|
import im.conversations.android.database.entity.MessageVersionEntity;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
import im.conversations.android.database.model.ChatIdentifier;
|
import im.conversations.android.database.model.ChatIdentifier;
|
||||||
import im.conversations.android.database.model.MessageContent;
|
import im.conversations.android.database.model.MessageContent;
|
||||||
import im.conversations.android.database.model.MessageIdentifier;
|
import im.conversations.android.database.model.MessageIdentifier;
|
||||||
|
import im.conversations.android.database.model.MessageState;
|
||||||
import im.conversations.android.database.model.Modification;
|
import im.conversations.android.database.model.Modification;
|
||||||
import im.conversations.android.transformer.Transformation;
|
import im.conversations.android.transformer.Transformation;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public abstract class MessageDao {
|
public abstract class MessageDao {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MessageDao.class);
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"UPDATE message SET acknowledged=1 WHERE messageId=:messageId AND toBare=:toBare AND"
|
"UPDATE message SET acknowledged=1 WHERE messageId=:messageId AND toBare=:toBare AND"
|
||||||
+ " toResource=NULL AND chatId IN (SELECT id FROM chat WHERE accountId=:account)")
|
+ " toResource=NULL AND chatId IN (SELECT id FROM chat WHERE accountId=:account)")
|
||||||
|
@ -115,10 +121,10 @@ public abstract class MessageDao {
|
||||||
// we only look up stubs
|
// we only look up stubs
|
||||||
// TODO the from matcher should be in the outer condition
|
// TODO the from matcher should be in the outer condition
|
||||||
@Query(
|
@Query(
|
||||||
"SELECT id,stanzaId,messageId,fromBare,latestVersion FROM message WHERE chatId=:chatId"
|
"SELECT id,stanzaId,messageId,fromBare,latestVersion as version FROM message WHERE"
|
||||||
+ " AND (fromBare=:fromBare OR fromBare=NULL) AND ((stanzaId != NULL AND"
|
+ " chatId=:chatId AND (fromBare=:fromBare OR fromBare=NULL) AND ((stanzaId !="
|
||||||
+ " stanzaId=:stanzaId AND (stanzaIdVerified=1 OR latestVersion=NULL)) OR"
|
+ " NULL AND stanzaId=:stanzaId AND (stanzaIdVerified=1 OR latestVersion=NULL)) OR"
|
||||||
+ " (stanzaId = NULL AND messageId=:messageId AND latestVersion = NULL))")
|
+ " (stanzaId = NULL AND messageId=:messageId AND latestVersion = NULL))")
|
||||||
abstract MessageIdentifier get(long chatId, Jid fromBare, String stanzaId, String messageId);
|
abstract MessageIdentifier get(long chatId, Jid fromBare, String stanzaId, String messageId);
|
||||||
|
|
||||||
public void insertMessageContent(Long latestVersion, List<MessageContent> contents) {
|
public void insertMessageContent(Long latestVersion, List<MessageContent> contents) {
|
||||||
|
@ -133,4 +139,29 @@ public abstract class MessageDao {
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
protected abstract void insertMessageContent(Collection<MessageContentEntity> contentEntities);
|
protected abstract void insertMessageContent(Collection<MessageContentEntity> contentEntities);
|
||||||
|
|
||||||
|
public void insertMessageState(
|
||||||
|
ChatIdentifier chatIdentifier,
|
||||||
|
final String messageId,
|
||||||
|
final MessageState messageState) {
|
||||||
|
final Long versionId = getVersionIdForOutgoingMessage(chatIdentifier.id, messageId);
|
||||||
|
if (versionId == null) {
|
||||||
|
LOGGER.warn(
|
||||||
|
"Can not find message {} in chat {} ({})",
|
||||||
|
messageId,
|
||||||
|
chatIdentifier.id,
|
||||||
|
chatIdentifier.address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insert(MessageStateEntity.of(versionId, messageState));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"SELECT message_version.id FROM message_version JOIN message ON"
|
||||||
|
+ " message.id=message_version.messageEntityId WHERE message.chatId=:chatId AND"
|
||||||
|
+ " message_version.messageId=:messageId AND message.outgoing=1")
|
||||||
|
protected abstract Long getVersionIdForOutgoingMessage(long chatId, final String messageId);
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
protected abstract void insert(MessageStateEntity messageStateEntity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package im.conversations.android.database.entity;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.room.Entity;
|
||||||
|
import androidx.room.ForeignKey;
|
||||||
|
import androidx.room.Index;
|
||||||
|
import androidx.room.PrimaryKey;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
import im.conversations.android.database.model.MessageState;
|
||||||
|
import im.conversations.android.database.model.StateType;
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "message_state",
|
||||||
|
foreignKeys =
|
||||||
|
@ForeignKey(
|
||||||
|
entity = MessageVersionEntity.class,
|
||||||
|
parentColumns = {"id"},
|
||||||
|
childColumns = {"messageVersionId"},
|
||||||
|
onDelete = ForeignKey.CASCADE),
|
||||||
|
indices = {@Index(value = "messageVersionId")})
|
||||||
|
public class MessageStateEntity {
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
public Long id;
|
||||||
|
|
||||||
|
@NonNull public Long messageVersionId;
|
||||||
|
|
||||||
|
@NonNull public Jid fromBare;
|
||||||
|
|
||||||
|
@Nullable public String fromResource;
|
||||||
|
|
||||||
|
@NonNull public StateType type;
|
||||||
|
|
||||||
|
public String errorCondition;
|
||||||
|
|
||||||
|
public String errorText;
|
||||||
|
|
||||||
|
public static MessageStateEntity of(
|
||||||
|
final long messageVersionId, final MessageState messageState) {
|
||||||
|
final var entity = new MessageStateEntity();
|
||||||
|
entity.messageVersionId = messageVersionId;
|
||||||
|
entity.fromBare = messageState.fromBare;
|
||||||
|
entity.fromResource = messageState.fromResource;
|
||||||
|
;
|
||||||
|
entity.type = messageState.type;
|
||||||
|
entity.errorCondition = messageState.errorCondition;
|
||||||
|
entity.errorText = messageState.errorText;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package im.conversations.android.database.model;
|
package im.conversations.android.database.model;
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
|
||||||
public class MessageIdentifier {
|
public class MessageIdentifier {
|
||||||
|
@ -9,29 +8,18 @@ public class MessageIdentifier {
|
||||||
public final String stanzaId;
|
public final String stanzaId;
|
||||||
public final String messageId;
|
public final String messageId;
|
||||||
public final Jid fromBare;
|
public final Jid fromBare;
|
||||||
public final Long latestVersion;
|
public final Long version;
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return MoreObjects.toStringHelper(this)
|
|
||||||
.add("id", id)
|
|
||||||
.add("stanzaId", stanzaId)
|
|
||||||
.add("messageId", messageId)
|
|
||||||
.add("fromBare", fromBare)
|
|
||||||
.add("latestVersion", latestVersion)
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageIdentifier(
|
public MessageIdentifier(
|
||||||
long id, String stanzaId, String messageId, Jid fromBare, Long latestVersion) {
|
long id, String stanzaId, String messageId, Jid fromBare, Long version) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.stanzaId = stanzaId;
|
this.stanzaId = stanzaId;
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.fromBare = fromBare;
|
this.fromBare = fromBare;
|
||||||
this.latestVersion = latestVersion;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isStub() {
|
public boolean isStub() {
|
||||||
return this.latestVersion == null;
|
return this.version == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package im.conversations.android.database.model;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
import im.conversations.android.transformer.Transformation;
|
||||||
|
import im.conversations.android.xmpp.model.error.Condition;
|
||||||
|
import im.conversations.android.xmpp.model.error.Error;
|
||||||
|
import im.conversations.android.xmpp.model.error.Text;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Message;
|
||||||
|
|
||||||
|
public class MessageState {
|
||||||
|
|
||||||
|
public final Jid fromBare;
|
||||||
|
|
||||||
|
public final String fromResource;
|
||||||
|
|
||||||
|
public final StateType type;
|
||||||
|
|
||||||
|
public final String errorCondition;
|
||||||
|
|
||||||
|
public final String errorText;
|
||||||
|
|
||||||
|
public MessageState(
|
||||||
|
Jid fromBare,
|
||||||
|
String fromResource,
|
||||||
|
StateType type,
|
||||||
|
String errorCondition,
|
||||||
|
String errorText) {
|
||||||
|
this.fromBare = fromBare;
|
||||||
|
this.fromResource = fromResource;
|
||||||
|
this.type = type;
|
||||||
|
this.errorCondition = errorCondition;
|
||||||
|
this.errorText = errorText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageState error(final Transformation transformation) {
|
||||||
|
Preconditions.checkArgument(transformation.type == Message.Type.ERROR);
|
||||||
|
final Error error = transformation.getExtension(Error.class);
|
||||||
|
final Condition condition = error == null ? null : error.getCondition();
|
||||||
|
final Text text = error == null ? null : error.getText();
|
||||||
|
return new MessageState(
|
||||||
|
transformation.fromBare(),
|
||||||
|
transformation.fromResource(),
|
||||||
|
StateType.ERROR,
|
||||||
|
condition == null ? null : condition.getName(),
|
||||||
|
text == null ? null : text.getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageState delivered(final Transformation transformation) {
|
||||||
|
return new MessageState(
|
||||||
|
transformation.fromBare(),
|
||||||
|
transformation.fromResource(),
|
||||||
|
StateType.DELIVERED,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageState displayed(final Transformation transformation) {
|
||||||
|
return new MessageState(
|
||||||
|
transformation.fromBare(),
|
||||||
|
transformation.fromResource(),
|
||||||
|
StateType.DISPLAYED,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package im.conversations.android.database.model;
|
||||||
|
|
||||||
|
public enum StateType {
|
||||||
|
DELIVERED,
|
||||||
|
ERROR,
|
||||||
|
DISPLAYED
|
||||||
|
}
|
|
@ -11,12 +11,14 @@ import im.conversations.android.xmpp.model.Extension;
|
||||||
import im.conversations.android.xmpp.model.axolotl.Encrypted;
|
import im.conversations.android.xmpp.model.axolotl.Encrypted;
|
||||||
import im.conversations.android.xmpp.model.jabber.Body;
|
import im.conversations.android.xmpp.model.jabber.Body;
|
||||||
import im.conversations.android.xmpp.model.jabber.Thread;
|
import im.conversations.android.xmpp.model.jabber.Thread;
|
||||||
|
import im.conversations.android.xmpp.model.markers.Displayed;
|
||||||
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
||||||
import im.conversations.android.xmpp.model.oob.OutOfBandData;
|
import im.conversations.android.xmpp.model.oob.OutOfBandData;
|
||||||
import im.conversations.android.xmpp.model.stanza.Message;
|
import im.conversations.android.xmpp.model.stanza.Message;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Transformation {
|
public class Transformation {
|
||||||
|
@ -28,7 +30,8 @@ public class Transformation {
|
||||||
Encrypted.class,
|
Encrypted.class,
|
||||||
OutOfBandData.class,
|
OutOfBandData.class,
|
||||||
DeliveryReceipt.class,
|
DeliveryReceipt.class,
|
||||||
MultiUserChat.class);
|
MultiUserChat.class,
|
||||||
|
Displayed.class);
|
||||||
|
|
||||||
public final Instant receivedAt;
|
public final Instant receivedAt;
|
||||||
public final Jid to;
|
public final Jid to;
|
||||||
|
@ -113,10 +116,16 @@ public class Transformation {
|
||||||
final var type = message.getType();
|
final var type = message.getType();
|
||||||
final var messageId = message.getId();
|
final var messageId = message.getId();
|
||||||
final ImmutableList.Builder<Extension> extensionListBuilder = new ImmutableList.Builder<>();
|
final ImmutableList.Builder<Extension> extensionListBuilder = new ImmutableList.Builder<>();
|
||||||
for (final Class<? extends Extension> clazz : EXTENSION_FOR_TRANSFORMATION) {
|
final Collection<DeliveryReceiptRequest> requests;
|
||||||
extensionListBuilder.addAll(message.getExtensions(clazz));
|
if (type == Message.Type.ERROR) {
|
||||||
|
extensionListBuilder.add(message.getError());
|
||||||
|
requests = Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
for (final Class<? extends Extension> clazz : EXTENSION_FOR_TRANSFORMATION) {
|
||||||
|
extensionListBuilder.addAll(message.getExtensions(clazz));
|
||||||
|
}
|
||||||
|
requests = message.getExtensions(DeliveryReceiptRequest.class);
|
||||||
}
|
}
|
||||||
final var requests = message.getExtensions(DeliveryReceiptRequest.class);
|
|
||||||
return new Transformation(
|
return new Transformation(
|
||||||
receivedAt,
|
receivedAt,
|
||||||
to,
|
to,
|
||||||
|
|
|
@ -8,12 +8,15 @@ import im.conversations.android.database.ConversationsDatabase;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
import im.conversations.android.database.model.ChatIdentifier;
|
import im.conversations.android.database.model.ChatIdentifier;
|
||||||
import im.conversations.android.database.model.MessageContent;
|
import im.conversations.android.database.model.MessageContent;
|
||||||
|
import im.conversations.android.database.model.MessageState;
|
||||||
import im.conversations.android.xmpp.model.DeliveryReceipt;
|
import im.conversations.android.xmpp.model.DeliveryReceipt;
|
||||||
import im.conversations.android.xmpp.model.axolotl.Encrypted;
|
import im.conversations.android.xmpp.model.axolotl.Encrypted;
|
||||||
import im.conversations.android.xmpp.model.correction.Replace;
|
import im.conversations.android.xmpp.model.correction.Replace;
|
||||||
import im.conversations.android.xmpp.model.jabber.Body;
|
import im.conversations.android.xmpp.model.jabber.Body;
|
||||||
|
import im.conversations.android.xmpp.model.markers.Displayed;
|
||||||
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
import im.conversations.android.xmpp.model.muc.user.MultiUserChat;
|
||||||
import im.conversations.android.xmpp.model.oob.OutOfBandData;
|
import im.conversations.android.xmpp.model.oob.OutOfBandData;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Message;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -47,26 +50,33 @@ public class Transformer {
|
||||||
final ConversationsDatabase database, final Transformation transformation) {
|
final ConversationsDatabase database, final Transformation transformation) {
|
||||||
final var remote = transformation.remote;
|
final var remote = transformation.remote;
|
||||||
final var messageType = transformation.type;
|
final var messageType = transformation.type;
|
||||||
final var deliveryReceipt = transformation.getExtension(DeliveryReceipt.class);
|
|
||||||
final Replace lastMessageCorrection = transformation.getExtension(Replace.class);
|
|
||||||
final var muc = transformation.getExtension(MultiUserChat.class);
|
final var muc = transformation.getExtension(MultiUserChat.class);
|
||||||
|
|
||||||
|
|
||||||
final List<MessageContent> contents = parseContent(transformation);
|
|
||||||
|
|
||||||
// TODO this also needs to be true for retractions once we support those (anything that
|
|
||||||
// creates a new message version
|
|
||||||
final boolean versionModification = Objects.nonNull(lastMessageCorrection);
|
|
||||||
|
|
||||||
// TODO get or create Cha
|
|
||||||
|
|
||||||
final ChatIdentifier chat =
|
final ChatIdentifier chat =
|
||||||
database.chatDao()
|
database.chatDao()
|
||||||
.getOrCreateChat(account, remote, messageType, Objects.nonNull(muc));
|
.getOrCreateChat(account, remote, messageType, Objects.nonNull(muc));
|
||||||
|
|
||||||
|
if (messageType == Message.Type.ERROR) {
|
||||||
|
if (transformation.outgoing()) {
|
||||||
|
LOGGER.info("Ignoring outgoing error to {}", transformation.to);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
database.messageDao()
|
||||||
|
.insertMessageState(
|
||||||
|
chat, transformation.messageId, MessageState.error(transformation));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Replace lastMessageCorrection = transformation.getExtension(Replace.class);
|
||||||
|
final List<MessageContent> contents = parseContent(transformation);
|
||||||
|
|
||||||
|
// TODO this also needs to be true for retractions once we support those (anything that
|
||||||
|
// creates a new message version
|
||||||
|
// TODO a type=groupchat message correction is only valid with an occupant id
|
||||||
|
final boolean versionModification = Objects.nonNull(lastMessageCorrection);
|
||||||
|
|
||||||
if (contents.isEmpty()) {
|
if (contents.isEmpty()) {
|
||||||
LOGGER.info("Received message from {} w/o contents", transformation.from);
|
LOGGER.info("Received message from {} w/o contents", transformation.from);
|
||||||
// TODO apply errors, displayed, received etc
|
transformMessageState(chat, transformation);
|
||||||
// TODO apply reactions
|
// TODO apply reactions
|
||||||
} else {
|
} else {
|
||||||
if (versionModification) {
|
if (versionModification) {
|
||||||
|
@ -78,8 +88,7 @@ public class Transformer {
|
||||||
} else {
|
} else {
|
||||||
final var messageIdentifier =
|
final var messageIdentifier =
|
||||||
database.messageDao().getOrCreateMessage(chat, transformation);
|
database.messageDao().getOrCreateMessage(chat, transformation);
|
||||||
database.messageDao()
|
database.messageDao().insertMessageContent(messageIdentifier.version, contents);
|
||||||
.insertMessageContent(messageIdentifier.latestVersion, contents);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,4 +130,31 @@ public class Transformer {
|
||||||
}
|
}
|
||||||
return messageContentBuilder.build();
|
return messageContentBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void transformMessageState(
|
||||||
|
final ChatIdentifier chat, final Transformation transformation) {
|
||||||
|
final var database = ConversationsDatabase.getInstance(context);
|
||||||
|
final var displayed = transformation.getExtension(Displayed.class);
|
||||||
|
if (displayed != null) {
|
||||||
|
if (transformation.outgoing()) {
|
||||||
|
LOGGER.info(
|
||||||
|
"Received outgoing displayed marker for chat with {}",
|
||||||
|
transformation.remote);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
database.messageDao()
|
||||||
|
.insertMessageState(
|
||||||
|
chat, displayed.getId(), MessageState.displayed(transformation));
|
||||||
|
}
|
||||||
|
final var deliveryReceipt = transformation.getExtension(DeliveryReceipt.class);
|
||||||
|
if (deliveryReceipt != null) {
|
||||||
|
if (transformation.outgoing()) {
|
||||||
|
LOGGER.info("Ignoring outgoing delivery receipt to {}", transformation.to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
database.messageDao()
|
||||||
|
.insertMessageState(
|
||||||
|
chat, deliveryReceipt.getId(), MessageState.delivered(transformation));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,6 @@ public class ChatStateManager extends AbstractManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(final Jid from, final ChatStateNotification chatState) {
|
public void handle(final Jid from, final ChatStateNotification chatState) {
|
||||||
LOGGER.info("Received {} from {}", chatState, from);
|
// LOGGER.info("Received {} from {}", chatState, from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,8 @@ public class Displayed extends Extension {
|
||||||
public Displayed() {
|
public Displayed() {
|
||||||
super(Displayed.class);
|
super(Displayed.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return this.getAttribute("id");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue