commit b925e8f54664d9aa7f92d43693a886051e1960af
parent 607521ec7605f09d7650a8e5f6b969d1f926fa60
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Sun, 17 Dec 2023 19:09:01 +0100
feat(core/message_logger): auto purge & message filter
- optimize bridge addMessage
Diffstat:
8 files changed, 98 insertions(+), 19 deletions(-)
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt b/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt
@@ -108,6 +108,11 @@ class RemoteSideContext(
streaksReminder.init()
scriptManager.init()
messageLogger.init()
+ config.root.messaging.messageLogger.takeIf {
+ it.globalState == true
+ }?.getAutoPurgeTime()?.let {
+ messageLogger.purgeAll(it)
+ }
}.onFailure {
log.error("Failed to load RemoteSideContext", it)
}
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/home/SettingsSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/home/SettingsSection.kt
@@ -161,7 +161,7 @@ class SettingsSection(
}
Button(onClick = {
runCatching {
- context.messageLogger.clearAll()
+ context.messageLogger.purgeAll()
storedMessagesCount = 0
storedStoriesCount = 0
}.onFailure {
diff --git a/common/src/main/aidl/me/rhunk/snapenhance/bridge/MessageLoggerInterface.aidl b/common/src/main/aidl/me/rhunk/snapenhance/bridge/MessageLoggerInterface.aidl
@@ -15,12 +15,12 @@ interface MessageLoggerInterface {
/**
* Add a message to the message logger database if it is not already there
*/
- boolean addMessage(String conversationId, long id, in byte[] message);
+ oneway void addMessage(String conversationId, long id, in byte[] message);
/**
* Delete a message from the message logger database
*/
- void deleteMessage(String conversationId, long id);
+ oneway void deleteMessage(String conversationId, long id);
/**
* Add a story to the message logger database if it is not already there
diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json
@@ -405,7 +405,21 @@
},
"message_logger": {
"name": "Message Logger",
- "description": "Prevents messages from being deleted"
+ "description": "Prevents messages from being deleted",
+ "properties": {
+ "keep_my_own_messages": {
+ "name": "Keep My Own Messages",
+ "description": "Prevents your own messages from being deleted"
+ },
+ "auto_purge": {
+ "name": "Auto Purge",
+ "description": "Automatically deletes cached messages that are older than the specified amount of time"
+ },
+ "message_filter": {
+ "name": "Message Filter",
+ "description": "Select which messages should get logged (empty for all messages)"
+ }
+ }
},
"auto_save_messages_in_conversations": {
"name": "Auto Save Messages",
@@ -806,6 +820,20 @@
"edit_text_override": {
"multi_line_chat_input": "Multi Line Chat Input",
"bypass_text_input_limit": "Bypass Text Input Limit"
+ },
+ "auto_purge": {
+ "never": "Never",
+ "1_hour": "1 Hour",
+ "3_hours": "3 Hours",
+ "6_hours": "6 Hours",
+ "12_hours": "12 Hours",
+ "1_day": "1 Day",
+ "3_days": "3 Days",
+ "1_week": "1 Week",
+ "2_weeks": "2 Weeks",
+ "1_month": "1 Month",
+ "3_months": "3 Months",
+ "6_months": "6 Months"
}
}
},
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/bridge/wrapper/MessageLoggerWrapper.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/bridge/wrapper/MessageLoggerWrapper.kt
@@ -26,12 +26,14 @@ class MessageLoggerWrapper(
SQLiteDatabaseHelper.createTablesFromSchema(openedDatabase, mapOf(
"messages" to listOf(
"id INTEGER PRIMARY KEY",
+ "added_timestamp BIGINT",
"conversation_id VARCHAR",
"message_id BIGINT",
"message_data BLOB"
),
"stories" to listOf(
"id INTEGER PRIMARY KEY",
+ "added_timestamp BIGINT",
"user_id VARCHAR",
"posted_timestamp BIGINT",
"created_timestamp BIGINT",
@@ -83,29 +85,33 @@ class MessageLoggerWrapper(
return message
}
- override fun addMessage(conversationId: String, messageId: Long, serializedMessage: ByteArray): Boolean {
+ override fun addMessage(conversationId: String, messageId: Long, serializedMessage: ByteArray) {
val cursor = database.rawQuery("SELECT message_id FROM messages WHERE conversation_id = ? AND message_id = ?", arrayOf(conversationId, messageId.toString()))
val state = cursor.moveToFirst()
cursor.close()
- if (state) {
- return false
- }
+ if (state) return
runBlocking {
withContext(coroutineScope.coroutineContext) {
database.insert("messages", null, ContentValues().apply {
+ put("added_timestamp", System.currentTimeMillis())
put("conversation_id", conversationId)
put("message_id", messageId)
put("message_data", serializedMessage)
})
}
}
- return true
}
- fun clearAll() {
+ fun purgeAll(maxAge: Long? = null) {
coroutineScope.launch {
- database.execSQL("DELETE FROM messages")
- database.execSQL("DELETE FROM stories")
+ maxAge?.let {
+ val maxTime = System.currentTimeMillis() - it
+ database.execSQL("DELETE FROM messages WHERE added_timestamp < ?", arrayOf(maxTime.toString()))
+ database.execSQL("DELETE FROM stories WHERE added_timestamp < ?", arrayOf(maxTime.toString()))
+ } ?: run {
+ database.execSQL("DELETE FROM messages")
+ database.execSQL("DELETE FROM stories")
+ }
}
}
@@ -141,6 +147,7 @@ class MessageLoggerWrapper(
withContext(coroutineScope.coroutineContext) {
database.insert("stories", null, ContentValues().apply {
put("user_id", userId)
+ put("added_timestamp", System.currentTimeMillis())
put("url", url)
put("posted_timestamp", postedAt)
put("created_timestamp", createdAt)
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt
@@ -15,6 +15,39 @@ class MessagingTweaks : ConfigContainer() {
}
}
+ inner class MessageLoggerConfig : ConfigContainer(hasGlobalState = true) {
+ val keepMyOwnMessages = boolean("keep_my_own_messages")
+ private val autoPurge = unique("auto_purge", "1_hour", "3_hours", "6_hours", "12_hours", "1_day", "3_days", "1_week", "2_weeks", "1_month", "3_months", "6_months") {
+ disabledKey = "features.options.auto_purge.never"
+ }.apply { set("3_days") }
+
+ fun getAutoPurgeTime(): Long? {
+ return when (autoPurge.getNullable()) {
+ "1_hour" -> 3600000L
+ "3_hours" -> 10800000L
+ "6_hours" -> 21600000L
+ "12_hours" -> 43200000L
+ "1_day" -> 86400000L
+ "3_days" -> 259200000L
+ "1_week" -> 604800000L
+ "2_weeks" -> 1209600000L
+ "1_month" -> 2592000000L
+ "3_months" -> 7776000000L
+ "6_months" -> 15552000000L
+ else -> null
+ }
+ }
+
+ val messageFilter = multiple("message_filter", "CHAT",
+ "SNAP",
+ "NOTE",
+ "EXTERNAL_MEDIA",
+ "STICKER"
+ ) {
+ customOptionTranslationPath = "content_type"
+ }
+ }
+
val bypassScreenshotDetection = boolean("bypass_screenshot_detection") { requireRestart() }
val anonymousStoryViewing = boolean("anonymous_story_viewing")
val preventStoryRewatchIndicator = boolean("prevent_story_rewatch_indicator") { requireRestart() }
@@ -42,7 +75,7 @@ class MessagingTweaks : ConfigContainer() {
val notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray()) {
customOptionTranslationPath = "features.options.notifications"
}
- val messageLogger = boolean("message_logger") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
+ val messageLogger = container("message_logger", MessageLoggerConfig()) { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
val galleryMediaSendOverride = boolean("gallery_media_send_override") { nativeHooks() }
val stripMediaMetadata = multiple("strip_media_metadata", "hide_caption_text", "hide_snap_filters", "hide_extras", "remove_audio_note_duration", "remove_audio_note_transcript_capability") { requireRestart() }
val bypassMessageRetentionPolicy = boolean("bypass_message_retention_policy") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/spying/MessageLogger.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/spying/MessageLogger.kt
@@ -34,7 +34,7 @@ class MessageLogger : Feature("MessageLogger",
private val messageLoggerInterface by lazy { context.bridgeClient.getMessageLogger() }
- val isEnabled get() = context.config.messaging.messageLogger.get()
+ val isEnabled get() = context.config.messaging.messageLogger.globalState == true
private val threadPool = Executors.newFixedThreadPool(10)
@@ -97,18 +97,24 @@ class MessageLogger : Feature("MessageLogger",
}
override fun init() {
- context.event.subscribe(BuildMessageEvent::class, { isEnabled }, priority = 1) { event ->
+ if (!isEnabled) return
+ val keepMyOwnMessages = context.config.messaging.messageLogger.keepMyOwnMessages.get()
+ val messageFilter by context.config.messaging.messageLogger.messageFilter
+
+ context.event.subscribe(BuildMessageEvent::class, priority = 1) { event ->
val messageInstance = event.message.instanceNonNull()
if (event.message.messageState != MessageState.COMMITTED) return@subscribe
cachedIdLinks[event.message.messageDescriptor!!.messageId!!] = event.message.orderKey!!
val conversationId = event.message.messageDescriptor!!.conversationId.toString()
//exclude messages sent by me
- if (event.message.senderId.toString() == context.database.myUserId) return@subscribe
+ if (!keepMyOwnMessages && event.message.senderId.toString() == context.database.myUserId) return@subscribe
val uniqueMessageIdentifier = computeMessageIdentifier(conversationId, event.message.orderKey!!)
+ val messageContentType = event.message.messageContent!!.contentType
- if (event.message.messageContent!!.contentType != ContentType.STATUS) {
+ if (messageContentType != ContentType.STATUS) {
+ if (messageFilter.isNotEmpty() && !messageFilter.contains(messageContentType?.name)) return@subscribe
if (fetchedMessages.contains(uniqueMessageIdentifier)) return@subscribe
fetchedMessages.add(uniqueMessageIdentifier)
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/ChatActionMenu.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/ChatActionMenu.kt
@@ -66,7 +66,7 @@ class ChatActionMenu : AbstractMenu() {
override fun init() {
runCatching {
- if (!context.config.downloader.chatDownloadContextMenu.get() && !context.config.messaging.messageLogger.get() && !context.isDeveloper) return
+ if (!context.config.downloader.chatDownloadContextMenu.get() && context.config.messaging.messageLogger.globalState != true && !context.isDeveloper) return
context.androidContext.classLoader.loadClass("com.snap.messaging.chat.features.actionmenu.ActionMenuChatItemContainer")
.hook("onMeasure", HookStage.BEFORE) { param ->
param.setArg(1,
@@ -136,7 +136,7 @@ class ChatActionMenu : AbstractMenu() {
}
//delete logged message button
- if (context.config.messaging.messageLogger.get()) {
+ if (context.config.messaging.messageLogger.globalState == true) {
injectButton(Button(viewGroup.context).apply {
text = this@ChatActionMenu.context.translation["chat_action_menu.delete_logged_message_button"]
setOnClickListener {