commit b92589fa07c6a6fc496433d0e090bc2375ce8277 parent baf872791246cd3b3fe9ca3da39082f2c72b047d Author: rhunk <101876869+rhunk@users.noreply.github.com> Date: Sat, 14 Oct 2023 12:14:30 +0200 feat(scripting): config interface - change onLaunched to onDispose - refactor JSModule extras Diffstat:
16 files changed, 324 insertions(+), 88 deletions(-)
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt b/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt @@ -14,6 +14,8 @@ import coil.ImageLoader import coil.decode.VideoFrameDecoder import coil.disk.DiskCache import coil.memory.MemoryCache +import com.google.gson.Gson +import com.google.gson.GsonBuilder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import me.rhunk.snapenhance.bridge.BridgeService @@ -81,6 +83,8 @@ class RemoteSideContext( .components { add(VideoFrameDecoder.Factory()) }.build() } + val gson: Gson by lazy { GsonBuilder().setPrettyPrinting().create() } + fun reload() { log.verbose("Loading RemoteSideContext") runCatching { diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/scripting/RemoteScriptManager.kt b/app/src/main/kotlin/me/rhunk/snapenhance/scripting/RemoteScriptManager.kt @@ -6,18 +6,20 @@ import me.rhunk.snapenhance.RemoteSideContext import me.rhunk.snapenhance.bridge.scripting.IPCListener import me.rhunk.snapenhance.bridge.scripting.IScripting import me.rhunk.snapenhance.common.scripting.ScriptRuntime +import me.rhunk.snapenhance.common.scripting.impl.ConfigInterface +import me.rhunk.snapenhance.common.scripting.impl.ConfigTransactionType import me.rhunk.snapenhance.common.scripting.type.ModuleInfo import me.rhunk.snapenhance.scripting.impl.IPCListeners import me.rhunk.snapenhance.scripting.impl.RemoteManagerIPC -import me.rhunk.snapenhance.scripting.impl.ui.InterfaceBuilder +import me.rhunk.snapenhance.scripting.impl.RemoteScriptConfig import me.rhunk.snapenhance.scripting.impl.ui.InterfaceManager +import java.io.File import java.io.InputStream class RemoteScriptManager( - private val context: RemoteSideContext, + val context: RemoteSideContext, ) : IScripting.Stub() { val runtime = ScriptRuntime(context.androidContext, context.log) - private val userInterfaces = mutableMapOf<String, MutableMap<String, InterfaceBuilder>>() private val cachedModuleInfo = mutableMapOf<String, ModuleInfo>() private val ipcListeners = IPCListeners() @@ -40,19 +42,15 @@ class RemoteScriptManager( fun init() { runtime.buildModuleObject = { module -> - putConst("ipc", this, RemoteManagerIPC(module.moduleInfo, context.log, ipcListeners)) - putConst("im", this, InterfaceManager(module.moduleInfo, context.log) { name, interfaceBuilder -> - userInterfaces.getOrPut(module.moduleInfo.name) { - mutableMapOf() - }[name] = interfaceBuilder - }) + module.extras["ipc"] = RemoteManagerIPC(module.moduleInfo, context.log, ipcListeners) + module.extras["im"] = InterfaceManager(module.moduleInfo, context.log) + module.extras["config"] = RemoteScriptConfig(this@RemoteScriptManager, module.moduleInfo, context.log).also { + it.load() + } } sync() enabledScripts.forEach { name -> - if (getModuleDataFolder(name) == null) { - context.log.warn("Module data folder not found for $name") - } loadScript(name) } } @@ -62,19 +60,17 @@ class RemoteScriptManager( runtime.load(name, content) } - fun getScriptInterface(scriptName: String, interfaceName: String) - = userInterfaces[scriptName]?.get(interfaceName) - - private fun <R> getScriptInputStream(name: String, callback: (InputStream?) -> R): R { val file = getScriptsFolder()?.findFile(name) ?: return callback(null) return context.androidContext.contentResolver.openInputStream(file.uri)?.use(callback) ?: callback(null) } - private fun getModuleDataFolder(moduleFileName: String): DocumentFile? { - val folderName = moduleFileName.substringBeforeLast(".js") - val folder = getScriptsFolder() ?: return null - return folder.findFile(folderName) ?: folder.createDirectory(folderName) + fun getModuleDataFolder(moduleFileName: String): File { + return context.androidContext.filesDir.resolve("modules").resolve(moduleFileName).also { + if (!it.exists()) { + it.mkdirs() + } + } } private fun getScriptsFolder() = runCatching { @@ -114,4 +110,35 @@ class RemoteScriptManager( context.log.error("Failed to send message for $eventName", it) } } + + override fun configTransaction( + module: String?, + action: String, + key: String?, + value: String?, + save: Boolean + ): String? { + val scriptConfig = runtime.getModuleByName(module ?: return null)?.extras?.get("config") as? ConfigInterface ?: return null.also { + context.log.warn("Failed to get config interface for $module") + } + val transactionType = ConfigTransactionType.fromKey(action) + + return runCatching { + scriptConfig.run { + if (transactionType == ConfigTransactionType.GET) { + return get(key ?: return@runCatching null, value) + } + when (transactionType) { + ConfigTransactionType.SET -> set(key ?: return@runCatching null, value, save) + ConfigTransactionType.SAVE -> save() + ConfigTransactionType.LOAD -> load() + ConfigTransactionType.DELETE -> delete() + else -> {} + } + null + } + }.onFailure { + context.log.error("Failed to perform config transaction", it) + }.getOrDefault("") + } } \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/scripting/impl/RemoteManagerIPC.kt b/app/src/main/kotlin/me/rhunk/snapenhance/scripting/impl/RemoteManagerIPC.kt @@ -3,8 +3,8 @@ package me.rhunk.snapenhance.scripting.impl import android.os.DeadObjectException import me.rhunk.snapenhance.bridge.scripting.IPCListener import me.rhunk.snapenhance.common.logger.AbstractLogger -import me.rhunk.snapenhance.common.scripting.IPCInterface -import me.rhunk.snapenhance.common.scripting.Listener +import me.rhunk.snapenhance.common.scripting.impl.IPCInterface +import me.rhunk.snapenhance.common.scripting.impl.Listener import me.rhunk.snapenhance.common.scripting.type.ModuleInfo import java.util.concurrent.ConcurrentHashMap diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/scripting/impl/RemoteScriptConfig.kt b/app/src/main/kotlin/me/rhunk/snapenhance/scripting/impl/RemoteScriptConfig.kt @@ -0,0 +1,57 @@ +package me.rhunk.snapenhance.scripting.impl + +import com.google.gson.JsonObject +import me.rhunk.snapenhance.common.logger.AbstractLogger +import me.rhunk.snapenhance.common.scripting.impl.ConfigInterface +import me.rhunk.snapenhance.common.scripting.type.ModuleInfo +import me.rhunk.snapenhance.scripting.RemoteScriptManager +import java.io.File + +class RemoteScriptConfig( + private val remoteScriptManager: RemoteScriptManager, + moduleInfo: ModuleInfo, + private val logger: AbstractLogger, +) : ConfigInterface() { + private val configFile = File(remoteScriptManager.getModuleDataFolder(moduleInfo.name), "config.json") + private var config = JsonObject() + + override fun get(key: String, defaultValue: Any?): String? { + return config[key]?.asString ?: defaultValue?.toString() + } + + override fun set(key: String, value: Any?, save: Boolean) { + when (value) { + is Int -> config.addProperty(key, value) + is Double -> config.addProperty(key, value) + is Boolean -> config.addProperty(key, value) + is Long -> config.addProperty(key, value) + is Float -> config.addProperty(key, value) + is Byte -> config.addProperty(key, value) + is Short -> config.addProperty(key, value) + else -> config.addProperty(key, value?.toString()) + } + + if (save) save() + } + + override fun save() { + configFile.writeText(config.toString()) + } + + override fun load() { + runCatching { + if (!configFile.exists()) { + save() + return@runCatching + } + config = remoteScriptManager.context.gson.fromJson(configFile.readText(), JsonObject::class.java) + }.onFailure { + logger.error("Failed to load config file", it) + save() + } + } + + override fun delete() { + configFile.delete() + } +}+ \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/scripting/impl/ui/InterfaceManager.kt b/app/src/main/kotlin/me/rhunk/snapenhance/scripting/impl/ui/InterfaceManager.kt @@ -12,15 +12,15 @@ import org.mozilla.javascript.annotations.JSFunction class InterfaceBuilder { val nodes = mutableListOf<Node>() - var onLaunchedCallback: (() -> Unit)? = null + var onDisposeCallback: (() -> Unit)? = null private fun createNode(type: NodeType, block: Node.() -> Unit): Node { return Node(type).apply(block).also { nodes.add(it) } } - fun onLaunched(block: () -> Unit) { - onLaunchedCallback = block + fun onDispose(block: () -> Unit) { + onDisposeCallback = block } fun row(block: (InterfaceBuilder) -> Unit) = RowColumnNode(NodeType.ROW).apply { @@ -66,14 +66,25 @@ class InterfaceBuilder { class InterfaceManager( private val moduleInfo: ModuleInfo, - private val logger: AbstractLogger, - private val registerInterface: (String, InterfaceBuilder) -> Unit, + private val logger: AbstractLogger ) { - @JSFunction - fun create(name: String, callback: Function) { - logger.info("Creating interface $name for ${moduleInfo.name}") - val interfaceBuilder = InterfaceBuilder() - callback.call(Context.getCurrentContext(), callback, callback, arrayOf(interfaceBuilder)) - registerInterface(name, interfaceBuilder) + private val interfaces = mutableMapOf<String, () -> InterfaceBuilder?>() + + fun buildInterface(name: String): InterfaceBuilder? { + return interfaces[name]?.invoke() + } + + @JSFunction fun create(name: String, callback: Function) { + interfaces[name] = { + val interfaceBuilder = InterfaceBuilder() + runCatching { + Context.enter() + callback.call(Context.getCurrentContext(), callback, callback, arrayOf(interfaceBuilder)) + Context.exit() + interfaceBuilder + }.onFailure { + logger.error("Failed to create interface $name for ${moduleInfo.name}", it) + }.getOrNull() + } } } \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/scripting/ScriptInterface.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/scripting/ScriptInterface.kt @@ -147,8 +147,14 @@ fun ScriptInterface(interfaceBuilder: InterfaceBuilder) { DrawNode(node) } - LaunchedEffect(interfaceBuilder) { - interfaceBuilder.onLaunchedCallback?.invoke() + DisposableEffect(Unit) { + onDispose { + runCatching { + interfaceBuilder.onDisposeCallback?.invoke() + }.onFailure { + AbstractLogger.directError("Error running onDisposed callback", it) + } + } } } } \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/scripting/ScriptsSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/scripting/ScriptsSection.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.unit.sp import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.rhunk.snapenhance.common.scripting.type.ModuleInfo +import me.rhunk.snapenhance.scripting.impl.ui.InterfaceManager import me.rhunk.snapenhance.ui.manager.Section import me.rhunk.snapenhance.ui.util.pullrefresh.PullRefreshIndicator import me.rhunk.snapenhance.ui.util.pullrefresh.pullRefresh @@ -88,7 +89,8 @@ class ScriptsSection : Section() { @Composable fun ScriptSettings(script: ModuleInfo) { val settingsInterface = remember { - context.scriptManager.getScriptInterface(script.name, "settings") + val module = context.scriptManager.runtime.getModuleByName(script.name) ?: return@remember null + (module.extras["im"] as? InterfaceManager)?.buildInterface("settings") } ?: run { Text( text = "This module does not have any settings", @@ -101,7 +103,6 @@ class ScriptsSection : Section() { ScriptInterface(interfaceBuilder = settingsInterface) } - @Composable override fun Content() { var scriptModules by remember { diff --git a/common/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IScripting.aidl b/common/src/main/aidl/me/rhunk/snapenhance/bridge/scripting/IScripting.aidl @@ -10,4 +10,6 @@ interface IScripting { void registerIPCListener(String channel, String eventName, IPCListener listener); void sendIPCMessage(String channel, String eventName, in String[] args); + + @nullable String configTransaction(String module, String action, @nullable String key, @nullable String value, boolean save); } \ No newline at end of file diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/IPCInterface.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/IPCInterface.kt @@ -1,17 +0,0 @@ -package me.rhunk.snapenhance.common.scripting - -typealias Listener = (Array<out String?>) -> Unit - -abstract class IPCInterface { - abstract fun on(eventName: String, listener: Listener) - - abstract fun onBroadcast(channel: String, eventName: String, listener: Listener) - - abstract fun emit(eventName: String, vararg args: String?) - abstract fun broadcast(channel: String, eventName: String, vararg args: String?) - - @Suppress("unused") - fun emit(eventName: String) = emit(eventName, *emptyArray()) - @Suppress("unused") - fun emit(channel: String, eventName: String) = broadcast(channel, eventName) -}- \ No newline at end of file diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/JSModule.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/JSModule.kt @@ -18,6 +18,7 @@ class JSModule( val moduleInfo: ModuleInfo, val content: String, ) { + val extras = mutableMapOf<String, Any>() private lateinit var moduleObject: ScriptableObject fun load(block: ScriptableObject.() -> Unit) { @@ -115,8 +116,10 @@ class JSModule( Undefined.instance } } - block(moduleObject) + extras.forEach { (key, value) -> + moduleObject.putConst(key, moduleObject, value) + } evaluateString(moduleObject, content, moduleInfo.name, 1, null) } } diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ScriptRuntime.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ScriptRuntime.kt @@ -25,6 +25,10 @@ open class ScriptRuntime( } } + fun getModuleByName(name: String): JSModule? { + return modules.values.find { it.moduleInfo.name == name } + } + private fun readModuleInfo(reader: BufferedReader): ModuleInfo { val header = reader.readLine() if (!header.startsWith("// ==SE_module==")) { diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/impl/ConfigInterface.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/impl/ConfigInterface.kt @@ -0,0 +1,74 @@ +package me.rhunk.snapenhance.common.scripting.impl + +import org.mozilla.javascript.annotations.JSFunction + + +enum class ConfigTransactionType( + val key: String +) { + GET("get"), + SET("set"), + SAVE("save"), + LOAD("load"), + DELETE("delete"); + + companion object { + fun fromKey(key: String) = entries.find { it.key == key } + } +} + + +abstract class ConfigInterface { + @JSFunction fun get(key: String): String? = get(key, null) + @JSFunction abstract fun get(key: String, defaultValue: Any?): String? + + @JSFunction fun getInteger(key: String): Int? = getInteger(key, null) + @JSFunction fun getInteger(key: String, defaultValue: Int?): Int? = get(key, defaultValue.toString())?.toIntOrNull() ?: defaultValue + + @JSFunction fun getDouble(key: String): Double? = getDouble(key, null) + @JSFunction fun getDouble(key: String, defaultValue: Double?): Double? = get(key, defaultValue.toString())?.toDoubleOrNull() ?: defaultValue + + @JSFunction fun getBoolean(key: String): Boolean? = getBoolean(key, null) + @JSFunction fun getBoolean(key: String, defaultValue: Boolean?): Boolean? = get(key, defaultValue.toString())?.toBoolean() ?: defaultValue + + @JSFunction fun getLong(key: String): Long? = getLong(key, null) + @JSFunction fun getLong(key: String, defaultValue: Long?): Long? = get(key, defaultValue.toString())?.toLongOrNull() ?: defaultValue + + @JSFunction fun getFloat(key: String): Float? = getFloat(key, null) + @JSFunction fun getFloat(key: String, defaultValue: Float?): Float? = get(key, defaultValue.toString())?.toFloatOrNull() ?: defaultValue + + @JSFunction fun getByte(key: String): Byte? = getByte(key, null) + @JSFunction fun getByte(key: String, defaultValue: Byte?): Byte? = get(key, defaultValue.toString())?.toByteOrNull() ?: defaultValue + + @JSFunction fun getShort(key: String): Short? = getShort(key, null) + @JSFunction fun getShort(key: String, defaultValue: Short?): Short? = get(key, defaultValue.toString())?.toShortOrNull() ?: defaultValue + + + @JSFunction fun set(key: String, value: Any?) = set(key, value, false) + @JSFunction abstract fun set(key: String, value: Any?, save: Boolean) + + @JSFunction fun setInteger(key: String, value: Int?) = setInteger(key, value, false) + @JSFunction fun setInteger(key: String, value: Int?, save: Boolean) = set(key, value, save) + + @JSFunction fun setDouble(key: String, value: Double?) = setDouble(key, value, false) + @JSFunction fun setDouble(key: String, value: Double?, save: Boolean) = set(key, value, save) + + @JSFunction fun setBoolean(key: String, value: Boolean?) = setBoolean(key, value, false) + @JSFunction fun setBoolean(key: String, value: Boolean?, save: Boolean) = set(key, value, save) + + @JSFunction fun setLong(key: String, value: Long?) = setLong(key, value, false) + @JSFunction fun setLong(key: String, value: Long?, save: Boolean) = set(key, value, save) + + @JSFunction fun setFloat(key: String, value: Float?) = setFloat(key, value, false) + @JSFunction fun setFloat(key: String, value: Float?, save: Boolean) = set(key, value, save) + + @JSFunction fun setByte(key: String, value: Byte?) = setByte(key, value, false) + @JSFunction fun setByte(key: String, value: Byte?, save: Boolean) = set(key, value, save) + + @JSFunction fun setShort(key: String, value: Short?) = setShort(key, value, false) + @JSFunction fun setShort(key: String, value: Short?, save: Boolean) = set(key, value, save) + + @JSFunction abstract fun save() + @JSFunction abstract fun load() + @JSFunction abstract fun delete() +}+ \ No newline at end of file diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/impl/IPCInterface.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/impl/IPCInterface.kt @@ -0,0 +1,17 @@ +package me.rhunk.snapenhance.common.scripting.impl + +typealias Listener = (Array<out String?>) -> Unit + +abstract class IPCInterface { + abstract fun on(eventName: String, listener: Listener) + + abstract fun onBroadcast(channel: String, eventName: String, listener: Listener) + + abstract fun emit(eventName: String, vararg args: String?) + abstract fun broadcast(channel: String, eventName: String, vararg args: String?) + + @Suppress("unused") + fun emit(eventName: String) = emit(eventName, *emptyArray()) + @Suppress("unused") + fun emit(channel: String, eventName: String) = broadcast(channel, eventName) +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/scripting/CoreScriptRuntime.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/scripting/CoreScriptRuntime.kt @@ -1,12 +1,11 @@ package me.rhunk.snapenhance.core.scripting import android.content.Context -import me.rhunk.snapenhance.bridge.scripting.IPCListener import me.rhunk.snapenhance.bridge.scripting.IScripting import me.rhunk.snapenhance.common.logger.AbstractLogger -import me.rhunk.snapenhance.common.scripting.IPCInterface -import me.rhunk.snapenhance.common.scripting.Listener import me.rhunk.snapenhance.common.scripting.ScriptRuntime +import me.rhunk.snapenhance.core.scripting.impl.CoreIPC +import me.rhunk.snapenhance.core.scripting.impl.CoreScriptConfig import me.rhunk.snapenhance.core.scripting.impl.ScriptHooker class CoreScriptRuntime( @@ -18,38 +17,19 @@ class CoreScriptRuntime( fun connect(scriptingInterface: IScripting) { scriptingInterface.apply { buildModuleObject = { module -> - putConst("ipc", this, object: IPCInterface() { - override fun onBroadcast(channel: String, eventName: String, listener: Listener) { - registerIPCListener(channel, eventName, object: IPCListener.Stub() { - override fun onMessage(args: Array<out String?>) { - listener(args) - } - }) - } - - override fun on(eventName: String, listener: Listener) { - onBroadcast(module.moduleInfo.name, eventName, listener) - } - - override fun emit(eventName: String, vararg args: String?) { - broadcast(module.moduleInfo.name, eventName, *args) - } - - override fun broadcast(channel: String, eventName: String, vararg args: String?) { - sendIPCMessage(channel, eventName, args) - } - }) - putConst("hooker", this, ScriptHooker(module.moduleInfo, logger, androidContext.classLoader).also { + module.extras["ipc"] = CoreIPC(this@apply, module.moduleInfo) + module.extras["hooker"] = ScriptHooker(module.moduleInfo, logger, androidContext.classLoader).also { scriptHookers.add(it) - }) + } + module.extras["config"] = CoreScriptConfig(this@apply, module.moduleInfo) } - } - scriptingInterface.enabledScripts.forEach { path -> - runCatching { - load(path, scriptingInterface.getScriptContent(path)) - }.onFailure { - logger.error("Failed to load script $path", it) + enabledScripts.forEach { path -> + runCatching { + load(path, scriptingInterface.getScriptContent(path)) + }.onFailure { + logger.error("Failed to load script $path", it) + } } } } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/scripting/impl/CoreIPC.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/scripting/impl/CoreIPC.kt @@ -0,0 +1,32 @@ +package me.rhunk.snapenhance.core.scripting.impl + +import me.rhunk.snapenhance.bridge.scripting.IPCListener +import me.rhunk.snapenhance.bridge.scripting.IScripting +import me.rhunk.snapenhance.common.scripting.impl.IPCInterface +import me.rhunk.snapenhance.common.scripting.impl.Listener +import me.rhunk.snapenhance.common.scripting.type.ModuleInfo + +class CoreIPC( + private val scripting: IScripting, + private val moduleInfo: ModuleInfo +) : IPCInterface() { + override fun onBroadcast(channel: String, eventName: String, listener: Listener) { + scripting.registerIPCListener(channel, eventName, object: IPCListener.Stub() { + override fun onMessage(args: Array<out String?>) { + listener(args) + } + }) + } + + override fun on(eventName: String, listener: Listener) { + onBroadcast(moduleInfo.name, eventName, listener) + } + + override fun emit(eventName: String, vararg args: String?) { + broadcast(moduleInfo.name, eventName, *args) + } + + override fun broadcast(channel: String, eventName: String, vararg args: String?) { + scripting.sendIPCMessage(channel, eventName, args) + } +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/scripting/impl/CoreScriptConfig.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/scripting/impl/CoreScriptConfig.kt @@ -0,0 +1,31 @@ +package me.rhunk.snapenhance.core.scripting.impl + +import me.rhunk.snapenhance.bridge.scripting.IScripting +import me.rhunk.snapenhance.common.scripting.impl.ConfigInterface +import me.rhunk.snapenhance.common.scripting.impl.ConfigTransactionType +import me.rhunk.snapenhance.common.scripting.type.ModuleInfo + +class CoreScriptConfig( + private val scripting: IScripting, + private val moduleInfo: ModuleInfo +): ConfigInterface() { + override fun get(key: String, defaultValue: Any?): String? { + return scripting.configTransaction(moduleInfo.name, ConfigTransactionType.GET.key, key, defaultValue.toString(), false) + } + + override fun set(key: String, value: Any?, save: Boolean) { + scripting.configTransaction(moduleInfo.name, ConfigTransactionType.SET.key, key, value.toString(), save) + } + + override fun save() { + scripting.configTransaction(moduleInfo.name, ConfigTransactionType.SAVE.key, null, null, false) + } + + override fun load() { + scripting.configTransaction(moduleInfo.name, ConfigTransactionType.LOAD.key, null, null, false) + } + + override fun delete() { + scripting.configTransaction(moduleInfo.name, ConfigTransactionType.DELETE.key, null, null, false) + } +}+ \ No newline at end of file