Skip to content

Commit

Permalink
Add lang support for javascript
Browse files Browse the repository at this point in the history
  • Loading branch information
only52607 committed Jun 18, 2022
1 parent cd79bae commit 50e2490
Show file tree
Hide file tree
Showing 16 changed files with 1,458 additions and 5 deletions.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Tue Apr 07 17:43:57 CST 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
# distributionUrl=https\://code.aliyun.com/kar/gradle-bin-zip/raw/master/gradle-6.7.1-bin.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
Expand Down
13 changes: 13 additions & 0 deletions lua-mirai-adapter-rhinojs/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
id("me.him188.kotlin-jvm-blocking-bridge") version "2.1.0-162.1"
id("net.mamoe.mirai-console") version "2.8.0"
}

dependencies {
implementation project(":lua-mirai-core")
implementation('org.mozilla:rhino:1.7.14')
implementation("com.squareup.okhttp3:okhttp:4.9.0")

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
This code is copied from:
https://github.com/hyb1996/Auto.js/blob/master/autojs/src/main/java/com/stardust/autojs/core/http/MutableOkHttp.java
This code is licensed under Mozilla Public License Version 2.0
See: https://github.com/hyb1996/Auto.js/blob/master/LICENSE.md
*/

package com.stardust.autojs.core.http;

import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
* Created by Stardust on 2018/4/11.
*/

@SuppressWarnings("ALL")
public class MutableOkHttp extends OkHttpClient {

private OkHttpClient mOkHttpClient;
private int mMaxRetries = 3;
private long mTimeout = 30 * 1000;
private Interceptor mRetryInterceptor = chain -> {
Request request = chain.request();
Response response = null;
int tryCount = 0;
do {
boolean succeed;
try {
response = chain.proceed(request);
succeed = response.isSuccessful();
} catch (SocketTimeoutException e) {
succeed = false;
if (tryCount >= getMaxRetries()) {
throw e;
}
}
if (succeed || tryCount >= getMaxRetries()) {
return response;
}
tryCount++;
} while (true);
};

public MutableOkHttp() {
mOkHttpClient = newClient(new OkHttpClient.Builder());
}

public OkHttpClient client() {
return mOkHttpClient;
}

protected OkHttpClient newClient(Builder builder) {
builder.readTimeout(getTimeout(), TimeUnit.MILLISECONDS)
.writeTimeout(getTimeout(), TimeUnit.MILLISECONDS)
.connectTimeout(getTimeout(), TimeUnit.MILLISECONDS);
for (Interceptor interceptor : getInterceptors()) {
builder.addInterceptor(interceptor);
}
return builder.build();
}

public Iterable<? extends Interceptor> getInterceptors() {
return Collections.singletonList(mRetryInterceptor);
}

public int getMaxRetries() {
return mMaxRetries;
}

public void setMaxRetries(int maxRetries) {
mMaxRetries = maxRetries;
}

public long getTimeout() {
return mTimeout;
}


public void setTimeout(long timeout) {
mTimeout = timeout;
muteClient();
}

public synchronized void muteClient(Builder builder) {
mOkHttpClient = newClient(builder);
}

protected synchronized void muteClient() {
mOkHttpClient = newClient(mOkHttpClient.newBuilder());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.only52607.luamirai.js

import org.mozilla.javascript.Context
import org.mozilla.javascript.Scriptable

abstract class JSLib {
abstract val nameInJs: String

@JvmSynthetic
abstract fun importTo(scope: Scriptable, context: Context)
}

fun Context.loadLib(lib: JSLib, scope: Scriptable) {
lib.importTo(scope, this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package com.github.only52607.luamirai.js

import com.github.only52607.luamirai.core.script.AbstractBotScript
import com.github.only52607.luamirai.core.script.BotScriptHeader
import com.github.only52607.luamirai.core.script.BotScriptSource
import com.github.only52607.luamirai.js.libs.LoggerLib
import com.github.only52607.luamirai.js.libs.MiraiLib
import kotlinx.coroutines.*
import org.mozilla.javascript.Context
import org.mozilla.javascript.FunctionObject
import org.mozilla.javascript.ImporterTopLevel
import org.mozilla.javascript.Scriptable
import java.io.InputStream
import java.io.InputStreamReader
import java.io.OutputStream
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import kotlin.coroutines.CoroutineContext
import kotlin.reflect.jvm.javaMethod

/**
* ClassName: JsMiraiScript
* Description:
* date: 2022/6/14 22:33
* @author ooooonly
* @version
*/
class JsMiraiScript(
override val source: BotScriptSource,
override val header: BotScriptHeader
) : AbstractBotScript(), CoroutineScope {
override val lang: String
get() = source.lang

private val loggerLib = LoggerLib()

override var stdout: OutputStream?
get() = loggerLib.stdout
set(value) {
loggerLib.stdout = value!!
}

override var stderr: OutputStream?
get() = loggerLib.stderr
set(value) {
loggerLib.stderr = value!!
}

override var stdin: InputStream?
get() = loggerLib.stdin
set(value) {
loggerLib.stdin = value!!
}

private val contextThreadDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()

override val coroutineContext: CoroutineContext
get() = SupervisorJob() + contextThreadDispatcher

private lateinit var context: Context

private lateinit var globalScope: Scriptable

private val moduleSearchPaths = listOf("?", "?.js")

override suspend fun onStart() {
prepareContext()
prepareGlobalScope()
execMainScript()
}

override suspend fun onStop() {
withContext(contextThreadDispatcher) {
Context.exit()
}
coroutineContext.cancel()
}

private suspend fun prepareContext() {
withContext(contextThreadDispatcher) {
context = Context.enter().apply {
languageVersion = Context.VERSION_ES6
}
}
}

private fun prepareGlobalScope() {
globalScope = context.initStandardObjects()
context.loadLib(MiraiLib(), globalScope)
// context.loadLib(OkHttpLib(), globalScope)
context.loadLib(loggerLib, globalScope)
}

private fun execMainScript() {
val mainScript = context.compileReader(InputStreamReader(source.mainInputStream), source.name, -1, null)
mainScript.exec(context, buildModuleScope())
}

private fun buildModuleScope() = ImporterTopLevel().apply {
parentScope = globalScope
put("require", this, FunctionObject("require", ::loadModule.javaMethod, this))
put("module", this, context.evaluateString(this, "{}", "module", -1, null))
}

private val moduleCache: ConcurrentHashMap<String, Scriptable> = ConcurrentHashMap()

private fun loadModule(name: String): Scriptable {
val resourceFinder = source.resourceFinder ?: throw Exception("ResourceFinder not found")
val searchedPaths = mutableListOf<String>()
for (searchPath in moduleSearchPaths) {
val actualPath = searchPath.replace("?", name)
moduleCache[actualPath]?.let {
return@loadModule it
}
resourceFinder.findResource(actualPath)?.let { resourceInputStream ->
val scope = buildModuleScope()
val script = context.compileReader(InputStreamReader(resourceInputStream), actualPath, -1, null)
script.exec(context, scope)
val exports = scope.get("exports", scope.get("module", scope) as Scriptable) as Scriptable
moduleCache[actualPath] = exports
return exports
}
searchedPaths.add(actualPath)
}
throw Exception(
"Module $name not found in the following path.\n${
searchedPaths.joinToString(
separator = "\n",
prefix = "\t"
)
}"
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.github.only52607.luamirai.js

import com.github.only52607.luamirai.core.BotScriptBuilder
import com.github.only52607.luamirai.core.script.BotScript
import com.github.only52607.luamirai.core.script.BotScriptHeader
import com.github.only52607.luamirai.core.script.BotScriptSource
import com.github.only52607.luamirai.core.script.mutableBotScriptHeaderOf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

/**
* ClassName: JsMiraiScriptBuilder
* Description:
* date: 2022/6/14 22:33
* @author ooooonly
* @version
*/
class JsMiraiScriptBuilder(
val source: BotScriptSource
) : BotScriptBuilder(source) {
companion object {
const val LANG = "js"

init {
register(LANG, ::JsMiraiScriptBuilder)
}
}

override val lang: String
get() = LANG

override suspend fun buildInstance(): BotScript {
return withContext(Dispatchers.IO) {
JsMiraiScript(source, readHeader())
}
}

private fun readHeaderFromJsonManifest(jsonString: String): BotScriptHeader {
val json = Json
val manifest: JsonObject = json.parseToJsonElement(jsonString).jsonObject
return mutableBotScriptHeaderOf {
manifest["header"]?.jsonObject?.forEach { key, value ->
this@mutableBotScriptHeaderOf[key] = value.jsonPrimitive.content
}
}
}

override suspend fun readHeader(): BotScriptHeader {
val manifestInputStream =
source.resourceFinder?.findResource("manifest.json") ?: return mutableBotScriptHeaderOf()
return readHeaderFromJsonManifest(String(manifestInputStream.readBytes()))
}
}
Loading

0 comments on commit 50e2490

Please sign in to comment.