refactor: lazy bridge references

This commit is contained in:
rhunk 2024-06-01 23:29:13 +02:00
parent 91b690b01d
commit b4879c9a7f
14 changed files with 115 additions and 53 deletions

View File

@ -28,6 +28,7 @@ import me.rhunk.snapenhance.common.bridge.wrapper.LoggerWrapper
import me.rhunk.snapenhance.common.bridge.wrapper.MappingsWrapper import me.rhunk.snapenhance.common.bridge.wrapper.MappingsWrapper
import me.rhunk.snapenhance.common.config.ModConfig import me.rhunk.snapenhance.common.config.ModConfig
import me.rhunk.snapenhance.common.logger.fatalCrash import me.rhunk.snapenhance.common.logger.fatalCrash
import me.rhunk.snapenhance.common.util.constantLazyBridge
import me.rhunk.snapenhance.common.util.getPurgeTime import me.rhunk.snapenhance.common.util.getPurgeTime
import me.rhunk.snapenhance.e2ee.E2EEImplementation import me.rhunk.snapenhance.e2ee.E2EEImplementation
import me.rhunk.snapenhance.scripting.RemoteScriptManager import me.rhunk.snapenhance.scripting.RemoteScriptManager
@ -61,9 +62,9 @@ class RemoteSideContext(
val sharedPreferences: SharedPreferences get() = androidContext.getSharedPreferences("prefs", 0) val sharedPreferences: SharedPreferences get() = androidContext.getSharedPreferences("prefs", 0)
val fileHandleManager = RemoteFileHandleManager(this) val fileHandleManager = RemoteFileHandleManager(this)
val config = ModConfig(androidContext, fileHandleManager) val config = ModConfig(androidContext, constantLazyBridge { fileHandleManager })
val translation = LocaleWrapper(fileHandleManager) val translation = LocaleWrapper(constantLazyBridge { fileHandleManager })
val mappings = MappingsWrapper(fileHandleManager) val mappings = MappingsWrapper(constantLazyBridge { fileHandleManager })
val taskManager = TaskManager(this) val taskManager = TaskManager(this)
val database = AppDatabase(this) val database = AppDatabase(this)
val streaksReminder = StreaksReminder(this) val streaksReminder = StreaksReminder(this)

View File

@ -5,6 +5,8 @@ import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.AutoCloseInputStream import android.os.ParcelFileDescriptor.AutoCloseInputStream
import android.os.ParcelFileDescriptor.AutoCloseOutputStream import android.os.ParcelFileDescriptor.AutoCloseOutputStream
import me.rhunk.snapenhance.bridge.storage.FileHandle import me.rhunk.snapenhance.bridge.storage.FileHandle
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import me.rhunk.snapenhance.common.util.lazyBridge
import java.io.File import java.io.File
@ -43,10 +45,10 @@ enum class InternalFileHandleType(
} }
} }
fun FileHandle.toWrapper() = FileHandleWrapper(lazy { this }) fun FileHandle.toWrapper() = FileHandleWrapper(lazyBridge { this })
open class FileHandleWrapper( open class FileHandleWrapper(
private val fileHandle: Lazy<FileHandle> private val fileHandle: LazyBridgeValue<FileHandle>
) { ) {
fun exists() = fileHandle.value.exists() fun exists() = fileHandle.value.exists()
fun create() = fileHandle.value.create() fun create() = fileHandle.value.create()

View File

@ -1,12 +1,14 @@
package me.rhunk.snapenhance.common.bridge package me.rhunk.snapenhance.common.bridge
import me.rhunk.snapenhance.bridge.storage.FileHandleManager import me.rhunk.snapenhance.bridge.storage.FileHandleManager
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import me.rhunk.snapenhance.common.util.lazyBridge
open class InternalFileWrapper( open class InternalFileWrapper(
fileHandleManager: FileHandleManager, fileHandleManager: LazyBridgeValue<FileHandleManager>,
private val fileType: InternalFileHandleType, private val fileType: InternalFileHandleType,
val defaultValue: String? = null val defaultValue: String? = null
): FileHandleWrapper(lazy { fileHandleManager.getFileHandle(FileHandleScope.INTERNAL.key, fileType.key)!! }) { ): FileHandleWrapper(lazyBridge { fileHandleManager.value.getFileHandle(FileHandleScope.INTERNAL.key, fileType.key)!! }) {
override fun readBytes(): ByteArray { override fun readBytes(): ByteArray {
if (!exists()) { if (!exists()) {
defaultValue?.toByteArray(Charsets.UTF_8)?.let { defaultValue?.toByteArray(Charsets.UTF_8)?.let {

View File

@ -8,11 +8,12 @@ import com.google.gson.JsonParser
import me.rhunk.snapenhance.bridge.storage.FileHandleManager import me.rhunk.snapenhance.bridge.storage.FileHandleManager
import me.rhunk.snapenhance.common.bridge.FileHandleScope import me.rhunk.snapenhance.common.bridge.FileHandleScope
import me.rhunk.snapenhance.common.logger.AbstractLogger import me.rhunk.snapenhance.common.logger.AbstractLogger
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import java.util.Locale import java.util.Locale
class LocaleWrapper( class LocaleWrapper(
private val fileHandleManager: FileHandleManager private val fileHandleManager: LazyBridgeValue<FileHandleManager>
) { ) {
companion object { companion object {
const val DEFAULT_LOCALE = "en_US" const val DEFAULT_LOCALE = "en_US"
@ -62,15 +63,14 @@ class LocaleWrapper(
} }
fun load() { fun load() {
load( fileHandleManager.value.getFileHandle(FileHandleScope.LOCALE.key, "$DEFAULT_LOCALE.json")?.open(ParcelFileDescriptor.MODE_READ_ONLY)?.use {
DEFAULT_LOCALE, load(DEFAULT_LOCALE, it)
fileHandleManager.getFileHandle(FileHandleScope.LOCALE.key, "$DEFAULT_LOCALE.json")?.open(ParcelFileDescriptor.MODE_READ_ONLY) ?: run { } ?: run {
throw IllegalStateException("Failed to load default locale") throw IllegalStateException("Failed to load default locale")
} }
)
if (userLocale != DEFAULT_LOCALE) { if (userLocale != DEFAULT_LOCALE) {
fileHandleManager.getFileHandle(FileHandleScope.LOCALE.key, "$userLocale.json")?.open(ParcelFileDescriptor.MODE_READ_ONLY)?.let { fileHandleManager.value.getFileHandle(FileHandleScope.LOCALE.key, "$userLocale.json")?.open(ParcelFileDescriptor.MODE_READ_ONLY)?.use {
load(userLocale, it) load(userLocale, it)
} }
} }

View File

@ -9,12 +9,13 @@ import me.rhunk.snapenhance.common.Constants
import me.rhunk.snapenhance.common.bridge.InternalFileHandleType import me.rhunk.snapenhance.common.bridge.InternalFileHandleType
import me.rhunk.snapenhance.common.bridge.InternalFileWrapper import me.rhunk.snapenhance.common.bridge.InternalFileWrapper
import me.rhunk.snapenhance.common.logger.AbstractLogger import me.rhunk.snapenhance.common.logger.AbstractLogger
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import me.rhunk.snapenhance.mapper.AbstractClassMapper import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.ClassMapper import me.rhunk.snapenhance.mapper.ClassMapper
import kotlin.reflect.KClass import kotlin.reflect.KClass
class MappingsWrapper( class MappingsWrapper(
fileHandleManager: FileHandleManager fileHandleManager: LazyBridgeValue<FileHandleManager>
): InternalFileWrapper(fileHandleManager, InternalFileHandleType.MAPPINGS, defaultValue = "{}") { ): InternalFileWrapper(fileHandleManager, InternalFileHandleType.MAPPINGS, defaultValue = "{}") {
private lateinit var context: Context private lateinit var context: Context
private var mappingUniqueHash: Long = 0 private var mappingUniqueHash: Long = 0

View File

@ -11,11 +11,12 @@ import me.rhunk.snapenhance.common.bridge.InternalFileWrapper
import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper
import me.rhunk.snapenhance.common.config.impl.RootConfig import me.rhunk.snapenhance.common.config.impl.RootConfig
import me.rhunk.snapenhance.common.logger.AbstractLogger import me.rhunk.snapenhance.common.logger.AbstractLogger
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import kotlin.properties.Delegates import kotlin.properties.Delegates
class ModConfig( class ModConfig(
private val context: Context, private val context: Context,
fileHandleManager: FileHandleManager fileHandleManager: LazyBridgeValue<FileHandleManager>
) { ) {
private val fileWrapper = InternalFileWrapper(fileHandleManager, InternalFileHandleType.CONFIG, "{}") private val fileWrapper = InternalFileWrapper(fileHandleManager, InternalFileHandleType.CONFIG, "{}")
var locale: String = LocaleWrapper.DEFAULT_LOCALE var locale: String = LocaleWrapper.DEFAULT_LOCALE

View File

@ -0,0 +1,49 @@
package me.rhunk.snapenhance.common.util
import android.os.IInterface
open class LazyBridgeValue<T: IInterface>(
private val block: () -> T,
private val isConstant: Boolean = false
): Lazy<T> {
private val lock = Any()
private var _value: T? = null
override val value: T get() = run {
synchronized(lock) {
if (_value == null || (!isConstant && !_value!!.asBinder().pingBinder())) {
_value = block()
}
}
return _value!!
}
override fun isInitialized(): Boolean {
return _value != null && (isConstant || _value!!.asBinder().pingBinder())
}
operator fun getValue(thisRef: Any?, property: Any?): T {
return value
}
}
fun <T : IInterface, R> mappedLazyBridge(lazyBridgeValue: LazyBridgeValue<T>, map: (T) -> R): Lazy<R> {
return object : Lazy<R> {
private var _value: T? = null
private var _mappedValue: R? = null
override val value: R get() = run {
if (_value != lazyBridgeValue.value) {
_value = lazyBridgeValue.value
_mappedValue = map(_value!!)
}
return _mappedValue!!
}
override fun isInitialized(): Boolean = lazyBridgeValue.isInitialized()
}
}
fun <T: IInterface> lazyBridge(block: () -> T) = LazyBridgeValue(block)
fun <T: IInterface> constantLazyBridge(value: () -> T) = LazyBridgeValue(value, isConstant = true)

View File

@ -17,6 +17,7 @@ import me.rhunk.snapenhance.common.Constants
import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper
import me.rhunk.snapenhance.common.bridge.wrapper.MappingsWrapper import me.rhunk.snapenhance.common.bridge.wrapper.MappingsWrapper
import me.rhunk.snapenhance.common.config.ModConfig import me.rhunk.snapenhance.common.config.ModConfig
import me.rhunk.snapenhance.common.util.lazyBridge
import me.rhunk.snapenhance.core.action.ActionManager import me.rhunk.snapenhance.core.action.ActionManager
import me.rhunk.snapenhance.core.bridge.BridgeClient import me.rhunk.snapenhance.core.bridge.BridgeClient
import me.rhunk.snapenhance.core.database.DatabaseAccess import me.rhunk.snapenhance.core.database.DatabaseAccess
@ -48,15 +49,18 @@ class ModContext(
val resources: Resources get() = androidContext.resources val resources: Resources get() = androidContext.resources
val gson: Gson = GsonBuilder().create() val gson: Gson = GsonBuilder().create()
private val _config by lazy { ModConfig(androidContext, bridgeClient.getFileHandlerManager()) } private val lazyFileHandlerManager = lazyBridge { bridgeClient.getFileHandlerManager() }
val fileHandlerManager by lazyFileHandlerManager
private val _config by lazy { ModConfig(androidContext, lazyFileHandlerManager) }
val config get() = _config.root val config get() = _config.root
val log by lazy { CoreLogger(this.bridgeClient) } val log by lazy { CoreLogger(this.bridgeClient) }
val translation by lazy { LocaleWrapper(bridgeClient.getFileHandlerManager()) } val translation by lazy { LocaleWrapper(lazyFileHandlerManager) }
val httpServer = HttpServer() val httpServer = HttpServer()
val messageSender = MessageSender(this) val messageSender = MessageSender(this)
val features = FeatureManager(this) val features = FeatureManager(this)
val mappings by lazy { MappingsWrapper(bridgeClient.getFileHandlerManager()) } val mappings by lazy { MappingsWrapper(lazyFileHandlerManager) }
val actionManager = ActionManager(this) val actionManager = ActionManager(this)
val database = DatabaseAccess(this) val database = DatabaseAccess(this)
val event = EventBus(this) val event = EventBus(this)

View File

@ -5,23 +5,15 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.Build import android.os.*
import android.os.DeadObjectException
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import android.os.ParcelFileDescriptor
import android.os.Process
import android.util.Log import android.util.Log
import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.XposedHelpers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withTimeoutOrNull import kotlinx.coroutines.withTimeoutOrNull
import me.rhunk.snapenhance.bridge.AccountStorage import me.rhunk.snapenhance.bridge.*
import me.rhunk.snapenhance.bridge.BridgeInterface
import me.rhunk.snapenhance.bridge.ConfigStateListener
import me.rhunk.snapenhance.bridge.DownloadCallback
import me.rhunk.snapenhance.bridge.SyncCallback
import me.rhunk.snapenhance.bridge.e2ee.E2eeInterface import me.rhunk.snapenhance.bridge.e2ee.E2eeInterface
import me.rhunk.snapenhance.bridge.logger.LoggerInterface import me.rhunk.snapenhance.bridge.logger.LoggerInterface
import me.rhunk.snapenhance.bridge.logger.TrackerInterface import me.rhunk.snapenhance.bridge.logger.TrackerInterface
@ -58,7 +50,7 @@ class BridgeClient(
return true return true
} }
return withTimeoutOrNull(5000L) { return withTimeoutOrNull(10000L) {
suspendCancellableCoroutine { cancellableContinuation -> suspendCancellableCoroutine { cancellableContinuation ->
continuation = cancellableContinuation continuation = cancellableContinuation
with(context.androidContext) { with(context.androidContext) {
@ -133,19 +125,24 @@ class BridgeClient(
continuation = null continuation = null
} }
private val reconnectSemaphore = Semaphore(permits = 1)
private fun tryReconnect() { private fun tryReconnect() {
runBlocking { runBlocking {
reconnectSemaphore.withPermit {
if (service.asBinder().pingBinder()) return@runBlocking
Log.d("BridgeClient", "service is dead, restarting") Log.d("BridgeClient", "service is dead, restarting")
val canLoad = connect { val canLoad = connect {
Log.e("BridgeClient", "connection failed", it) Log.e("BridgeClient", "connection failed", it)
context.softRestartApp() context.softRestartApp()
} }
if (canLoad != true) { if (canLoad != true) {
Log.e("BridgeClient", "failed to reconnect to service", Throwable()) Log.e("BridgeClient", "failed to reconnect to service, result=$canLoad")
context.softRestartApp() context.softRestartApp()
} }
} }
} }
}
private fun <T> safeServiceCall(block: () -> T): T { private fun <T> safeServiceCall(block: () -> T): T {
return runCatching { return runCatching {

View File

@ -3,15 +3,17 @@ package me.rhunk.snapenhance.core.features
import me.rhunk.snapenhance.common.bridge.FileHandleScope import me.rhunk.snapenhance.common.bridge.FileHandleScope
import me.rhunk.snapenhance.common.bridge.InternalFileHandleType import me.rhunk.snapenhance.common.bridge.InternalFileHandleType
import me.rhunk.snapenhance.common.bridge.toWrapper import me.rhunk.snapenhance.common.bridge.toWrapper
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import me.rhunk.snapenhance.common.util.mappedLazyBridge
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
abstract class BridgeFileFeature(name: String, private val bridgeFileType: InternalFileHandleType, loadParams: Int) : Feature(name, loadParams) { abstract class BridgeFileFeature(name: String, private val bridgeFileType: InternalFileHandleType, loadParams: Int) : Feature(name, loadParams) {
private val fileLines = mutableListOf<String>() private val fileLines = mutableListOf<String>()
private val fileWrapper by lazy { context.bridgeClient.getFileHandlerManager().getFileHandle(FileHandleScope.INTERNAL.key, bridgeFileType.key)!!.toWrapper() } private val fileWrapper by mappedLazyBridge(LazyBridgeValue({ context.fileHandlerManager.getFileHandle(FileHandleScope.INTERNAL.key, bridgeFileType.key)!! }), map = { it.toWrapper() })
protected fun readFile() { private fun readFile() {
val temporaryLines = mutableListOf<String>() val temporaryLines = mutableListOf<String>()
fileWrapper.inputStream { stream -> fileWrapper.inputStream { stream ->
with(BufferedReader(InputStreamReader(stream, StandardCharsets.UTF_8))) { with(BufferedReader(InputStreamReader(stream, StandardCharsets.UTF_8))) {

View File

@ -13,7 +13,7 @@ fun getCustomEmojiFontPath(
val customFileName = context.config.experimental.nativeHooks.customEmojiFont.getNullable()?.takeIf { it.isNotBlank() } ?: return null val customFileName = context.config.experimental.nativeHooks.customEmojiFont.getNullable()?.takeIf { it.isNotBlank() } ?: return null
if (cacheFontPath == null) { if (cacheFontPath == null) {
cacheFontPath = runCatching { cacheFontPath = runCatching {
context.bridgeClient.getFileHandlerManager().getFileHandleLocalPath( context.fileHandlerManager.getFileHandleLocalPath(
context, context,
FileHandleScope.USER_IMPORT, FileHandleScope.USER_IMPORT,
customFileName, customFileName,

View File

@ -25,6 +25,7 @@ import me.rhunk.snapenhance.common.data.MessagingRuleType
import me.rhunk.snapenhance.common.data.RuleState import me.rhunk.snapenhance.common.data.RuleState
import me.rhunk.snapenhance.common.database.impl.ConversationMessage import me.rhunk.snapenhance.common.database.impl.ConversationMessage
import me.rhunk.snapenhance.common.ui.createComposeView import me.rhunk.snapenhance.common.ui.createComposeView
import me.rhunk.snapenhance.common.util.lazyBridge
import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
import me.rhunk.snapenhance.common.util.protobuf.ProtoWriter import me.rhunk.snapenhance.common.util.protobuf.ProtoWriter
@ -58,7 +59,7 @@ class EndToEndEncryption : MessagingRuleFeature(
loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC or FeatureLoadParams.INIT_SYNC or FeatureLoadParams.INIT_ASYNC loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC or FeatureLoadParams.INIT_SYNC or FeatureLoadParams.INIT_ASYNC
) { ) {
val isEnabled get() = context.config.experimental.e2eEncryption.globalState == true val isEnabled get() = context.config.experimental.e2eEncryption.globalState == true
private val e2eeInterface by lazy { context.bridgeClient.getE2eeInterface() } private val e2eeInterface by lazyBridge { context.bridgeClient.getE2eeInterface() }
private val translation by lazy { context.translation.getCategory("end_to_end_encryption") } private val translation by lazy { context.translation.getCategory("end_to_end_encryption") }

View File

@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Info
import me.rhunk.snapenhance.common.Constants import me.rhunk.snapenhance.common.Constants
import me.rhunk.snapenhance.common.data.* import me.rhunk.snapenhance.common.data.*
import me.rhunk.snapenhance.common.util.lazyBridge
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
import me.rhunk.snapenhance.common.util.toParcelable import me.rhunk.snapenhance.common.util.toParcelable
import me.rhunk.snapenhance.core.features.Feature import me.rhunk.snapenhance.core.features.Feature
@ -24,7 +25,7 @@ import java.nio.ByteBuffer
class FriendTracker : Feature("Friend Tracker", loadParams = FeatureLoadParams.INIT_SYNC) { class FriendTracker : Feature("Friend Tracker", loadParams = FeatureLoadParams.INIT_SYNC) {
private val conversationPresenceState = mutableMapOf<String, MutableMap<String, FriendPresenceState?>>() // conversationId -> (userId -> state) private val conversationPresenceState = mutableMapOf<String, MutableMap<String, FriendPresenceState?>>() // conversationId -> (userId -> state)
private val tracker by lazy { context.bridgeClient.getTracker() } private val tracker by lazyBridge { context.bridgeClient.getTracker() }
private val notificationManager by lazy { context.androidContext.getSystemService(NotificationManager::class.java).apply { private val notificationManager by lazy { context.androidContext.getSystemService(NotificationManager::class.java).apply {
createNotificationChannel(NotificationChannel( createNotificationChannel(NotificationChannel(
"friend_tracker", "friend_tracker",

View File

@ -11,6 +11,7 @@ import me.rhunk.snapenhance.common.data.ContentType
import me.rhunk.snapenhance.common.data.MessageState import me.rhunk.snapenhance.common.data.MessageState
import me.rhunk.snapenhance.common.data.QuotedMessageContentStatus import me.rhunk.snapenhance.common.data.QuotedMessageContentStatus
import me.rhunk.snapenhance.common.util.ktx.longHashCode import me.rhunk.snapenhance.common.util.ktx.longHashCode
import me.rhunk.snapenhance.common.util.lazyBridge
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent
import me.rhunk.snapenhance.core.event.events.impl.BuildMessageEvent import me.rhunk.snapenhance.core.event.events.impl.BuildMessageEvent
@ -33,7 +34,7 @@ class MessageLogger : Feature("MessageLogger",
const val DELETED_MESSAGE_COLOR = 0x6Eb71c1c const val DELETED_MESSAGE_COLOR = 0x6Eb71c1c
} }
private val loggerInterface by lazy { context.bridgeClient.getMessageLogger() } private val loggerInterface by lazyBridge { context.bridgeClient.getMessageLogger() }
val isEnabled get() = context.config.messaging.messageLogger.globalState == true val isEnabled get() = context.config.messaging.messageLogger.globalState == true