commit 08cd7917f334c9e9ae9b92948af32fb645001eed
parent 6e0e6d33395d13bb006800f8e8e5ee16eedcdda3
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun, 17 Sep 2023 02:17:05 +0200

feat(scripting): ipc system

Diffstat:
Mapp/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt | 4++++
Aapp/src/main/kotlin/me/rhunk/snapenhance/scripting/IRemoteIPC.kt | 14++++++++++++++
Mapp/src/main/kotlin/me/rhunk/snapenhance/scripting/RemoteScriptManager.kt | 26+++++++++++++++++++++-----
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/MainActivity.kt | 4----
Acore/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IPCListener.aidl | 7+++++++
Mcore/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IScripting.aidl | 5+++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/SnapEnhance.kt | 17+++++++++++++++++
Acore/src/main/kotlin/me/rhunk/snapenhance/scripting/IPCInterface.kt | 9+++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/scripting/JSModule.kt | 10++++++----
Mcore/src/main/kotlin/me/rhunk/snapenhance/scripting/ScriptRuntime.kt | 6++++--
10 files changed, 87 insertions(+), 15 deletions(-)

diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt b/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt @@ -95,6 +95,10 @@ class RemoteSideContext( }.onFailure { log.error("Failed to load RemoteSideContext", it) } + + scriptManager.runtime.eachModule { + callOnManagerLoad(androidContext) + } } val installationSummary by lazy { diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/scripting/IRemoteIPC.kt b/app/src/main/kotlin/me/rhunk/snapenhance/scripting/IRemoteIPC.kt @@ -0,0 +1,13 @@ +package me.rhunk.snapenhance.scripting + +class IRemoteIPC : IPCInterface { + private val listeners = mutableMapOf<String, MutableSet<Listener>>() + + override fun on(eventName: String, listener: Listener) { + listeners.getOrPut(eventName) { mutableSetOf() }.add(listener) + } + + override fun emit(eventName: String, args: Array<out String?>) { + listeners[eventName]?.forEach { it(args) } + } +}+ \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/scripting/RemoteScriptManager.kt b/app/src/main/kotlin/me/rhunk/snapenhance/scripting/RemoteScriptManager.kt @@ -3,6 +3,7 @@ package me.rhunk.snapenhance.scripting import android.net.Uri import androidx.documentfile.provider.DocumentFile import me.rhunk.snapenhance.RemoteSideContext +import me.rhunk.snapenhance.bridge.scripting.IPCListener import me.rhunk.snapenhance.bridge.scripting.IScripting import me.rhunk.snapenhance.bridge.scripting.ReloadListener import me.rhunk.snapenhance.scripting.type.ModuleInfo @@ -11,7 +12,9 @@ import java.io.InputStream class RemoteScriptManager( private val context: RemoteSideContext, ) : IScripting.Stub() { - val runtime = ScriptRuntime(context.log) + val runtime = ScriptRuntime(context.log).apply { + ipcManager = IRemoteIPC() + } private fun getScriptFolder() = DocumentFile.fromTreeUri(context.androidContext, Uri.parse(context.config.root.scripting.moduleFolder.get())) @@ -38,7 +41,6 @@ class RemoteScriptManager( fun init() { sync() - enabledScripts.forEach { path -> val content = getScriptContent(path) ?: return@forEach runtime.load(path, content) @@ -55,9 +57,13 @@ class RemoteScriptManager( } override fun getEnabledScripts(): List<String> { - return getScriptFileNames().filter { - context.modDatabase.isScriptEnabled(cachedModuleInfo[it]?.name ?: return@filter false) - } + return runCatching { + getScriptFileNames().filter { + context.modDatabase.isScriptEnabled(cachedModuleInfo[it]?.name ?: return@filter false) + } + }.onFailure { + context.log.error("Failed to get enabled scripts", it) + }.getOrDefault(emptyList()) } override fun getScriptContent(name: String): String? { @@ -67,4 +73,14 @@ class RemoteScriptManager( override fun registerReloadListener(listener: ReloadListener) { reloadListeners.add(listener) } + + override fun registerIPCListener(eventName: String, listener: IPCListener) { + runtime.ipcManager.on(eventName) { args -> + listener.onMessage(args) + } + } + + override fun sendIPCMessage(eventName: String, args: Array<out String>) { + runtime.ipcManager.emit(eventName, args) + } } \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/MainActivity.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/MainActivity.kt @@ -46,10 +46,6 @@ class MainActivity : ComponentActivity() { checkForRequirements() } - managerContext.scriptManager.runtime.eachModule { - callOnManagerLoad(this@MainActivity) - } - sections = EnumSection.values().toList().associateWith { it.section.constructors.first().call() }.onEach { (section, instance) -> diff --git a/core/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IPCListener.aidl b/core/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IPCListener.aidl @@ -0,0 +1,6 @@ +package me.rhunk.snapenhance.bridge.scripting; + + +interface IPCListener { + void onMessage(in String[] args); +}+ \ No newline at end of file diff --git a/core/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IScripting.aidl b/core/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IScripting.aidl @@ -1,6 +1,7 @@ package me.rhunk.snapenhance.bridge.scripting; import me.rhunk.snapenhance.bridge.scripting.ReloadListener; +import me.rhunk.snapenhance.bridge.scripting.IPCListener; interface IScripting { List<String> getEnabledScripts(); @@ -8,4 +9,8 @@ interface IScripting { @nullable String getScriptContent(String path); void registerReloadListener(ReloadListener listener); + + void registerIPCListener(String eventName, IPCListener listener); + + void sendIPCMessage(String eventName, in String[] args); } \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/SnapEnhance.kt b/core/src/main/kotlin/me/rhunk/snapenhance/SnapEnhance.kt @@ -7,6 +7,7 @@ import android.content.pm.PackageManager import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import me.rhunk.snapenhance.bridge.SyncCallback +import me.rhunk.snapenhance.bridge.scripting.IPCListener import me.rhunk.snapenhance.bridge.scripting.ReloadListener import me.rhunk.snapenhance.core.BuildConfig import me.rhunk.snapenhance.core.Logger @@ -20,6 +21,8 @@ import me.rhunk.snapenhance.data.SnapClassCache import me.rhunk.snapenhance.hook.HookStage import me.rhunk.snapenhance.hook.Hooker import me.rhunk.snapenhance.hook.hook +import me.rhunk.snapenhance.scripting.IPCInterface +import me.rhunk.snapenhance.scripting.Listener import kotlin.time.ExperimentalTime import kotlin.time.measureTime @@ -122,6 +125,20 @@ class SnapEnhance { } }) + scriptRuntime.ipcManager = object: IPCInterface { + override fun on(eventName: String, listener: Listener) { + registerIPCListener(eventName, object: IPCListener.Stub() { + override fun onMessage(args: Array<out String?>) { + listener(args) + } + }) + } + + override fun emit(eventName: String, args: Array<out String?>) { + sendIPCMessage(eventName, args) + } + } + enabledScripts.forEach { path -> runCatching { scriptRuntime.load(path, getScriptContent(path)) diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/scripting/IPCInterface.kt b/core/src/main/kotlin/me/rhunk/snapenhance/scripting/IPCInterface.kt @@ -0,0 +1,8 @@ +package me.rhunk.snapenhance.scripting + +typealias Listener = (Array<out String?>) -> Unit + +interface IPCInterface { + fun on(eventName: String, listener: Listener) + fun emit(eventName: String, args: Array<out String?>) +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/scripting/JSModule.kt b/core/src/main/kotlin/me/rhunk/snapenhance/scripting/JSModule.kt @@ -3,6 +3,7 @@ package me.rhunk.snapenhance.scripting import android.app.Activity import me.rhunk.snapenhance.core.logger.AbstractLogger import me.rhunk.snapenhance.scripting.type.ModuleInfo +import org.mozilla.javascript.Context import org.mozilla.javascript.ScriptableObject import org.mozilla.javascript.Undefined @@ -13,7 +14,7 @@ class JSModule( lateinit var logger: AbstractLogger private lateinit var moduleObject: ScriptableObject - fun load() { + fun load(block: Context.(ScriptableObject) -> Unit) { contextScope { moduleObject = initSafeStandardObjects() moduleObject.putConst("module", moduleObject, buildScriptableObject { @@ -33,6 +34,7 @@ class JSModule( Undefined.instance } + block(this, moduleObject) evaluateString(moduleObject, content, moduleInfo.name, 1, null) } } @@ -59,13 +61,13 @@ class JSModule( } } - fun callOnManagerLoad(activity: Activity) { + fun callOnManagerLoad(context: android.content.Context) { contextScope { - moduleObject.scriptable("module")?.function("onManagerActivity")?.call( + moduleObject.scriptable("module")?.function("onManagerLoad")?.call( this, moduleObject, moduleObject, - arrayOf(activity) + arrayOf(context) ) } } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/scripting/ScriptRuntime.kt b/core/src/main/kotlin/me/rhunk/snapenhance/scripting/ScriptRuntime.kt @@ -9,6 +9,7 @@ import java.io.InputStream class ScriptRuntime( private val logger: AbstractLogger, ) { + lateinit var ipcManager: IPCInterface private val modules = mutableMapOf<String, JSModule>() fun eachModule(f: JSModule.() -> Unit) { @@ -57,7 +58,6 @@ class ScriptRuntime( private fun unload(path: String) { val module = modules[path] ?: return module.unload() - module.load() modules.remove(path) } @@ -69,7 +69,9 @@ class ScriptRuntime( content = content, ).apply { logger = this@ScriptRuntime.logger - load() + load { + it.putConst("ipc", it, ipcManager) + } modules[path] = this } }.onFailure {