refactor: mapping wrapper

- rename members
This commit is contained in:
rhunk
2023-08-07 00:38:20 +02:00
parent 289afce4a5
commit 3fc6030a23
13 changed files with 138 additions and 98 deletions

View File

@ -13,6 +13,7 @@ import com.google.gson.GsonBuilder
import kotlinx.coroutines.asCoroutineDispatcher
import me.rhunk.snapenhance.bridge.BridgeClient
import me.rhunk.snapenhance.bridge.wrapper.LocaleWrapper
import me.rhunk.snapenhance.bridge.wrapper.MappingsWrapper
import me.rhunk.snapenhance.core.config.ModConfig
import me.rhunk.snapenhance.core.eventbus.EventBus
import me.rhunk.snapenhance.data.MessageSender
@ -20,7 +21,6 @@ import me.rhunk.snapenhance.database.DatabaseAccess
import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.manager.impl.ActionManager
import me.rhunk.snapenhance.manager.impl.FeatureManager
import me.rhunk.snapenhance.manager.impl.MappingManager
import me.rhunk.snapenhance.util.download.DownloadServer
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
@ -47,7 +47,7 @@ class ModContext {
val translation = LocaleWrapper()
val features = FeatureManager(this)
val mappings = MappingManager(this)
val mappings = MappingsWrapper()
val actionManager = ActionManager(this)
val database = DatabaseAccess(this)
val downloadServer = DownloadServer()

View File

@ -66,7 +66,7 @@ class SnapEnhance {
if (!activity.packageName.equals(Constants.SNAPCHAT_PACKAGE_NAME)) return@hook
val isMainActivityNotNull = appContext.mainActivity != null
appContext.mainActivity = activity
if (isMainActivityNotNull || !appContext.mappings.areMappingsLoaded) return@hook
if (isMainActivityNotNull || !appContext.mappings.isMappingsLoaded()) return@hook
onActivityCreate()
}
@ -95,13 +95,14 @@ class SnapEnhance {
reloadConfig()
withContext(appContext.coroutineDispatcher) {
translation.userLocale = getConfigLocale()
translation.loadFromBridge(appContext.bridgeClient)
translation.loadFromBridge(bridgeClient)
}
mappings.init()
mappings.loadFromBridge(bridgeClient)
mappings.init(androidContext)
eventDispatcher.init()
//if mappings aren't loaded, we can't initialize features
if (!mappings.areMappingsLoaded) return
if (!mappings.isMappingsLoaded()) return
features.init()
}
}.also { time ->

View File

@ -11,6 +11,7 @@ import me.rhunk.snapenhance.bridge.types.BridgeFileType
import me.rhunk.snapmapper.Mapper
import me.rhunk.snapmapper.impl.BCryptClassMapper
import me.rhunk.snapmapper.impl.CallbackMapper
import me.rhunk.snapmapper.impl.CompositeConfigurationProviderMapper
import me.rhunk.snapmapper.impl.DefaultMediaItemMapper
import me.rhunk.snapmapper.impl.EnumMapper
import me.rhunk.snapmapper.impl.FriendsFeedEventDispatcherMapper
@ -19,13 +20,12 @@ import me.rhunk.snapmapper.impl.OperaPageViewControllerMapper
import me.rhunk.snapmapper.impl.PlatformAnalyticsCreatorMapper
import me.rhunk.snapmapper.impl.PlusSubscriptionMapper
import me.rhunk.snapmapper.impl.ScCameraSettingsMapper
import me.rhunk.snapmapper.impl.ScoreUpdateMapper
import me.rhunk.snapmapper.impl.StoryBoostStateMapper
import java.util.concurrent.ConcurrentHashMap
import kotlin.system.measureTimeMillis
class MappingsWrapper(
private val context: Context,
) : FileLoaderWrapper(BridgeFileType.MAPPINGS, "{}".toByteArray(Charsets.UTF_8)) {
class MappingsWrapper : FileLoaderWrapper(BridgeFileType.MAPPINGS, "{}".toByteArray(Charsets.UTF_8)) {
companion object {
private val gson = GsonBuilder().setPrettyPrinting().create()
private val mappers = arrayOf(
@ -39,14 +39,19 @@ class MappingsWrapper(
PlusSubscriptionMapper::class,
ScCameraSettingsMapper::class,
StoryBoostStateMapper::class,
FriendsFeedEventDispatcherMapper::class
FriendsFeedEventDispatcherMapper::class,
CompositeConfigurationProviderMapper::class,
ScoreUpdateMapper::class
)
}
private lateinit var context: Context
private val mappings = ConcurrentHashMap<String, Any>()
private var snapBuildNumber: Long = 0
fun init() {
fun init(context: Context) {
this.context = context
snapBuildNumber = getSnapchatVersionCode()
if (isFileExists()) {
@ -56,6 +61,8 @@ class MappingsWrapper(
Logger.error("Failed to load cached mappings", it)
delete()
}
} else {
Logger.debug("Mappings file does not exist")
}
}

View File

@ -4,7 +4,6 @@ class SnapClassCache (
private val classLoader: ClassLoader
) {
val snapUUID by lazy { findClass("com.snapchat.client.messaging.UUID") }
val composerLocalSubscriptionStore by lazy { findClass("com.snap.plus.lib.common.ComposerLocalSubscriptionStore") }
val snapManager by lazy { findClass("com.snapchat.client.messaging.SnapManager\$CppProxy") }
val conversationManager by lazy { findClass("com.snapchat.client.messaging.ConversationManager\$CppProxy") }
val presenceSession by lazy { findClass("com.snapchat.talkcorev3.PresenceSession\$CppProxy") }

View File

@ -5,39 +5,45 @@ import android.database.Cursor
import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.data.ContentType
import me.rhunk.snapenhance.database.DatabaseObject
import me.rhunk.snapenhance.util.getBlobOrNull
import me.rhunk.snapenhance.util.getInteger
import me.rhunk.snapenhance.util.getLong
import me.rhunk.snapenhance.util.getStringOrNull
import me.rhunk.snapenhance.util.protobuf.ProtoReader
@Suppress("ArrayInDataClass")
data class ConversationMessage(
var client_conversation_id: String? = null,
var client_message_id: Int = 0,
var server_message_id: Int = 0,
var message_content: ByteArray? = null,
var is_saved: Int = 0,
var is_viewed_by_user: Int = 0,
var content_type: Int = 0,
var creation_timestamp: Long = 0,
var read_timestamp: Long = 0,
var sender_id: String? = null
var clientConversationId: String? = null,
var clientMessageId: Int = 0,
var serverMessageId: Int = 0,
var messageContent: ByteArray? = null,
var isSaved: Int = 0,
var isViewedByUser: Int = 0,
var contentType: Int = 0,
var creationTimestamp: Long = 0,
var readTimestamp: Long = 0,
var senderId: String? = null
) : DatabaseObject {
@SuppressLint("Range")
override fun write(cursor: Cursor) {
client_conversation_id = cursor.getString(cursor.getColumnIndex("client_conversation_id"))
client_message_id = cursor.getInt(cursor.getColumnIndex("client_message_id"))
server_message_id = cursor.getInt(cursor.getColumnIndex("server_message_id"))
message_content = cursor.getBlob(cursor.getColumnIndex("message_content"))
is_saved = cursor.getInt(cursor.getColumnIndex("is_saved"))
is_viewed_by_user = cursor.getInt(cursor.getColumnIndex("is_viewed_by_user"))
content_type = cursor.getInt(cursor.getColumnIndex("content_type"))
creation_timestamp = cursor.getLong(cursor.getColumnIndex("creation_timestamp"))
read_timestamp = cursor.getLong(cursor.getColumnIndex("read_timestamp"))
sender_id = cursor.getString(cursor.getColumnIndex("sender_id"))
with(cursor) {
clientConversationId = getStringOrNull("client_conversation_id")
clientMessageId = getInteger("client_message_id")
serverMessageId = getInteger("server_message_id")
messageContent = getBlobOrNull("message_content")
isSaved = getInteger("is_saved")
isViewedByUser = getInteger("is_viewed_by_user")
contentType = getInteger("content_type")
creationTimestamp = getLong("creation_timestamp")
readTimestamp = getLong("read_timestamp")
senderId = getStringOrNull("sender_id")
}
}
fun getMessageAsString(): String? {
return when (ContentType.fromId(content_type)) {
ContentType.CHAT -> message_content?.let { ProtoReader(it).getString(*Constants.ARROYO_STRING_CHAT_MESSAGE_PROTO) }
return when (ContentType.fromId(contentType)) {
ContentType.CHAT -> messageContent?.let { ProtoReader(it).getString(*Constants.ARROYO_STRING_CHAT_MESSAGE_PROTO) }
else -> null
}
}

View File

@ -3,6 +3,9 @@ package me.rhunk.snapenhance.database.objects
import android.annotation.SuppressLint
import android.database.Cursor
import me.rhunk.snapenhance.database.DatabaseObject
import me.rhunk.snapenhance.util.getInteger
import me.rhunk.snapenhance.util.getLong
import me.rhunk.snapenhance.util.getStringOrNull
data class FriendFeedInfo(
var id: Int = 0,
@ -19,15 +22,17 @@ data class FriendFeedInfo(
@SuppressLint("Range")
override fun write(cursor: Cursor) {
id = cursor.getInt(cursor.getColumnIndex("_id"))
feedDisplayName = cursor.getString(cursor.getColumnIndex("feedDisplayName"))
participantsSize = cursor.getInt(cursor.getColumnIndex("participantsSize"))
lastInteractionTimestamp = cursor.getLong(cursor.getColumnIndex("lastInteractionTimestamp"))
displayTimestamp = cursor.getLong(cursor.getColumnIndex("displayTimestamp"))
displayInteractionType = cursor.getString(cursor.getColumnIndex("displayInteractionType"))
lastInteractionUserId = cursor.getInt(cursor.getColumnIndex("lastInteractionUserId"))
key = cursor.getString(cursor.getColumnIndex("key"))
friendUserId = cursor.getString(cursor.getColumnIndex("friendUserId"))
friendDisplayName = cursor.getString(cursor.getColumnIndex("friendDisplayUsername"))
with(cursor) {
id = getInteger("_id")
feedDisplayName = getStringOrNull("feedDisplayName")
participantsSize = getInteger("participantsSize")
lastInteractionTimestamp = getLong("lastInteractionTimestamp")
displayTimestamp = getLong("displayTimestamp")
displayInteractionType = getStringOrNull("displayInteractionType")
lastInteractionUserId = getInteger("lastInteractionUserId")
key = getStringOrNull("key")
friendUserId = getStringOrNull("friendUserId")
friendDisplayName = getStringOrNull("friendDisplayUsername")
}
}
}

View File

@ -3,6 +3,9 @@ package me.rhunk.snapenhance.database.objects
import android.annotation.SuppressLint
import android.database.Cursor
import me.rhunk.snapenhance.database.DatabaseObject
import me.rhunk.snapenhance.util.getInteger
import me.rhunk.snapenhance.util.getLong
import me.rhunk.snapenhance.util.getStringOrNull
data class FriendInfo(
var id: Int = 0,
@ -30,29 +33,31 @@ data class FriendInfo(
) : DatabaseObject {
@SuppressLint("Range")
override fun write(cursor: Cursor) {
id = cursor.getInt(cursor.getColumnIndex("_id"))
lastModifiedTimestamp = cursor.getLong(cursor.getColumnIndex("_lastModifiedTimestamp"))
username = cursor.getString(cursor.getColumnIndex("username"))
userId = cursor.getString(cursor.getColumnIndex("userId"))
displayName = cursor.getString(cursor.getColumnIndex("displayName"))
bitmojiAvatarId = cursor.getString(cursor.getColumnIndex("bitmojiAvatarId"))
bitmojiSelfieId = cursor.getString(cursor.getColumnIndex("bitmojiSelfieId"))
bitmojiSceneId = cursor.getString(cursor.getColumnIndex("bitmojiSceneId"))
bitmojiBackgroundId = cursor.getString(cursor.getColumnIndex("bitmojiBackgroundId"))
friendmojis = cursor.getString(cursor.getColumnIndex("friendmojis"))
friendmojiCategories = cursor.getString(cursor.getColumnIndex("friendmojiCategories"))
snapScore = cursor.getInt(cursor.getColumnIndex("score"))
birthday = cursor.getLong(cursor.getColumnIndex("birthday"))
addedTimestamp = cursor.getLong(cursor.getColumnIndex("addedTimestamp"))
reverseAddedTimestamp = cursor.getLong(cursor.getColumnIndex("reverseAddedTimestamp"))
serverDisplayName = cursor.getString(cursor.getColumnIndex("serverDisplayName"))
streakLength = cursor.getInt(cursor.getColumnIndex("streakLength"))
streakExpirationTimestamp = cursor.getLong(cursor.getColumnIndex("streakExpiration"))
reverseBestFriendRanking = cursor.getInt(cursor.getColumnIndex("reverseBestFriendRanking"))
usernameForSorting = cursor.getString(cursor.getColumnIndex("usernameForSorting"))
if (cursor.getColumnIndex("isPinnedBestFriend") != -1) isPinnedBestFriend =
cursor.getInt(cursor.getColumnIndex("isPinnedBestFriend"))
if (cursor.getColumnIndex("plusBadgeVisibility") != -1) plusBadgeVisibility =
cursor.getInt(cursor.getColumnIndex("plusBadgeVisibility"))
with(cursor) {
id = getInteger("_id")
lastModifiedTimestamp = getLong("_lastModifiedTimestamp")
username = getStringOrNull("username")
userId = getStringOrNull("userId")
displayName = getStringOrNull("displayName")
bitmojiAvatarId = getStringOrNull("bitmojiAvatarId")
bitmojiSelfieId = getStringOrNull("bitmojiSelfieId")
bitmojiSceneId = getStringOrNull("bitmojiSceneId")
bitmojiBackgroundId = getStringOrNull("bitmojiBackgroundId")
friendmojis = getStringOrNull("friendmojis")
friendmojiCategories = getStringOrNull("friendmojiCategories")
snapScore = getInteger("score")
birthday = getLong("birthday")
addedTimestamp = getLong("addedTimestamp")
reverseAddedTimestamp = getLong("reverseAddedTimestamp")
serverDisplayName = getStringOrNull("serverDisplayName")
streakLength = getInteger("streakLength")
streakExpirationTimestamp = getLong("streakExpiration")
reverseBestFriendRanking = getInteger("reverseBestFriendRanking")
usernameForSorting = getStringOrNull("usernameForSorting")
if (getColumnIndex("isPinnedBestFriend") != -1) isPinnedBestFriend =
getInteger("isPinnedBestFriend")
if (getColumnIndex("plusBadgeVisibility") != -1) plusBadgeVisibility =
getInteger("plusBadgeVisibility")
}
}
}

View File

@ -3,6 +3,8 @@ package me.rhunk.snapenhance.database.objects
import android.annotation.SuppressLint
import android.database.Cursor
import me.rhunk.snapenhance.database.DatabaseObject
import me.rhunk.snapenhance.util.getInteger
import me.rhunk.snapenhance.util.getStringOrNull
data class StoryEntry(
var id: Int = 0,
@ -14,10 +16,12 @@ data class StoryEntry(
@SuppressLint("Range")
override fun write(cursor: Cursor) {
id = cursor.getInt(cursor.getColumnIndex("_id"))
storyId = cursor.getString(cursor.getColumnIndex("storyId"))
displayName = cursor.getString(cursor.getColumnIndex("displayName"))
isLocal = cursor.getInt(cursor.getColumnIndex("isLocal")) == 1
userId = cursor.getString(cursor.getColumnIndex("userId"))
with(cursor) {
id = getInteger("_id")
storyId = getStringOrNull("storyId")
displayName = getStringOrNull("displayName")
isLocal = getInteger("isLocal") == 1
userId = getStringOrNull("userId")
}
}
}

View File

@ -3,17 +3,21 @@ package me.rhunk.snapenhance.database.objects
import android.annotation.SuppressLint
import android.database.Cursor
import me.rhunk.snapenhance.database.DatabaseObject
import me.rhunk.snapenhance.util.getInteger
import me.rhunk.snapenhance.util.getStringOrNull
class UserConversationLink(
var user_id: String? = null,
var client_conversation_id: String? = null,
var conversation_type: Int = 0
var userId: String? = null,
var clientConversationId: String? = null,
var conversationType: Int = 0
) : DatabaseObject {
@SuppressLint("Range")
override fun write(cursor: Cursor) {
user_id = cursor.getString(cursor.getColumnIndex("user_id"))
client_conversation_id = cursor.getString(cursor.getColumnIndex("client_conversation_id"))
conversation_type = cursor.getInt(cursor.getColumnIndex("conversation_type"))
with(cursor) {
userId = getStringOrNull("user_id")
clientConversationId = getStringOrNull("client_conversation_id")
conversationType = getInteger("conversation_type")
}
}
}

View File

@ -228,8 +228,8 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
val messageId = id.substring(id.lastIndexOf(":") + 1).toLong()
val conversationMessage = context.database.getConversationMessageFromId(messageId)!!
val senderId = conversationMessage.sender_id!!
val conversationId = conversationMessage.client_conversation_id!!
val senderId = conversationMessage.senderId!!
val conversationId = conversationMessage.clientConversationId!!
if (!forceDownload && context.feature(AntiAutoDownload::class).isUserIgnored(senderId)) {
return
@ -240,7 +240,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
downloadOperaMedia(provideDownloadManagerClient(
pathSuffix = authorUsername,
mediaIdentifier = "$conversationId$senderId${conversationMessage.server_message_id}",
mediaIdentifier = "$conversationId$senderId${conversationMessage.serverMessageId}",
mediaDisplaySource = authorUsername,
mediaDisplayType = MediaFilter.CHAT_MEDIA.key,
friendInfo = author
@ -266,9 +266,9 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
?.split(":")?.getOrNull(2) ?: return@let
val conversationMessage = context.database.getConversationMessageFromId(arroyoMessageId.toLong()) ?: return@let
val conversationParticipants = context.database.getConversationParticipants(conversationMessage.client_conversation_id.toString()) ?: return@let
val conversationParticipants = context.database.getConversationParticipants(conversationMessage.clientConversationId.toString()) ?: return@let
conversationParticipants.firstOrNull { it != conversationMessage.sender_id }
conversationParticipants.firstOrNull { it != conversationMessage.senderId }
}
val author = context.database.getFriendInfo(
@ -421,18 +421,18 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
val message = context.database.getConversationMessageFromId(messageId) ?: throw Exception("Message not found in database")
//get the message author
val friendInfo: FriendInfo = context.database.getFriendInfo(message.sender_id!!) ?: throw Exception("Friend not found in database")
val friendInfo: FriendInfo = context.database.getFriendInfo(message.senderId!!) ?: throw Exception("Friend not found in database")
val authorName = friendInfo.usernameForSorting!!
var messageContent = message.message_content!!
var messageContent = message.messageContent!!
var isArroyoMessage = true
var deletedMediaReference: ByteArray? = null
//check if the messageId
var contentType: ContentType = ContentType.fromId(message.content_type)
var contentType: ContentType = ContentType.fromId(message.contentType)
if (messageLogger.isMessageRemoved(message.client_message_id.toLong())) {
val messageObject = messageLogger.getMessageObject(message.client_conversation_id!!, message.client_message_id.toLong()) ?: throw Exception("Message not found in database")
if (messageLogger.isMessageRemoved(message.clientMessageId.toLong())) {
val messageObject = messageLogger.getMessageObject(message.clientConversationId!!, message.clientMessageId.toLong()) ?: throw Exception("Message not found in database")
isArroyoMessage = false
val messageContentObject = messageObject.getAsJsonObject("mMessageContent")
@ -474,7 +474,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
val encryptionKeys = EncryptionHelper.getEncryptionKeys(contentType, messageReader, isArroyo = isArroyoMessage)
provideDownloadManagerClient(
pathSuffix = authorName,
mediaIdentifier = "${message.client_conversation_id}${message.sender_id}${message.server_message_id}",
mediaIdentifier = "${message.clientConversationId}${message.senderId}${message.serverMessageId}",
mediaDisplaySource = authorName,
mediaDisplayType = MediaFilter.CHAT_MEDIA.key,
friendInfo = friendInfo

View File

@ -117,12 +117,12 @@ class FriendFeedInfoMenu : AbstractMenu() {
val messageBuilder = StringBuilder()
messages.forEach{ message: ConversationMessage ->
val sender: FriendInfo? = participants[message.sender_id]
val sender: FriendInfo? = participants[message.senderId]
var messageString: String = message.getMessageAsString() ?: ContentType.fromId(message.content_type).name
var messageString: String = message.getMessageAsString() ?: ContentType.fromId(message.contentType).name
if (message.content_type == ContentType.SNAP.id) {
val readTimeStamp: Long = message.read_timestamp
if (message.contentType == ContentType.SNAP.id) {
val readTimeStamp: Long = message.readTimestamp
messageString = "\uD83D\uDFE5" //red square
if (readTimeStamp > 0) {
messageString += " \uD83D\uDC40 " //eyes
@ -160,7 +160,7 @@ class FriendFeedInfoMenu : AbstractMenu() {
messages.lastOrNull()?.let {
messageBuilder
.append("\n\n")
.append(context.translation.format("conversation_preview.total_messages", "count" to it.server_message_id.toString()))
.append(context.translation.format("conversation_preview.total_messages", "count" to it.serverMessageId.toString()))
.append("\n")
}
@ -214,7 +214,7 @@ class FriendFeedInfoMenu : AbstractMenu() {
//old conversation fetch
val conversationId = if (messaging.lastFetchConversationUUID == null && focusedConversationTargetUser != null) {
val conversation: UserConversationLink = context.database.getDMConversationIdFromUserId(focusedConversationTargetUser) ?: throw IllegalStateException("No conversation found")
conversation.client_conversation_id!!.trim().lowercase()
conversation.clientConversationId!!.trim().lowercase()
} else {
messaging.lastFetchConversationUUID.toString()
}

View File

@ -12,6 +12,15 @@ fun Cursor.getIntOrNull(columnName: String): Int? {
return if (columnIndex == -1) null else getInt(columnIndex)
}
fun Cursor.getInteger(columnName: String) = getIntOrNull(columnName) ?: throw NullPointerException("Column $columnName is null")
fun Cursor.getLong(columnName: String) = getLongOrNull(columnName) ?: throw NullPointerException("Column $columnName is null")
fun Cursor.getBlobOrNull(columnName: String): ByteArray? {
val columnIndex = getColumnIndex(columnName)
return if (columnIndex == -1) null else getBlob(columnIndex)
}
fun Cursor.getLongOrNull(columnName: String): Long? {
val columnIndex = getColumnIndex(columnName)
return if (columnIndex == -1) null else getLong(columnIndex)