From d1e457713253d1329e9a2198e1f3b200885a256d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 4 Jun 2019 11:05:03 +1000 Subject: [PATCH] Implement LokiAPIDatabase --- .../database/helpers/SQLCipherOpenHelper.java | 4 +- .../securesms/loki/LokiAPIDatabase.kt | 82 +++++++++++++++---- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index a1c4adb04a..3d3bae2bf5 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -113,7 +113,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { for (String sql : JobDatabase.CREATE_TABLE) { db.execSQL(sql); } - db.execSQL(LokiAPIDatabase.getCreateTableCommand()); + db.execSQL(LokiAPIDatabase.getCreateSwarmCacheTableCommand()); + db.execSQL(LokiAPIDatabase.getCreateLastMessageHashValueTableCommand()); + db.execSQL(LokiAPIDatabase.getCreateReceivedMessageHashValuesTableCommand()); executeStatements(db, SmsDatabase.CREATE_INDEXS); executeStatements(db, MmsDatabase.CREATE_INDEXS); diff --git a/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt index ff2a4b70b5..6d08fff367 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt @@ -1,44 +1,94 @@ package org.thoughtcrime.securesms.loki +import android.content.ContentValues import android.content.Context +import android.database.Cursor import org.thoughtcrime.securesms.database.Database import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol import org.whispersystems.signalservice.loki.api.LokiAPITarget +import org.whispersystems.signalservice.loki.api.LokiSwarmAPI class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiAPIDatabaseProtocol { companion object { - private val tableKey = "loki_api_database" - private val swarmCacheKey = "swarm_cache" - private val lastMessageHashValueKey = "last_message_hash_value" - private val receivedMessageHashValuesKey = "received_message_hash_values" - - @JvmStatic - val createTableCommand = "CREATE TABLE $tableKey ($swarmCacheKey TEXT, $lastMessageHashValueKey TEXT, $receivedMessageHashValuesKey TEXT);" + // Swarm cache + private val swarmCache = "loki_api_swarm_cache" + private val hexEncodedPublicKey = "hex_encoded_public_key" + private val swarm = "swarm" + @JvmStatic val createSwarmCacheTableCommand = "CREATE TABLE $swarmCache ($hexEncodedPublicKey TEXT, $swarm TEXT);" + // Last message hash value cache + private val lastMessageHashValueCache = "loki_api_last_message_hash_value_cache" + private val target = "target" + private val lastMessageHashValue = "last_message_hash_value" + @JvmStatic val createLastMessageHashValueTableCommand = "CREATE TABLE $lastMessageHashValueCache ($target TEXT, $lastMessageHashValue TEXT);" + // Received message hash values cache + private val receivedMessageHashValuesCache = "loki_api_received_message_hash_values_cache" + private val userID = "user_id" + private val receivedMessageHashValues = "received_message_hash_values" + @JvmStatic val createReceivedMessageHashValuesTableCommand = "CREATE TABLE $receivedMessageHashValuesCache ($userID TEXT, $receivedMessageHashValues TEXT);" } - override fun getSwarmCache(): Map>? { - return null + override fun getSwarmCache(hexEncodedPublicKey: String): List? { + return get(swarmCache, "${Companion.hexEncodedPublicKey} = ?", wrap(hexEncodedPublicKey)) { cursor -> + val swarmAsString = cursor.getString(cursor.getColumnIndexOrThrow(swarm)) + swarmAsString.split(",").map { LokiAPITarget(it, LokiSwarmAPI.defaultSnodePort) } + } } - override fun setSwarmCache(newValue: Map>) { - // TODO: Implement + override fun setSwarmCache(hexEncodedPublicKey: String, newValue: List) { + val database = databaseHelper.writableDatabase + val swarmAsString = newValue.joinToString(",") { it.address } + database.update(swarmCache, wrap(mapOf( swarm to swarmAsString )), "${Companion.hexEncodedPublicKey} = ?", wrap(hexEncodedPublicKey)) } override fun getLastMessageHashValue(target: LokiAPITarget): String? { - return null + return get(lastMessageHashValueCache, "${Companion.target} = ?", wrap(target.address)) { cursor -> + cursor.getString(cursor.getColumnIndexOrThrow(lastMessageHashValue)) + } } override fun setLastMessageHashValue(target: LokiAPITarget, newValue: String) { - // TODO: Implement + val database = databaseHelper.writableDatabase + database.update(lastMessageHashValueCache, wrap(mapOf( lastMessageHashValue to newValue )), "${Companion.target} = ?", wrap(target.address)) } override fun getReceivedMessageHashValues(): Set? { - return null + return get(receivedMessageHashValuesCache, "$userID = ?", wrap("0")) { cursor -> + val receivedMessageHashValuesAsString = cursor.getString(cursor.getColumnIndexOrThrow(receivedMessageHashValues)) + receivedMessageHashValuesAsString.split(",").toSet() + } } override fun setReceivedMessageHashValues(newValue: Set) { - // TODO: Implement + val database = databaseHelper.writableDatabase + val receivedMessageHashValuesAsString = newValue.joinToString(",") + database.update(receivedMessageHashValuesCache, wrap(mapOf( receivedMessageHashValues to receivedMessageHashValuesAsString )), "$userID = ?", wrap("0")) } -} \ No newline at end of file + + // region Convenience + private fun get(table: String, query: String, arguments: Array, get: (Cursor) -> T): T? { + val database = databaseHelper.readableDatabase + var cursor: Cursor? = null + try { + cursor = database.query(table, null, query, arguments, null, null, null) + if (cursor != null && cursor.moveToFirst()) { return get(cursor) } + } catch (e: Exception) { + // Do nothing + } finally { + cursor?.close() + } + return null + } +} + +private inline fun wrap(x: T): Array { + return Array(1) { x } +} + +private fun wrap(x: Map): ContentValues { + val result = ContentValues(x.size) + x.forEach { result.put(it.key, it.value) } + return result +} +// endregion \ No newline at end of file