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.config.ModConfig
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.e2ee.E2EEImplementation
import me.rhunk.snapenhance.scripting.RemoteScriptManager
@ -61,9 +62,9 @@ class RemoteSideContext(
val sharedPreferences: SharedPreferences get() = androidContext.getSharedPreferences("prefs", 0)
val fileHandleManager = RemoteFileHandleManager(this)
val config = ModConfig(androidContext, fileHandleManager)
val translation = LocaleWrapper(fileHandleManager)
val mappings = MappingsWrapper(fileHandleManager)
val config = ModConfig(androidContext, constantLazyBridge { fileHandleManager })
val translation = LocaleWrapper(constantLazyBridge { fileHandleManager })
val mappings = MappingsWrapper(constantLazyBridge { fileHandleManager })
val taskManager = TaskManager(this)
val database = AppDatabase(this)
val streaksReminder = StreaksReminder(this)

View File

@ -5,6 +5,8 @@ import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.AutoCloseInputStream
import android.os.ParcelFileDescriptor.AutoCloseOutputStream
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
@ -43,10 +45,10 @@ enum class InternalFileHandleType(
}
}
fun FileHandle.toWrapper() = FileHandleWrapper(lazy { this })
fun FileHandle.toWrapper() = FileHandleWrapper(lazyBridge { this })
open class FileHandleWrapper(
private val fileHandle: Lazy<FileHandle>
private val fileHandle: LazyBridgeValue<FileHandle>
) {
fun exists() = fileHandle.value.exists()
fun create() = fileHandle.value.create()

View File

@ -1,12 +1,14 @@
package me.rhunk.snapenhance.common.bridge
import me.rhunk.snapenhance.bridge.storage.FileHandleManager
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import me.rhunk.snapenhance.common.util.lazyBridge
open class InternalFileWrapper(
fileHandleManager: FileHandleManager,
fileHandleManager: LazyBridgeValue<FileHandleManager>,
private val fileType: InternalFileHandleType,
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 {
if (!exists()) {
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.common.bridge.FileHandleScope
import me.rhunk.snapenhance.common.logger.AbstractLogger
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import java.util.Locale
class LocaleWrapper(
private val fileHandleManager: FileHandleManager
private val fileHandleManager: LazyBridgeValue<FileHandleManager>
) {
companion object {
const val DEFAULT_LOCALE = "en_US"
@ -62,15 +63,14 @@ class LocaleWrapper(
}
fun load() {
load(
DEFAULT_LOCALE,
fileHandleManager.getFileHandle(FileHandleScope.LOCALE.key, "$DEFAULT_LOCALE.json")?.open(ParcelFileDescriptor.MODE_READ_ONLY) ?: run {
fileHandleManager.value.getFileHandle(FileHandleScope.LOCALE.key, "$DEFAULT_LOCALE.json")?.open(ParcelFileDescriptor.MODE_READ_ONLY)?.use {
load(DEFAULT_LOCALE, it)
} ?: run {
throw IllegalStateException("Failed to load 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)
}
}

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.InternalFileWrapper
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.ClassMapper
import kotlin.reflect.KClass
class MappingsWrapper(
fileHandleManager: FileHandleManager
fileHandleManager: LazyBridgeValue<FileHandleManager>
): InternalFileWrapper(fileHandleManager, InternalFileHandleType.MAPPINGS, defaultValue = "{}") {
private lateinit var context: Context
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.config.impl.RootConfig
import me.rhunk.snapenhance.common.logger.AbstractLogger
import me.rhunk.snapenhance.common.util.LazyBridgeValue
import kotlin.properties.Delegates
class ModConfig(
private val context: Context,
fileHandleManager: FileHandleManager
fileHandleManager: LazyBridgeValue<FileHandleManager>
) {
private val fileWrapper = InternalFileWrapper(fileHandleManager, InternalFileHandleType.CONFIG, "{}")
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.MappingsWrapper
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.bridge.BridgeClient
import me.rhunk.snapenhance.core.database.DatabaseAccess
@ -48,15 +49,18 @@ class ModContext(
val resources: Resources get() = androidContext.resources
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 log by lazy { CoreLogger(this.bridgeClient) }
val translation by lazy { LocaleWrapper(bridgeClient.getFileHandlerManager()) }
val translation by lazy { LocaleWrapper(lazyFileHandlerManager) }
val httpServer = HttpServer()
val messageSender = MessageSender(this)
val features = FeatureManager(this)
val mappings by lazy { MappingsWrapper(bridgeClient.getFileHandlerManager()) }
val mappings by lazy { MappingsWrapper(lazyFileHandlerManager) }
val actionManager = ActionManager(this)
val database = DatabaseAccess(this)
val event = EventBus(this)

View File

@ -5,23 +5,15 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Build
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.os.*
import android.util.Log
import de.robv.android.xposed.XposedHelpers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withTimeoutOrNull
import me.rhunk.snapenhance.bridge.AccountStorage
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.*
import me.rhunk.snapenhance.bridge.e2ee.E2eeInterface
import me.rhunk.snapenhance.bridge.logger.LoggerInterface
import me.rhunk.snapenhance.bridge.logger.TrackerInterface
@ -58,7 +50,7 @@ class BridgeClient(
return true
}
return withTimeoutOrNull(5000L) {
return withTimeoutOrNull(10000L) {
suspendCancellableCoroutine { cancellableContinuation ->
continuation = cancellableContinuation
with(context.androidContext) {
@ -133,19 +125,24 @@ class BridgeClient(
continuation = null
}
private val reconnectSemaphore = Semaphore(permits = 1)
private fun tryReconnect() {
runBlocking {
reconnectSemaphore.withPermit {
if (service.asBinder().pingBinder()) return@runBlocking
Log.d("BridgeClient", "service is dead, restarting")
val canLoad = connect {
Log.e("BridgeClient", "connection failed", it)
context.softRestartApp()
}
if (canLoad != true) {
Log.e("BridgeClient", "failed to reconnect to service", Throwable())
Log.e("BridgeClient", "failed to reconnect to service, result=$canLoad")
context.softRestartApp()
}
}
}
}
private fun <T> safeServiceCall(block: () -> T): T {
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.InternalFileHandleType
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.InputStreamReader
import java.nio.charset.StandardCharsets
abstract class BridgeFileFeature(name: String, private val bridgeFileType: InternalFileHandleType, loadParams: Int) : Feature(name, loadParams) {
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>()
fileWrapper.inputStream { stream ->
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
if (cacheFontPath == null) {
cacheFontPath = runCatching {
context.bridgeClient.getFileHandlerManager().getFileHandleLocalPath(
context.fileHandlerManager.getFileHandleLocalPath(
context,
FileHandleScope.USER_IMPORT,
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.database.impl.ConversationMessage
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.ProtoReader
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
) {
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") }

View File

@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import me.rhunk.snapenhance.common.Constants
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.toParcelable
import me.rhunk.snapenhance.core.features.Feature
@ -24,7 +25,7 @@ import java.nio.ByteBuffer
class FriendTracker : Feature("Friend Tracker", loadParams = FeatureLoadParams.INIT_SYNC) {
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 {
createNotificationChannel(NotificationChannel(
"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.QuotedMessageContentStatus
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.core.event.events.impl.BindViewEvent
import me.rhunk.snapenhance.core.event.events.impl.BuildMessageEvent
@ -33,7 +34,7 @@ class MessageLogger : Feature("MessageLogger",
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