mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 02:25:19 +00:00
fix: fixing up LokiMessageDatabase.kt table structure, deletion closer to finished
This commit is contained in:
parent
51554f1cdf
commit
ef19c0d10e
@ -137,9 +137,19 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
|
|||||||
return openGroupMessagingDatabase.getMessageID(serverID)
|
return openGroupMessagingDatabase.getMessageID(serverID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteMessage(messageID: Long) {
|
override fun getMessageID(serverId: Long, threadId: Long): Pair<Long, Boolean>? {
|
||||||
val messagingDatabase = DatabaseFactory.getSmsDatabase(context)
|
val messageDB = DatabaseFactory.getLokiMessageDatabase(context)
|
||||||
messagingDatabase.deleteMessage(messageID)
|
return messageDB.getMessageID(serverId, threadId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteMessage(messageID: Long, isSms: Boolean) {
|
||||||
|
if (isSms) {
|
||||||
|
val db = DatabaseFactory.getSmsDatabase(context)
|
||||||
|
db.deleteMessage(messageID)
|
||||||
|
} else {
|
||||||
|
val db = DatabaseFactory.getMmsDatabase(context)
|
||||||
|
db.delete(messageID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment? {
|
override fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment? {
|
||||||
|
@ -1718,7 +1718,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
boolean initiating = threadId == -1;
|
boolean initiating = threadId == -1;
|
||||||
boolean needsSplit = message.length() > characterCalculator.calculateCharacters(message).maxPrimaryMessageSize;
|
boolean needsSplit = message.length() > characterCalculator.calculateCharacters(message).maxPrimaryMessageSize;
|
||||||
boolean isMediaMessage = attachmentManager.isAttachmentPresent() ||
|
boolean isMediaMessage = attachmentManager.isAttachmentPresent() ||
|
||||||
recipient.isGroupRecipient() ||
|
// recipient.isGroupRecipient() ||
|
||||||
inputPanel.getQuote().isPresent() ||
|
inputPanel.getQuote().isPresent() ||
|
||||||
linkPreviewViewModel.hasLinkPreview() ||
|
linkPreviewViewModel.hasLinkPreview() ||
|
||||||
LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages
|
LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages
|
||||||
|
@ -533,7 +533,7 @@ public class ConversationFragment extends Fragment
|
|||||||
boolean isSentByUser = true;
|
boolean isSentByUser = true;
|
||||||
for (MessageRecord messageRecord : messageRecords) {
|
for (MessageRecord messageRecord : messageRecords) {
|
||||||
isSentByUser = isSentByUser && messageRecord.isOutgoing();
|
isSentByUser = isSentByUser && messageRecord.isOutgoing();
|
||||||
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id);
|
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id, !messageRecord.isMms());
|
||||||
if (serverID != null) {
|
if (serverID != null) {
|
||||||
serverIDs.add(serverID);
|
serverIDs.add(serverID);
|
||||||
} else {
|
} else {
|
||||||
@ -545,7 +545,7 @@ public class ConversationFragment extends Fragment
|
|||||||
.deleteMessages(serverIDs, publicChat.getChannel(), publicChat.getServer(), isSentByUser)
|
.deleteMessages(serverIDs, publicChat.getChannel(), publicChat.getServer(), isSentByUser)
|
||||||
.success(l -> {
|
.success(l -> {
|
||||||
for (MessageRecord messageRecord : messageRecords) {
|
for (MessageRecord messageRecord : messageRecords) {
|
||||||
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id);
|
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id, !messageRecord.isMms());
|
||||||
if (l.contains(serverID)) {
|
if (l.contains(serverID)) {
|
||||||
if (messageRecord.isMms()) {
|
if (messageRecord.isMms()) {
|
||||||
DatabaseFactory.getMmsDatabase(getActivity()).delete(messageRecord.getId());
|
DatabaseFactory.getMmsDatabase(getActivity()).delete(messageRecord.getId());
|
||||||
@ -568,7 +568,7 @@ public class ConversationFragment extends Fragment
|
|||||||
.deleteMessage(serverId, openGroupChat.getRoom(), openGroupChat.getServer())
|
.deleteMessage(serverId, openGroupChat.getRoom(), openGroupChat.getServer())
|
||||||
.success(l -> {
|
.success(l -> {
|
||||||
for (MessageRecord messageRecord : messageRecords) {
|
for (MessageRecord messageRecord : messageRecords) {
|
||||||
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id);
|
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id, !messageRecord.isMms());
|
||||||
if (serverID != null && serverID.equals(serverId)) {
|
if (serverID != null && serverID.equals(serverId)) {
|
||||||
if (messageRecord.isMms()) {
|
if (messageRecord.isMms()) {
|
||||||
DatabaseFactory.getMmsDatabase(getContext()).delete(messageRecord.getId());
|
DatabaseFactory.getMmsDatabase(getContext()).delete(messageRecord.getId());
|
||||||
|
@ -388,8 +388,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
return database.getMessageFor(timestamp, address)?.getId()
|
return database.getMessageFor(timestamp, address)?.getId()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setOpenGroupServerMessageID(messageID: Long, serverID: Long) {
|
override fun setOpenGroupServerMessageID(messageID: Long, serverID: Long, threadID: Long, isSms: Boolean) {
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageID, serverID)
|
DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageID, serverID, isSms)
|
||||||
|
DatabaseFactory.getLokiMessageDatabase(context).setOriginalThreadID(messageID, serverID, threadID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getQuoteServerID(quoteID: Long, publicKey: String): Long? {
|
override fun getQuoteServerID(quoteID: Long, publicKey: String): Long? {
|
||||||
|
@ -54,9 +54,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int lokiV20 = 41;
|
private static final int lokiV20 = 41;
|
||||||
private static final int lokiV21 = 42;
|
private static final int lokiV21 = 42;
|
||||||
private static final int lokiV22 = 43;
|
private static final int lokiV22 = 43;
|
||||||
|
private static final int lokiV23 = 44;
|
||||||
|
|
||||||
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||||
private static final int DATABASE_VERSION = lokiV22;
|
private static final int DATABASE_VERSION = lokiV23;
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -124,6 +125,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand());
|
db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand());
|
||||||
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
|
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
|
||||||
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
|
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
|
||||||
|
db.execSQL(LokiMessageDatabase.getUpdateMessageIDTableForType());
|
||||||
|
db.execSQL(LokiMessageDatabase.getUpdateMessageMappingTable());
|
||||||
|
|
||||||
executeStatements(db, SmsDatabase.CREATE_INDEXS);
|
executeStatements(db, SmsDatabase.CREATE_INDEXS);
|
||||||
executeStatements(db, MmsDatabase.CREATE_INDEXS);
|
executeStatements(db, MmsDatabase.CREATE_INDEXS);
|
||||||
@ -272,6 +275,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
"SendDeliveryReceiptJob");
|
"SendDeliveryReceiptJob");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < lokiV23) {
|
||||||
|
db.execSQL(LokiMessageDatabase.getUpdateMessageIDTableForType());
|
||||||
|
db.execSQL(LokiMessageDatabase.getUpdateMessageMappingTable());
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -6,11 +6,8 @@ import org.session.libsession.messaging.threads.Address
|
|||||||
import org.thoughtcrime.securesms.database.Database
|
import org.thoughtcrime.securesms.database.Database
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||||
import org.thoughtcrime.securesms.loki.utilities.get
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.getInt
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.getString
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate
|
|
||||||
import org.session.libsignal.service.loki.database.LokiMessageDatabaseProtocol
|
import org.session.libsignal.service.loki.database.LokiMessageDatabaseProtocol
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.*
|
||||||
|
|
||||||
class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol {
|
class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol {
|
||||||
|
|
||||||
@ -23,14 +20,21 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
private val friendRequestStatus = "friend_request_status"
|
private val friendRequestStatus = "friend_request_status"
|
||||||
private val threadID = "thread_id"
|
private val threadID = "thread_id"
|
||||||
private val errorMessage = "error_message"
|
private val errorMessage = "error_message"
|
||||||
|
private val messageType = "message_type"
|
||||||
@JvmStatic val createMessageIDTableCommand = "CREATE TABLE $messageIDTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);"
|
@JvmStatic val createMessageIDTableCommand = "CREATE TABLE $messageIDTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);"
|
||||||
@JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTable ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);"
|
@JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTable ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);"
|
||||||
@JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTable ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);"
|
@JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTable ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);"
|
||||||
|
@JvmStatic val updateMessageIDTableForType = "ALTER TABLE $messageIDTable ADD COLUMN $messageType INTEGER DEFAULT 0; ALTER TABLE $messageIDTable ADD CONSTRAINT PK_$messageIDTable PRIMARY KEY ($messageID, $serverID);"
|
||||||
|
@JvmStatic val updateMessageMappingTable = "ALTER TABLE $messageThreadMappingTable ADD COLUMN $serverID INTEGER DEFAULT 0; ALTER TABLE $messageThreadMappingTable ADD CONSTRAINT PK_$messageThreadMappingTable PRIMARY KEY ($messageID, $serverID);"
|
||||||
|
|
||||||
|
const val SMS_TYPE = 0
|
||||||
|
const val MMS_TYPE = 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long? {
|
override fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long? {
|
||||||
val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, quoteePublicKey)
|
val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, quoteePublicKey)
|
||||||
return if (message != null) getServerID(message.getId()) else null
|
return if (message != null) getServerID(message.getId(), !message.isMms) else null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getServerID(messageID: Long): Long? {
|
fun getServerID(messageID: Long): Long? {
|
||||||
@ -40,6 +44,13 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
}?.toLong()
|
}?.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getServerID(messageID: Long, isSms: Boolean): Long? {
|
||||||
|
val database = databaseHelper.readableDatabase
|
||||||
|
return database.get(messageIDTable, "${Companion.messageID} = ? AND $messageType = ?", arrayOf( messageID.toString(), if (isSms) SMS_TYPE.toString() else MMS_TYPE.toString() )) { cursor ->
|
||||||
|
cursor.getInt(serverID)
|
||||||
|
}?.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
fun getMessageID(serverID: Long): Long? {
|
fun getMessageID(serverID: Long): Long? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.get(messageIDTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor ->
|
return database.get(messageIDTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor ->
|
||||||
@ -47,12 +58,22 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
}?.toLong()
|
}?.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setServerID(messageID: Long, serverID: Long) {
|
fun getMessageID(serverID: Long, threadID: Long): Pair<Long,Boolean>? {
|
||||||
|
val database = databaseHelper.readableDatabase
|
||||||
|
return database.get("$messageIDTable INNER JOIN $messageThreadMappingTable ON $messageIDTable.$messageID = $messageThreadMappingTable.$messageID",
|
||||||
|
"${Companion.serverID} = ? AND ${Companion.threadID} = ?",
|
||||||
|
arrayOf(serverID.toString(),threadID.toString())) { cursor ->
|
||||||
|
cursor.getLong(messageID) to (cursor.getInt(messageType) == SMS_TYPE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setServerID(messageID: Long, serverID: Long, isSms: Boolean) {
|
||||||
val database = databaseHelper.writableDatabase
|
val database = databaseHelper.writableDatabase
|
||||||
val contentValues = ContentValues(2)
|
val contentValues = ContentValues(2)
|
||||||
contentValues.put(Companion.messageID, messageID)
|
contentValues.put(Companion.messageID, messageID)
|
||||||
contentValues.put(Companion.serverID, serverID)
|
contentValues.put(Companion.serverID, serverID)
|
||||||
database.insertOrUpdate(messageIDTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
contentValues.put(messageType, if (isSms) SMS_TYPE else MMS_TYPE)
|
||||||
|
database.insertOrUpdate(messageIDTable, contentValues, "${Companion.messageID} = ? AND ${Companion.serverID} = ?", arrayOf( messageID.toString(), serverID.toString() ))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOriginalThreadID(messageID: Long): Long {
|
fun getOriginalThreadID(messageID: Long): Long {
|
||||||
@ -62,12 +83,13 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
}?.toLong() ?: -1L
|
}?.toLong() ?: -1L
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOriginalThreadID(messageID: Long, threadID: Long) {
|
fun setOriginalThreadID(messageID: Long, serverID: Long, threadID: Long) {
|
||||||
val database = databaseHelper.writableDatabase
|
val database = databaseHelper.writableDatabase
|
||||||
val contentValues = ContentValues(2)
|
val contentValues = ContentValues(2)
|
||||||
contentValues.put(Companion.messageID, messageID)
|
contentValues.put(Companion.messageID, messageID)
|
||||||
|
contentValues.put(Companion.serverID, serverID)
|
||||||
contentValues.put(Companion.threadID, threadID)
|
contentValues.put(Companion.threadID, threadID)
|
||||||
database.insertOrUpdate(messageThreadMappingTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
database.insertOrUpdate(messageThreadMappingTable, contentValues, "${Companion.messageID} = ? AND ${Companion.serverID} = ?", arrayOf( messageID.toString(), serverID.toString() ))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getErrorMessage(messageID: Long): String? {
|
fun getErrorMessage(messageID: Long): String? {
|
||||||
|
@ -11,7 +11,8 @@ import java.io.InputStream
|
|||||||
interface MessageDataProvider {
|
interface MessageDataProvider {
|
||||||
|
|
||||||
fun getMessageID(serverID: Long): Long?
|
fun getMessageID(serverID: Long): Long?
|
||||||
fun deleteMessage(messageID: Long)
|
fun getMessageID(serverId: Long, threadId: Long): Pair<Long, Boolean>?
|
||||||
|
fun deleteMessage(messageID: Long, isSms: Boolean)
|
||||||
|
|
||||||
fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment?
|
fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment?
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ interface StorageProtocol {
|
|||||||
// Open Groups
|
// Open Groups
|
||||||
fun getThreadID(openGroupID: String): String?
|
fun getThreadID(openGroupID: String): String?
|
||||||
fun addOpenGroup(server: String, channel: Long)
|
fun addOpenGroup(server: String, channel: Long)
|
||||||
fun setOpenGroupServerMessageID(messageID: Long, serverID: Long)
|
fun setOpenGroupServerMessageID(messageID: Long, serverID: Long, threadID: Long, isSms: Boolean)
|
||||||
fun getQuoteServerID(quoteID: Long, publicKey: String): Long?
|
fun getQuoteServerID(quoteID: Long, publicKey: String): Long?
|
||||||
|
|
||||||
// Open Group Public Keys
|
// Open Group Public Keys
|
||||||
@ -137,7 +137,7 @@ interface StorageProtocol {
|
|||||||
fun getOrCreateThreadIdFor(address: Address): Long
|
fun getOrCreateThreadIdFor(address: Address): Long
|
||||||
fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long
|
fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long
|
||||||
fun getThreadIdFor(address: Address): Long?
|
fun getThreadIdFor(address: Address): Long?
|
||||||
fun getThreadIdForMms(messageId: Long): Long
|
fun getThreadIdForMms(mmsId: Long): Long
|
||||||
|
|
||||||
// Session Request
|
// Session Request
|
||||||
fun getSessionRequestSentTimestamp(publicKey: String): Long?
|
fun getSessionRequestSentTimestamp(publicKey: String): Long?
|
||||||
|
@ -2,6 +2,7 @@ package org.session.libsession.messaging.open_groups
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonNaming
|
import com.fasterxml.jackson.databind.annotation.JsonNaming
|
||||||
|
import com.fasterxml.jackson.databind.type.TypeFactory
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import nl.komponents.kovenant.Kovenant
|
import nl.komponents.kovenant.Kovenant
|
||||||
@ -28,6 +29,8 @@ import org.session.libsignal.utilities.logging.Log
|
|||||||
import org.whispersystems.curve25519.Curve25519
|
import org.whispersystems.curve25519.Curve25519
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
typealias DeletionList = List<OpenGroupAPIV2.MessageDeletion>
|
||||||
|
|
||||||
object OpenGroupAPIV2 {
|
object OpenGroupAPIV2 {
|
||||||
|
|
||||||
private val moderators: HashMap<String, Set<String>> = hashMapOf() // Server URL to (channel ID to set of moderator IDs)
|
private val moderators: HashMap<String, Set<String>> = hashMapOf() // Server URL to (channel ID to set of moderator IDs)
|
||||||
@ -60,7 +63,7 @@ object OpenGroupAPIV2 {
|
|||||||
val imageID: String?
|
val imageID: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy::class)
|
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
|
||||||
data class CompactPollRequest(val roomId: String,
|
data class CompactPollRequest(val roomId: String,
|
||||||
val authToken: String,
|
val authToken: String,
|
||||||
val fromDeletionServerId: Long?,
|
val fromDeletionServerId: Long?,
|
||||||
@ -72,6 +75,11 @@ object OpenGroupAPIV2 {
|
|||||||
val moderators: List<String>
|
val moderators: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
|
||||||
|
data class MessageDeletion @JvmOverloads constructor(val id: Long = 0,
|
||||||
|
val deletedMessageId: Long = 0
|
||||||
|
)
|
||||||
|
|
||||||
data class Request(
|
data class Request(
|
||||||
val verb: HTTP.Verb,
|
val verb: HTTP.Verb,
|
||||||
val room: String?,
|
val room: String?,
|
||||||
@ -93,7 +101,7 @@ object OpenGroupAPIV2 {
|
|||||||
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
|
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun send(request: Request): Promise<Map<*, *>, Exception> {
|
private fun send(request: Request, isJsonRequired: Boolean = true): Promise<Map<*, *>, Exception> {
|
||||||
val parsed = HttpUrl.parse(request.server) ?: return Promise.ofFail(Error.INVALID_URL)
|
val parsed = HttpUrl.parse(request.server) ?: return Promise.ofFail(Error.INVALID_URL)
|
||||||
val urlBuilder = HttpUrl.Builder()
|
val urlBuilder = HttpUrl.Builder()
|
||||||
.scheme(parsed.scheme())
|
.scheme(parsed.scheme())
|
||||||
@ -128,7 +136,7 @@ object OpenGroupAPIV2 {
|
|||||||
if (request.useOnionRouting) {
|
if (request.useOnionRouting) {
|
||||||
val publicKey = MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
|
val publicKey = MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
|
||||||
?: return Promise.ofFail(Error.NO_PUBLIC_KEY)
|
?: return Promise.ofFail(Error.NO_PUBLIC_KEY)
|
||||||
return OnionRequestAPI.sendOnionRequest(requestBuilder.build(), request.server, publicKey)
|
return OnionRequestAPI.sendOnionRequest(requestBuilder.build(), request.server, publicKey, isJSONRequired = isJsonRequired)
|
||||||
.fail { e ->
|
.fail { e ->
|
||||||
if (e is OnionRequestAPI.HTTPRequestFailedAtDestinationException && e.statusCode == 401) {
|
if (e is OnionRequestAPI.HTTPRequestFailedAtDestinationException && e.statusCode == 401) {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
@ -289,7 +297,7 @@ object OpenGroupAPIV2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDeletedMessages(room: String, server: String): Promise<List<Long>, Exception> {
|
fun getDeletedMessages(room: String, server: String): Promise<List<MessageDeletion>, Exception> {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val queryParameters = mutableMapOf<String, String>()
|
val queryParameters = mutableMapOf<String, String>()
|
||||||
storage.getLastDeletionServerId(room, server)?.let { last ->
|
storage.getLastDeletionServerId(room, server)?.let { last ->
|
||||||
@ -297,12 +305,13 @@ object OpenGroupAPIV2 {
|
|||||||
}
|
}
|
||||||
val request = Request(verb = GET, room = room, server = server, endpoint = "deleted_messages", queryParameters = queryParameters)
|
val request = Request(verb = GET, room = room, server = server, endpoint = "deleted_messages", queryParameters = queryParameters)
|
||||||
return send(request).map(sharedContext) { json ->
|
return send(request).map(sharedContext) { json ->
|
||||||
@Suppress("UNCHECKED_CAST") val serverIDs = (json["ids"] as? List<Int>)?.map { it.toLong() }
|
val type = TypeFactory.defaultInstance().constructCollectionType(List::class.java, MessageDeletion::class.java)
|
||||||
?: throw Error.PARSING_FAILED
|
val idsAsString = JsonUtil.toJson(json["ids"])
|
||||||
|
val serverIDs = JsonUtil.fromJson<List<MessageDeletion>>(idsAsString, type) ?: throw Error.PARSING_FAILED
|
||||||
val lastMessageServerId = storage.getLastDeletionServerId(room, server) ?: 0
|
val lastMessageServerId = storage.getLastDeletionServerId(room, server) ?: 0
|
||||||
val serverID = serverIDs.maxOrNull() ?: 0
|
val serverID = serverIDs.maxByOrNull {it.id } ?: serverIDs.first()
|
||||||
if (serverID > lastMessageServerId) {
|
if (serverID.id > lastMessageServerId) {
|
||||||
storage.setLastDeletionServerId(room, server, serverID)
|
storage.setLastDeletionServerId(room, server, serverID.id)
|
||||||
}
|
}
|
||||||
serverIDs
|
serverIDs
|
||||||
}
|
}
|
||||||
@ -343,14 +352,14 @@ object OpenGroupAPIV2 {
|
|||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region General
|
// region General
|
||||||
fun getCompactPoll(rooms: List<String>, server: String): Promise<Map<String,CompactPollResult>, Exception> {
|
fun getCompactPoll(rooms: List<String>, server: String): Promise<Map<String, CompactPollResult>, Exception> {
|
||||||
val requestAuths = rooms.associateWith { room -> getAuthToken(room,server) }
|
val requestAuths = rooms.associateWith { room -> getAuthToken(room, server) }
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val requests = rooms.mapNotNull { room ->
|
val requests = rooms.mapNotNull { room ->
|
||||||
val authToken = try {
|
val authToken = try {
|
||||||
requestAuths[room]?.get()
|
requestAuths[room]?.get()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("Loki", "Failed to get auth token for $room",e)
|
Log.e("Loki", "Failed to get auth token for $room", e)
|
||||||
null
|
null
|
||||||
} ?: return@mapNotNull null
|
} ?: return@mapNotNull null
|
||||||
|
|
||||||
@ -363,7 +372,7 @@ object OpenGroupAPIV2 {
|
|||||||
val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false, parameters = mapOf("requests" to requests))
|
val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false, parameters = mapOf("requests" to requests))
|
||||||
// build a request for all rooms
|
// build a request for all rooms
|
||||||
return send(request = request).map(sharedContext) { json ->
|
return send(request = request).map(sharedContext) { json ->
|
||||||
val results = json["results"] as? Map<*,*> ?: throw Error.PARSING_FAILED
|
val results = json["results"] as? Map<*, *> ?: throw Error.PARSING_FAILED
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,15 @@ import org.session.libsession.messaging.messages.control.ClosedGroupControlMessa
|
|||||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
import org.session.libsession.messaging.messages.visible.*
|
import org.session.libsession.messaging.messages.visible.*
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupAPI
|
import org.session.libsession.messaging.open_groups.*
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupMessage
|
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupMessageV2
|
|
||||||
import org.session.libsession.messaging.threads.Address
|
import org.session.libsession.messaging.threads.Address
|
||||||
|
import org.session.libsession.messaging.threads.recipients.Recipient
|
||||||
import org.session.libsession.messaging.utilities.MessageWrapper
|
import org.session.libsession.messaging.utilities.MessageWrapper
|
||||||
import org.session.libsession.snode.RawResponsePromise
|
import org.session.libsession.snode.RawResponsePromise
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsession.snode.SnodeModule
|
import org.session.libsession.snode.SnodeModule
|
||||||
import org.session.libsession.snode.SnodeMessage
|
import org.session.libsession.snode.SnodeMessage
|
||||||
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsession.utilities.SSKEnvironment
|
import org.session.libsession.utilities.SSKEnvironment
|
||||||
import org.session.libsignal.service.internal.push.PushTransportDetails
|
import org.session.libsignal.service.internal.push.PushTransportDetails
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
@ -290,8 +289,12 @@ object MessageSender {
|
|||||||
// Ignore future self-sends
|
// Ignore future self-sends
|
||||||
storage.addReceivedMessageTimestamp(message.sentTimestamp!!)
|
storage.addReceivedMessageTimestamp(message.sentTimestamp!!)
|
||||||
// Track the open group server message ID
|
// Track the open group server message ID
|
||||||
if (message.openGroupServerMessageID != null) {
|
if (message.openGroupServerMessageID != null && destination is Destination.OpenGroupV2) {
|
||||||
storage.setOpenGroupServerMessageID(messageId, message.openGroupServerMessageID!!)
|
val encoded = GroupUtil.getEncodedOpenGroupID("${destination.server}.${destination.room}".toByteArray())
|
||||||
|
val threadID = storage.getThreadIdFor(Address.fromSerialized(encoded))
|
||||||
|
if (threadID != null && threadID >= 0) {
|
||||||
|
storage.setOpenGroupServerMessageID(messageId, message.openGroupServerMessageID!!, threadID, !(message as VisibleMessage).isMediaMessage())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Mark the message as sent
|
// Mark the message as sent
|
||||||
storage.markAsSent(message.sentTimestamp!!, message.sender?:userPublicKey)
|
storage.markAsSent(message.sentTimestamp!!, message.sender?:userPublicKey)
|
||||||
|
@ -151,9 +151,19 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
|
|||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val context = MessagingModuleConfiguration.shared.context
|
val context = MessagingModuleConfiguration.shared.context
|
||||||
val userPublicKey = storage.getUserPublicKey()
|
val userPublicKey = storage.getUserPublicKey()
|
||||||
|
|
||||||
|
// Get or create thread
|
||||||
|
val threadID = storage.getOrCreateThreadIdFor(message.syncTarget
|
||||||
|
?: message.sender!!, message.groupPublicKey, openGroupID)
|
||||||
|
|
||||||
|
val openGroup = threadID.let {
|
||||||
|
storage.getOpenGroup(it.toString())
|
||||||
|
}
|
||||||
|
|
||||||
// Update profile if needed
|
// Update profile if needed
|
||||||
val newProfile = message.profile
|
val newProfile = message.profile
|
||||||
if (newProfile != null && openGroupID.isNullOrEmpty() && userPublicKey != message.sender) {
|
|
||||||
|
if (newProfile != null && userPublicKey != message.sender && openGroup == null) {
|
||||||
val profileManager = SSKEnvironment.shared.profileManager
|
val profileManager = SSKEnvironment.shared.profileManager
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(message.sender!!), false)
|
val recipient = Recipient.from(context, Address.fromSerialized(message.sender!!), false)
|
||||||
val displayName = newProfile.displayName!!
|
val displayName = newProfile.displayName!!
|
||||||
@ -172,9 +182,6 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get or create thread
|
|
||||||
val threadID = storage.getOrCreateThreadIdFor(message.syncTarget
|
|
||||||
?: message.sender!!, message.groupPublicKey, openGroupID)
|
|
||||||
// Parse quote if needed
|
// Parse quote if needed
|
||||||
var quoteModel: QuoteModel? = null
|
var quoteModel: QuoteModel? = null
|
||||||
if (message.quote != null && proto.dataMessage.hasQuote()) {
|
if (message.quote != null && proto.dataMessage.hasQuote()) {
|
||||||
@ -224,6 +231,10 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
|
|||||||
JobQueue.shared.add(downloadJob)
|
JobQueue.shared.add(downloadJob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val openGroupServerID = message.openGroupServerMessageID
|
||||||
|
if (openGroupServerID != null) {
|
||||||
|
storage.setOpenGroupServerMessageID(messageID, openGroupServerID, threadID, !(message.isMediaMessage() || attachments.isNotEmpty()))
|
||||||
|
}
|
||||||
// Cancel any typing indicators if needed
|
// Cancel any typing indicators if needed
|
||||||
cancelTypingIndicatorsIfNeeded(message.sender!!)
|
cancelTypingIndicatorsIfNeeded(message.sender!!)
|
||||||
//Notify the user if needed
|
//Notify the user if needed
|
||||||
|
@ -9,6 +9,8 @@ import org.session.libsession.messaging.jobs.MessageReceiveJob
|
|||||||
import org.session.libsession.messaging.open_groups.OpenGroup
|
import org.session.libsession.messaging.open_groups.OpenGroup
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupAPI
|
import org.session.libsession.messaging.open_groups.OpenGroupAPI
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupMessage
|
import org.session.libsession.messaging.open_groups.OpenGroupMessage
|
||||||
|
import org.session.libsession.messaging.threads.Address
|
||||||
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.*
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.*
|
||||||
import org.session.libsignal.utilities.logging.Log
|
import org.session.libsignal.utilities.logging.Log
|
||||||
import org.session.libsignal.utilities.successBackground
|
import org.session.libsignal.utilities.successBackground
|
||||||
@ -210,10 +212,13 @@ class OpenGroupPoller(private val openGroup: OpenGroup, private val executorServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun pollForDeletedMessages() {
|
private fun pollForDeletedMessages() {
|
||||||
|
val messagingModule = MessagingModuleConfiguration.shared
|
||||||
|
val address = GroupUtil.getEncodedOpenGroupID(openGroup.id.toByteArray())
|
||||||
|
val threadId = messagingModule.storage.getThreadIdFor(Address.fromSerialized(address)) ?: return
|
||||||
OpenGroupAPI.getDeletedMessageServerIDs(openGroup.channel, openGroup.server).success { deletedMessageServerIDs ->
|
OpenGroupAPI.getDeletedMessageServerIDs(openGroup.channel, openGroup.server).success { deletedMessageServerIDs ->
|
||||||
val deletedMessageIDs = deletedMessageServerIDs.mapNotNull { MessagingModuleConfiguration.shared.messageDataProvider.getMessageID(it) }
|
val deletedMessageIDs = deletedMessageServerIDs.mapNotNull { messagingModule.messageDataProvider.getMessageID(it, threadId) }
|
||||||
deletedMessageIDs.forEach {
|
deletedMessageIDs.forEach { (messageId, isSms) ->
|
||||||
MessagingModuleConfiguration.shared.messageDataProvider.deleteMessage(it)
|
MessagingModuleConfiguration.shared.messageDataProvider.deleteMessage(messageId, isSms)
|
||||||
}
|
}
|
||||||
}.fail {
|
}.fail {
|
||||||
Log.d("Loki", "Failed to get deleted messages for group chat with ID: ${openGroup.channel} on server: ${openGroup.server}.")
|
Log.d("Loki", "Failed to get deleted messages for group chat with ID: ${openGroup.channel} on server: ${openGroup.server}.")
|
||||||
|
@ -7,7 +7,10 @@ import org.session.libsession.messaging.jobs.JobQueue
|
|||||||
import org.session.libsession.messaging.jobs.MessageReceiveJob
|
import org.session.libsession.messaging.jobs.MessageReceiveJob
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupV2
|
import org.session.libsession.messaging.open_groups.OpenGroupV2
|
||||||
|
import org.session.libsession.messaging.threads.Address
|
||||||
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
import org.session.libsignal.service.loki.database.LokiMessageDatabaseProtocol
|
||||||
import org.session.libsignal.utilities.logging.Log
|
import org.session.libsignal.utilities.logging.Log
|
||||||
import org.session.libsignal.utilities.successBackground
|
import org.session.libsignal.utilities.successBackground
|
||||||
import java.util.concurrent.ScheduledExecutorService
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
@ -101,10 +104,17 @@ class OpenGroupV2Poller(private val openGroup: OpenGroupV2, private val executor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun pollForDeletedMessages() {
|
private fun pollForDeletedMessages() {
|
||||||
|
val messagingModule = MessagingModuleConfiguration.shared
|
||||||
|
val address = GroupUtil.getEncodedOpenGroupID(openGroup.id.toByteArray())
|
||||||
|
val threadId = messagingModule.storage.getThreadIdFor(Address.fromSerialized(address)) ?: return
|
||||||
|
|
||||||
OpenGroupAPIV2.getDeletedMessages(openGroup.room, openGroup.server).success { deletedMessageServerIDs ->
|
OpenGroupAPIV2.getDeletedMessages(openGroup.room, openGroup.server).success { deletedMessageServerIDs ->
|
||||||
val deletedMessageIDs = deletedMessageServerIDs.mapNotNull { MessagingModuleConfiguration.shared.messageDataProvider.getMessageID(it) }
|
|
||||||
deletedMessageIDs.forEach {
|
val deletedMessageIDs = deletedMessageServerIDs.mapNotNull { serverId ->
|
||||||
MessagingModuleConfiguration.shared.messageDataProvider.deleteMessage(it)
|
messagingModule.messageDataProvider.getMessageID(serverId.deletedMessageId, threadId)
|
||||||
|
}
|
||||||
|
deletedMessageIDs.forEach { (messageId, isSms) ->
|
||||||
|
MessagingModuleConfiguration.shared.messageDataProvider.deleteMessage(messageId, isSms)
|
||||||
}
|
}
|
||||||
}.fail {
|
}.fail {
|
||||||
Log.d("Loki", "Failed to get deleted messages for group chat with ID: ${openGroup.room} on server: ${openGroup.server}.")
|
Log.d("Loki", "Failed to get deleted messages for group chat with ID: ${openGroup.room} on server: ${openGroup.server}.")
|
||||||
|
@ -3,5 +3,5 @@ package org.session.libsignal.service.loki.database
|
|||||||
interface LokiMessageDatabaseProtocol {
|
interface LokiMessageDatabaseProtocol {
|
||||||
|
|
||||||
fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long?
|
fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long?
|
||||||
fun setServerID(messageID: Long, serverID: Long)
|
fun setServerID(messageID: Long, serverID: Long, isSms: Boolean)
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package org.session.libsignal.utilities;
|
|||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.ResolvedType;
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
@ -42,6 +44,10 @@ public class JsonUtil {
|
|||||||
return objectMapper.readValue(serialized, clazz);
|
return objectMapper.readValue(serialized, clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static<T> T fromJson(String serialized, JavaType clazz) throws IOException {
|
||||||
|
return objectMapper.readValue(serialized, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> T fromJson(InputStream serialized, Class<T> clazz) throws IOException {
|
public static <T> T fromJson(InputStream serialized, Class<T> clazz) throws IOException {
|
||||||
return objectMapper.readValue(serialized, clazz);
|
return objectMapper.readValue(serialized, clazz);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user