feat(ui): script list

- add module state
- add onSnapActivity and onManagerActivity test functions
This commit is contained in:
rhunk
2023-09-16 23:34:28 +02:00
parent 08614ef454
commit 6e0e6d3339
11 changed files with 314 additions and 62 deletions

View File

@ -3,9 +3,9 @@ package me.rhunk.snapenhance.bridge.scripting;
import me.rhunk.snapenhance.bridge.scripting.ReloadListener;
interface IScripting {
List<String> getEnabledScriptPaths();
List<String> getEnabledScripts();
String getScriptContent(String path);
@nullable String getScriptContent(String path);
void registerReloadListener(ReloadListener listener);
}

View File

@ -122,7 +122,7 @@ class SnapEnhance {
}
})
enabledScriptPaths.forEach { path ->
enabledScripts.forEach { path ->
runCatching {
scriptRuntime.load(path, getScriptContent(path))
}.onFailure {
@ -143,6 +143,7 @@ class SnapEnhance {
with(appContext) {
features.onActivityCreate()
actionManager.init()
scriptRuntime.eachModule { callOnSnapActivity(mainActivity!!) }
}
}.also { time ->
appContext.log.verbose("onActivityCreate took $time")

View File

@ -1,53 +1,72 @@
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.FunctionObject
import org.mozilla.javascript.ScriptableObject
import org.mozilla.javascript.Undefined
class JSModule(
val moduleInfo: ModuleInfo,
val content: String,
) {
lateinit var logger: AbstractLogger
private lateinit var scope: ScriptableObject
private lateinit var moduleObject: ScriptableObject
companion object {
@JvmStatic
fun logDebug(message: String) {
println(message)
fun load() {
contextScope {
moduleObject = initSafeStandardObjects()
moduleObject.putConst("module", moduleObject, buildScriptableObject {
putConst("info", this, buildScriptableObject {
putConst("name", this, moduleInfo.name)
putConst("version", this, moduleInfo.version)
putConst("description", this, moduleInfo.description)
putConst("author", this, moduleInfo.author)
putConst("minSnapchatVersion", this, moduleInfo.minSnapchatVersion)
putConst("minSEVersion", this, moduleInfo.minSEVersion)
putConst("grantPermissions", this, moduleInfo.grantPermissions)
})
})
moduleObject.putFunction("logInfo") { args ->
logger.info(args?.getOrNull(0)?.toString() ?: "null")
Undefined.instance
}
evaluateString(moduleObject, content, moduleInfo.name, 1, null)
}
}
fun load() {
val context = Context.enter()
context.optimizationLevel = -1
scope = context.initSafeStandardObjects()
scope.putConst("module", scope, moduleInfo)
scope.putConst("logDebug", scope,
FunctionObject("logDebug", JSModule::class.java.getDeclaredMethod("logDebug", String::class.java), scope)
)
context.evaluateString(scope, content, moduleInfo.name, 1, null)
}
fun unload() {
val context = Context.enter()
context.evaluateString(scope, "if (typeof module.onUnload === 'function') module.onUnload();", "onUnload", 1, null)
Context.exit()
contextScope {
moduleObject.scriptable("module")?.function("onUnload")?.call(
this,
moduleObject,
moduleObject,
null
)
}
}
fun callOnCoreLoad() {
val context = Context.enter()
context.evaluateString(scope, "if (typeof module.onCoreLoad === 'function') module.onCoreLoad();", "onCoreLoad", 1, null)
Context.exit()
fun callOnSnapActivity(activity: Activity) {
contextScope {
moduleObject.scriptable("module")?.function("onSnapActivity")?.call(
this,
moduleObject,
moduleObject,
arrayOf(activity)
)
}
}
fun callOnManagerLoad() {
val context = Context.enter()
context.evaluateString(scope, "if (typeof module.onManagerLoad === 'function') module.onManagerLoad();", "onManagerLoad", 1, null)
Context.exit()
fun callOnManagerLoad(activity: Activity) {
contextScope {
moduleObject.scriptable("module")?.function("onManagerActivity")?.call(
this,
moduleObject,
moduleObject,
arrayOf(activity)
)
}
}
}

View File

@ -0,0 +1,43 @@
package me.rhunk.snapenhance.scripting
import org.mozilla.javascript.Context
import org.mozilla.javascript.Function
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject
fun contextScope(f: Context.() -> Unit) {
val context = Context.enter()
context.optimizationLevel = -1
try {
context.f()
} finally {
Context.exit()
}
}
fun Scriptable.scriptable(name: String): Scriptable? {
return this.get(name, this) as? Scriptable
}
fun Scriptable.function(name: String): Function? {
return this.get(name, this) as? Function
}
fun ScriptableObject.putFunction(name: String, proxy: Scriptable.(Array<out Any>?) -> Any) {
this.putConst(name, this, object: org.mozilla.javascript.BaseFunction() {
override fun call(
cx: Context?,
scope: Scriptable,
thisObj: Scriptable,
args: Array<out Any>?
): Any {
return thisObj.proxy(args)
}
})
}
fun buildScriptableObject(name: String? = "ScriptableObject", f: ScriptableObject.() -> Unit): ScriptableObject {
return object: ScriptableObject() {
override fun getClassName() = name
}.apply(f)
}

View File

@ -4,12 +4,17 @@ import me.rhunk.snapenhance.core.logger.AbstractLogger
import me.rhunk.snapenhance.scripting.type.ModuleInfo
import java.io.BufferedReader
import java.io.ByteArrayInputStream
import java.io.InputStream
class ScriptRuntime(
private val logger: AbstractLogger,
) {
private val modules = mutableMapOf<String, JSModule>()
fun eachModule(f: JSModule.() -> Unit) {
modules.values.forEach(f)
}
private fun readModuleInfo(reader: BufferedReader): ModuleInfo {
val header = reader.readLine()
if (!header.startsWith("// ==SE_module==")) {
@ -40,6 +45,10 @@ class ScriptRuntime(
)
}
fun getModuleInfo(inputStream: InputStream): ModuleInfo {
return readModuleInfo(inputStream.bufferedReader())
}
fun reload(path: String, content: String) {
unload(path)
load(path, content)