feat(scripting): module updater
This commit is contained in:
@@ -5,9 +5,8 @@ import android.os.ParcelFileDescriptor
|
||||
import me.rhunk.snapenhance.bridge.scripting.IScripting
|
||||
import me.rhunk.snapenhance.common.BuildConfig
|
||||
import me.rhunk.snapenhance.common.logger.AbstractLogger
|
||||
import me.rhunk.snapenhance.common.scripting.type.ModuleInfo
|
||||
import me.rhunk.snapenhance.common.scripting.type.readModuleInfo
|
||||
import org.mozilla.javascript.ScriptableObject
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStream
|
||||
|
||||
open class ScriptRuntime(
|
||||
@@ -35,45 +34,6 @@ open class ScriptRuntime(
|
||||
return modules.values.find { it.moduleInfo.name == name }
|
||||
}
|
||||
|
||||
fun readModuleInfo(reader: BufferedReader): ModuleInfo {
|
||||
val header = reader.readLine()
|
||||
if (!header.startsWith("// ==SE_module==")) {
|
||||
throw Exception("Invalid module header")
|
||||
}
|
||||
|
||||
val properties = mutableMapOf<String, String>()
|
||||
while (true) {
|
||||
val line = reader.readLine()
|
||||
if (line.startsWith("// ==/SE_module==")) {
|
||||
break
|
||||
}
|
||||
val split = line.replaceFirst("//", "").split(":")
|
||||
if (split.size != 2) {
|
||||
throw Exception("Invalid module property")
|
||||
}
|
||||
properties[split[0].trim()] = split[1].trim()
|
||||
}
|
||||
|
||||
return ModuleInfo(
|
||||
name = properties["name"]?.also {
|
||||
if (!it.matches(Regex("[a-z_]+"))) {
|
||||
throw Exception("Invalid module name : Only lowercase letters and underscores are allowed")
|
||||
}
|
||||
} ?: throw Exception("Missing module name"),
|
||||
version = properties["version"] ?: throw Exception("Missing module version"),
|
||||
displayName = properties["displayName"],
|
||||
description = properties["description"],
|
||||
author = properties["author"],
|
||||
minSnapchatVersion = properties["minSnapchatVersion"]?.toLongOrNull(),
|
||||
minSEVersion = properties["minSEVersion"]?.toLongOrNull(),
|
||||
grantedPermissions = properties["permissions"]?.split(",")?.map { it.trim() } ?: emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
fun getModuleInfo(inputStream: InputStream): ModuleInfo {
|
||||
return readModuleInfo(inputStream.bufferedReader())
|
||||
}
|
||||
|
||||
fun removeModule(scriptPath: String) {
|
||||
modules.remove(scriptPath)
|
||||
}
|
||||
@@ -94,7 +54,7 @@ open class ScriptRuntime(
|
||||
fun load(scriptPath: String, content: InputStream): JSModule {
|
||||
logger.info("Loading module $scriptPath")
|
||||
val bufferedReader = content.bufferedReader()
|
||||
val moduleInfo = readModuleInfo(bufferedReader)
|
||||
val moduleInfo = bufferedReader.readModuleInfo()
|
||||
|
||||
if (moduleInfo.minSEVersion != null && moduleInfo.minSEVersion > BuildConfig.VERSION_CODE) {
|
||||
throw Exception("Module requires a newer version of SnapEnhance (min version: ${moduleInfo.minSEVersion})")
|
||||
|
||||
@@ -1,28 +1,57 @@
|
||||
package me.rhunk.snapenhance.common.scripting.type
|
||||
|
||||
import java.io.BufferedReader
|
||||
|
||||
data class ModuleInfo(
|
||||
val name: String,
|
||||
val version: String,
|
||||
val displayName: String? = null,
|
||||
val description: String? = null,
|
||||
val updateUrl: String? = null,
|
||||
val author: String? = null,
|
||||
val minSnapchatVersion: Long? = null,
|
||||
val minSEVersion: Long? = null,
|
||||
val grantedPermissions: List<String>,
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is ModuleInfo) return false
|
||||
if (other === this) return true
|
||||
return name == other.name &&
|
||||
version == other.version &&
|
||||
displayName == other.displayName &&
|
||||
description == other.description &&
|
||||
author == other.author
|
||||
}
|
||||
|
||||
fun ensurePermissionGranted(permission: Permissions) {
|
||||
if (!grantedPermissions.contains(permission.key)) {
|
||||
throw AssertionError("Permission $permission is not granted")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BufferedReader.readModuleInfo(): ModuleInfo {
|
||||
val header = readLine()
|
||||
if (!header.startsWith("// ==SE_module==")) {
|
||||
throw Exception("Invalid module header")
|
||||
}
|
||||
|
||||
val properties = mutableMapOf<String, String>()
|
||||
while (true) {
|
||||
val line = readLine()
|
||||
if (line.startsWith("// ==/SE_module==")) {
|
||||
break
|
||||
}
|
||||
val split = line.replaceFirst("//", "").split(":", limit = 2)
|
||||
if (split.size != 2) {
|
||||
throw Exception("Invalid module property")
|
||||
}
|
||||
properties[split[0].trim()] = split[1].trim()
|
||||
}
|
||||
|
||||
return ModuleInfo(
|
||||
name = properties["name"]?.also {
|
||||
if (!it.matches(Regex("[a-z_]+"))) {
|
||||
throw Exception("Invalid module name : Only lowercase letters and underscores are allowed")
|
||||
}
|
||||
} ?: throw Exception("Missing module name"),
|
||||
version = properties["version"] ?: throw Exception("Missing module version"),
|
||||
displayName = properties["displayName"],
|
||||
description = properties["description"],
|
||||
updateUrl = properties["updateUrl"],
|
||||
author = properties["author"],
|
||||
minSnapchatVersion = properties["minSnapchatVersion"]?.toLongOrNull(),
|
||||
minSEVersion = properties["minSEVersion"]?.toLongOrNull(),
|
||||
grantedPermissions = properties["permissions"]?.split(",")?.map { it.trim() } ?: emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ fun <T> rememberAsyncMutableState(
|
||||
defaultValue: T,
|
||||
updateDispatcher: AsyncUpdateDispatcher? = null,
|
||||
keys: Array<*> = emptyArray<Any>(),
|
||||
getter: () -> T,
|
||||
getter: suspend () -> T,
|
||||
): MutableState<T> {
|
||||
return rememberCommonState(
|
||||
initialState = { mutableStateOf(defaultValue) },
|
||||
@@ -82,7 +82,7 @@ fun <T> rememberAsyncMutableStateList(
|
||||
defaultValue: List<T>,
|
||||
updateDispatcher: AsyncUpdateDispatcher? = null,
|
||||
keys: Array<*> = emptyArray<Any>(),
|
||||
getter: () -> List<T>,
|
||||
getter: suspend () -> List<T>,
|
||||
): SnapshotStateList<T> {
|
||||
return rememberCommonState(
|
||||
initialState = { mutableStateListOf<T>().apply {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package me.rhunk.snapenhance.common.util.ktx
|
||||
|
||||
import kotlinx.coroutines.CompletionHandler
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.Response
|
||||
import okio.IOException
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
suspend inline fun Call.await(): Response {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val callback = object: CompletionHandler, Callback {
|
||||
override fun invoke(cause: Throwable?) {
|
||||
runCatching { cancel() }
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
continuation.resumeWithException(e)
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
continuation.resumeWith(runCatching { response })
|
||||
}
|
||||
}
|
||||
enqueue(callback)
|
||||
continuation.invokeOnCancellation(callback)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user