mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 05:27:23 +00:00
code clean up
This commit is contained in:
22
.vscode/c_cpp_properties.json
vendored
22
.vscode/c_cpp_properties.json
vendored
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Linux",
|
|
||||||
"includePath": [
|
|
||||||
"${workspaceFolder}/**",
|
|
||||||
"C:\\Users\\ekibun\\AppData\\Local\\Android\\Sdk\\ndk\\21.3.6528147\\toolchains\\llvm\\prebuilt\\windows-x86_64\\sysroot\\usr\\include"
|
|
||||||
],
|
|
||||||
"defines": [
|
|
||||||
"_DEBUG",
|
|
||||||
"UNICODE",
|
|
||||||
"_UNICODE"
|
|
||||||
],
|
|
||||||
"windowsSdkVersion": "10.0.18362.0",
|
|
||||||
"compilerPath": "C:\\Users\\ekibun\\AppData\\Local\\Android\\Sdk\\cmake\\3.10.2.4988404\\bin\\cmake.exe",
|
|
||||||
"cStandard": "c11",
|
|
||||||
"cppStandard": "c++17",
|
|
||||||
"intelliSenseMode": "gcc-x64"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": 4
|
|
||||||
}
|
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.4.1)
|
cmake_minimum_required(VERSION 3.4.1)
|
||||||
set(JNI_LIB_NAME libjsengine)
|
set(JNI_LIB_NAME libjsengine)
|
||||||
|
set(QUICK_JS_LIB_DIR ../../../../cxx)
|
||||||
|
|
||||||
|
|
||||||
# Creates and names a library, sets it as either STATIC
|
# Creates and names a library, sets it as either STATIC
|
||||||
@@ -22,13 +23,13 @@ add_library( # Sets the name of the library.
|
|||||||
native-lib.cpp )
|
native-lib.cpp )
|
||||||
|
|
||||||
# quickjs
|
# quickjs
|
||||||
file (STRINGS "quickjs/VERSION" QUICKJS_VERSION)
|
file (STRINGS "${QUICK_JS_LIB_DIR}/quickjs/VERSION" QUICKJS_VERSION)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_VERSION=\\\"${QUICKJS_VERSION}\\\"")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_VERSION=\\\"${QUICKJS_VERSION}\\\"")
|
||||||
target_sources(${JNI_LIB_NAME} PUBLIC
|
target_sources(${JNI_LIB_NAME} PUBLIC
|
||||||
quickjs/cutils.c
|
${QUICK_JS_LIB_DIR}/quickjs/cutils.c
|
||||||
quickjs/libregexp.c
|
${QUICK_JS_LIB_DIR}/quickjs/libregexp.c
|
||||||
quickjs/libunicode.c
|
${QUICK_JS_LIB_DIR}/quickjs/libunicode.c
|
||||||
quickjs/quickjs.c
|
${QUICK_JS_LIB_DIR}/quickjs/quickjs.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Searches for a specified prebuilt library and stores the path as a
|
# Searches for a specified prebuilt library and stores the path as a
|
||||||
|
@@ -3,17 +3,14 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-09 18:16:11
|
* @Date: 2020-08-09 18:16:11
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-12 23:11:35
|
* @LastEditTime: 2020-08-12 23:37:28
|
||||||
*/
|
*/
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "js_engine.hpp"
|
#include "../../../../cxx/js_engine.hpp"
|
||||||
|
|
||||||
qjs::Engine *engine = nullptr;
|
qjs::Engine *engine = nullptr;
|
||||||
|
|
||||||
// static jobject gClassLoader;
|
|
||||||
// static jmethodID gFindClassMethod;
|
|
||||||
|
|
||||||
JNIEnv *getEnv(JavaVM *gJvm)
|
JNIEnv *getEnv(JavaVM *gJvm)
|
||||||
{
|
{
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
@@ -29,26 +26,6 @@ JNIEnv *getEnv(JavaVM *gJvm)
|
|||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
// JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved)
|
|
||||||
// {
|
|
||||||
// JNIEnv *env = getEnv(pjvm);
|
|
||||||
// auto randomClass = env->FindClass("soko/ekibun/flutter_qjs/ResultWrapper");
|
|
||||||
// jclass classClass = env->GetObjectClass(randomClass);
|
|
||||||
// auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
|
|
||||||
// auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
|
|
||||||
// "()Ljava/lang/ClassLoader;");
|
|
||||||
// gClassLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
|
|
||||||
// gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
|
|
||||||
// "(Ljava/lang/String;)Ljava/lang/Class;");
|
|
||||||
|
|
||||||
// return JNI_VERSION_1_6;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// jclass findClass(JNIEnv *env, const char *name)
|
|
||||||
// {
|
|
||||||
// return static_cast<jclass>(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
|
|
||||||
// }
|
|
||||||
|
|
||||||
void jniResultResolve(JavaVM *jvm, jobject result, std::string data)
|
void jniResultResolve(JavaVM *jvm, jobject result, std::string data)
|
||||||
{
|
{
|
||||||
JNIEnv *env = getEnv(jvm);
|
JNIEnv *env = getEnv(jvm);
|
||||||
@@ -122,12 +99,9 @@ Java_soko_ekibun_flutter_1qjs_JniBridge_evaluate(
|
|||||||
env->GetStringUTFChars(name, 0),
|
env->GetStringUTFChars(name, 0),
|
||||||
[jvm, gresult](std::string resolve) {
|
[jvm, gresult](std::string resolve) {
|
||||||
jniResultResolve(jvm, gresult, resolve);
|
jniResultResolve(jvm, gresult, resolve);
|
||||||
// flutter::EncodableValue response(resolve);
|
|
||||||
// presult->Success(&response);
|
|
||||||
},
|
},
|
||||||
[jvm, gresult](std::string reject) {
|
[jvm, gresult](std::string reject) {
|
||||||
jniResultReject(jvm, gresult, reject);
|
jniResultReject(jvm, gresult, reject);
|
||||||
// presult->Error("FlutterJSException", reject);
|
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,10 +3,10 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-07 13:55:52
|
* @Date: 2020-08-07 13:55:52
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-12 14:24:42
|
* @LastEditTime: 2020-08-12 23:30:57
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "quickjs/quickjspp.hpp"
|
#include "quickjspp.hpp"
|
||||||
#include "quickjs/list.h"
|
#include "quickjs/list.h"
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <string.h>
|
#include <string.h>
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 10:30:59
|
* @Date: 2020-08-08 10:30:59
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-12 13:53:59
|
* @LastEditTime: 2020-08-12 23:27:20
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "js_dart_promise.hpp"
|
#include "js_dart_promise.hpp"
|
||||||
#include "quickjs/quickjspp.hpp"
|
#include "quickjspp.hpp"
|
||||||
|
|
||||||
namespace qjs
|
namespace qjs
|
||||||
{
|
{
|
@@ -215,7 +215,11 @@ typedef struct JSValue {
|
|||||||
#define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
|
#define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
|
||||||
#define JS_VALUE_GET_PTR(v) ((v).u.ptr)
|
#define JS_VALUE_GET_PTR(v) ((v).u.ptr)
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define JS_MKVAL(tag, val) JSValue { JSValueUnion { val }, tag }
|
||||||
|
#else
|
||||||
#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
|
#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
|
||||||
|
#endif
|
||||||
#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }
|
#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }
|
||||||
|
|
||||||
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
|
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
|
@@ -12,7 +12,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace qjs {
|
namespace qjs {
|
||||||
#include "quickjs.h"
|
#include "quickjs/quickjs.h"
|
||||||
|
|
||||||
|
|
||||||
/** Exception type.
|
/** Exception type.
|
@@ -3,14 +3,12 @@
|
|||||||
// This must be included before many other Windows headers.
|
// This must be included before many other Windows headers.
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
// For getPlatformVersion; remove unless needed for your plugin implementation.
|
|
||||||
#include <VersionHelpers.h>
|
|
||||||
|
|
||||||
#include <flutter/method_channel.h>
|
#include <flutter/method_channel.h>
|
||||||
#include <flutter/plugin_registrar_windows.h>
|
#include <flutter/plugin_registrar_windows.h>
|
||||||
#include <flutter/standard_method_codec.h>
|
#include <flutter/standard_method_codec.h>
|
||||||
|
#include <flutter/method_result_functions.h>
|
||||||
|
|
||||||
#include "js_engine.hpp"
|
#include "../cxx/js_engine.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -32,6 +30,37 @@ namespace
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel;
|
std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel;
|
||||||
|
std::future<qjs::JSFutureReturn> invokeChannelMethod(std::string name, std::string args)
|
||||||
|
{
|
||||||
|
auto promise = new std::promise<qjs::JSFutureReturn>();
|
||||||
|
channel->InvokeMethod(
|
||||||
|
name,
|
||||||
|
std::make_unique<flutter::EncodableValue>(args),
|
||||||
|
std::make_unique<flutter::MethodResultFunctions<flutter::EncodableValue>>(
|
||||||
|
(flutter::ResultHandlerSuccess<flutter::EncodableValue>)[promise](
|
||||||
|
const flutter::EncodableValue *result) {
|
||||||
|
promise->set_value((qjs::JSFutureReturn)[rep = std::get<std::string>(*result)](qjs::JSContext * ctx) {
|
||||||
|
qjs::JSValue *ret = new qjs::JSValue{JS_NewString(ctx, rep.c_str())};
|
||||||
|
return qjs::JSOSFutureArgv{1, ret};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(flutter::ResultHandlerError<flutter::EncodableValue>)[promise](
|
||||||
|
const std::string &error_code,
|
||||||
|
const std::string &error_message,
|
||||||
|
const flutter::EncodableValue *error_details) {
|
||||||
|
promise->set_value((qjs::JSFutureReturn)[error_message](qjs::JSContext * ctx) {
|
||||||
|
qjs::JSValue *ret = new qjs::JSValue{JS_NewString(ctx, error_message.c_str())};
|
||||||
|
return qjs::JSOSFutureArgv{-1, ret};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(flutter::ResultHandlerNotImplemented<flutter::EncodableValue>)[promise]() {
|
||||||
|
promise->set_value((qjs::JSFutureReturn)[](qjs::JSContext * ctx) {
|
||||||
|
qjs::JSValue *ret = new qjs::JSValue{JS_NewString(ctx, "NotImplemented")};
|
||||||
|
return qjs::JSOSFutureArgv{-1, ret};
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
return promise->get_future();
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void FlutterQjsPlugin::RegisterWithRegistrar(
|
void FlutterQjsPlugin::RegisterWithRegistrar(
|
||||||
@@ -81,7 +110,7 @@ namespace
|
|||||||
// for the relevant Flutter APIs.
|
// for the relevant Flutter APIs.
|
||||||
if (method_call.method_name().compare("initEngine") == 0)
|
if (method_call.method_name().compare("initEngine") == 0)
|
||||||
{
|
{
|
||||||
engine = new qjs::Engine(channel);
|
engine = new qjs::Engine((qjs::DartChannel)invokeChannelMethod);
|
||||||
flutter::EncodableValue response((long)engine);
|
flutter::EncodableValue response((long)engine);
|
||||||
result->Success(&response);
|
result->Success(&response);
|
||||||
}
|
}
|
||||||
|
@@ -1,207 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Description:
|
|
||||||
* @Author: ekibun
|
|
||||||
* @Date: 2020-08-07 13:55:52
|
|
||||||
* @LastEditors: ekibun
|
|
||||||
* @LastEditTime: 2020-08-08 16:54:23
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include "quickjs/quickjspp.hpp"
|
|
||||||
#include "quickjs/quickjs/list.h"
|
|
||||||
#include <flutter/method_result_functions.h>
|
|
||||||
#include <future>
|
|
||||||
|
|
||||||
namespace qjs
|
|
||||||
{
|
|
||||||
static JSClassID js_dart_promise_class_id;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
JSValue *argv;
|
|
||||||
} JSOSFutureArgv;
|
|
||||||
|
|
||||||
using JSFutureReturn = std::function<JSOSFutureArgv(JSContext *)>;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
struct list_head link;
|
|
||||||
std::shared_future<JSFutureReturn> future;
|
|
||||||
JSValue resolve;
|
|
||||||
JSValue reject;
|
|
||||||
} JSOSFuture;
|
|
||||||
|
|
||||||
typedef struct JSThreadState
|
|
||||||
{
|
|
||||||
struct list_head os_future; /* list of JSOSFuture.link */
|
|
||||||
std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel;
|
|
||||||
} JSThreadState;
|
|
||||||
|
|
||||||
static JSValue js_add_future(Value resolve, Value reject, std::shared_future<JSFutureReturn> future)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = JS_GetRuntime(resolve.ctx);
|
|
||||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
|
||||||
JSValueConst jsResolve, jsReject;
|
|
||||||
JSOSFuture *th;
|
|
||||||
JSValue obj;
|
|
||||||
|
|
||||||
jsResolve = resolve.v;
|
|
||||||
if (!JS_IsFunction(resolve.ctx, jsResolve))
|
|
||||||
return JS_ThrowTypeError(resolve.ctx, "resolve not a function");
|
|
||||||
jsReject = reject.v;
|
|
||||||
if (!JS_IsFunction(reject.ctx, jsReject))
|
|
||||||
return JS_ThrowTypeError(reject.ctx, "reject not a function");
|
|
||||||
obj = JS_NewObjectClass(resolve.ctx, js_dart_promise_class_id);
|
|
||||||
if (JS_IsException(obj))
|
|
||||||
return obj;
|
|
||||||
th = (JSOSFuture *)js_mallocz(resolve.ctx, sizeof(*th));
|
|
||||||
if (!th)
|
|
||||||
{
|
|
||||||
JS_FreeValue(resolve.ctx, obj);
|
|
||||||
return JS_EXCEPTION;
|
|
||||||
}
|
|
||||||
th->future = future;
|
|
||||||
th->resolve = JS_DupValue(resolve.ctx, jsResolve);
|
|
||||||
th->reject = JS_DupValue(reject.ctx, jsReject);
|
|
||||||
list_add_tail(&th->link, &ts->os_future);
|
|
||||||
JS_SetOpaque(obj, th);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValue js_dart_future(Value resolve, Value reject, std::string name, std::string args)
|
|
||||||
{
|
|
||||||
auto promise = new std::promise<JSFutureReturn>();
|
|
||||||
JSRuntime *rt = JS_GetRuntime(resolve.ctx);
|
|
||||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
|
||||||
ts->channel->InvokeMethod(
|
|
||||||
name,
|
|
||||||
std::make_unique<flutter::EncodableValue>(args),
|
|
||||||
std::make_unique<flutter::MethodResultFunctions<flutter::EncodableValue>>(
|
|
||||||
(flutter::ResultHandlerSuccess<flutter::EncodableValue>)[promise](
|
|
||||||
const flutter::EncodableValue *result) {
|
|
||||||
promise->set_value((JSFutureReturn)[rep = std::get<std::string>(*result)](JSContext * ctx) {
|
|
||||||
JSValue *ret = new JSValue{JS_NewString(ctx, rep.c_str())};
|
|
||||||
return JSOSFutureArgv{1, ret};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(flutter::ResultHandlerError<flutter::EncodableValue>)[promise](
|
|
||||||
const std::string &error_code,
|
|
||||||
const std::string &error_message,
|
|
||||||
const flutter::EncodableValue *error_details) {
|
|
||||||
promise->set_value((JSFutureReturn)[error_message](JSContext * ctx) {
|
|
||||||
JSValue *ret = new JSValue{JS_NewString(ctx, error_message.c_str())};
|
|
||||||
return JSOSFutureArgv{-1, ret};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(flutter::ResultHandlerNotImplemented<flutter::EncodableValue>)[promise]() {
|
|
||||||
promise->set_value((JSFutureReturn)[](JSContext * ctx) {
|
|
||||||
JSValue *ret = new JSValue{JS_NewString(ctx, "NotImplemented")};
|
|
||||||
return JSOSFutureArgv{-1, ret};
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
return js_add_future(resolve, reject, promise->get_future());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unlink_future(JSRuntime *rt, JSOSFuture *th)
|
|
||||||
{
|
|
||||||
if (th->link.prev)
|
|
||||||
{
|
|
||||||
list_del(&th->link);
|
|
||||||
th->link.prev = th->link.next = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_future(JSRuntime *rt, JSOSFuture *th)
|
|
||||||
{
|
|
||||||
JS_FreeValueRT(rt, th->resolve);
|
|
||||||
JS_FreeValueRT(rt, th->reject);
|
|
||||||
js_free_rt(rt, th);
|
|
||||||
}
|
|
||||||
|
|
||||||
void js_init_handlers(JSRuntime *rt, std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel)
|
|
||||||
{
|
|
||||||
JSThreadState *ts = (JSThreadState *)malloc(sizeof(*ts));
|
|
||||||
if (!ts)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Could not allocate memory for the worker");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
memset(ts, 0, sizeof(*ts));
|
|
||||||
init_list_head(&ts->os_future);
|
|
||||||
ts->channel = channel;
|
|
||||||
|
|
||||||
JS_SetRuntimeOpaque(rt, ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
void js_free_handlers(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
|
||||||
struct list_head *el, *el1;
|
|
||||||
|
|
||||||
list_for_each_safe(el, el1, &ts->os_future)
|
|
||||||
{
|
|
||||||
JSOSFuture *th = list_entry(el, JSOSFuture, link);
|
|
||||||
th->future.get();
|
|
||||||
unlink_future(rt, th);
|
|
||||||
free_future(rt, th);
|
|
||||||
}
|
|
||||||
ts->channel = nullptr;
|
|
||||||
free(ts);
|
|
||||||
JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void call_handler(JSContext *ctx, JSValueConst func, int count, JSValue *argv)
|
|
||||||
{
|
|
||||||
JSValue ret, func1;
|
|
||||||
/* 'func' might be destroyed when calling itself (if it frees the
|
|
||||||
handler), so must take extra care */
|
|
||||||
func1 = JS_DupValue(ctx, func);
|
|
||||||
ret = JS_Call(ctx, func1, JS_UNDEFINED, count, argv);
|
|
||||||
JS_FreeValue(ctx, func1);
|
|
||||||
if (JS_IsException(ret))
|
|
||||||
throw exception{};
|
|
||||||
JS_FreeValue(ctx, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int js_dart_poll(JSContext *ctx)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
||||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
|
||||||
struct list_head *el;
|
|
||||||
|
|
||||||
/* XXX: handle signals if useful */
|
|
||||||
|
|
||||||
if (list_empty(&ts->os_future))
|
|
||||||
return -1; /* no more events */
|
|
||||||
|
|
||||||
/* XXX: only timers and basic console input are supported */
|
|
||||||
if (!list_empty(&ts->os_future))
|
|
||||||
{
|
|
||||||
list_for_each(el, &ts->os_future)
|
|
||||||
{
|
|
||||||
JSOSFuture *th = list_entry(el, JSOSFuture, link);
|
|
||||||
if (th->future._Is_ready())
|
|
||||||
{
|
|
||||||
JSOSFutureArgv argv = th->future.get()(ctx);
|
|
||||||
JSValue resolve, reject;
|
|
||||||
int64_t delay;
|
|
||||||
/* the timer expired */
|
|
||||||
resolve = th->resolve;
|
|
||||||
th->resolve = JS_UNDEFINED;
|
|
||||||
reject = th->reject;
|
|
||||||
th->reject = JS_UNDEFINED;
|
|
||||||
unlink_future(rt, th);
|
|
||||||
free_future(rt, th);
|
|
||||||
call_handler(ctx, argv.count < 0 ? reject : resolve, abs(argv.count), argv.argv);
|
|
||||||
for (int i = 0; i < abs(argv.count); ++i)
|
|
||||||
JS_FreeValue(ctx, argv.argv[i]);
|
|
||||||
JS_FreeValue(ctx, resolve);
|
|
||||||
JS_FreeValue(ctx, reject);
|
|
||||||
delete argv.argv;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace qjs
|
|
@@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Description:
|
|
||||||
* @Author: ekibun
|
|
||||||
* @Date: 2020-08-08 10:30:59
|
|
||||||
* @LastEditors: ekibun
|
|
||||||
* @LastEditTime: 2020-08-08 17:05:22
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <queue>
|
|
||||||
#include <thread>
|
|
||||||
#include <atomic>
|
|
||||||
#include <future>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "js_dart_promise.hpp"
|
|
||||||
#include "quickjs/quickjspp.hpp"
|
|
||||||
|
|
||||||
namespace qjs
|
|
||||||
{
|
|
||||||
struct EngineTask
|
|
||||||
{
|
|
||||||
std::string command;
|
|
||||||
std::string name;
|
|
||||||
std::function<void(std::string)> resolve;
|
|
||||||
std::function<void(std::string)> reject;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EngineTaskResolver
|
|
||||||
{
|
|
||||||
Value result;
|
|
||||||
std::function<void(std::string)> resolve;
|
|
||||||
std::function<void(std::string)> reject;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string getStackTrack(Value exc)
|
|
||||||
{
|
|
||||||
std::string err = (std::string)exc;
|
|
||||||
if ((bool)exc["stack"])
|
|
||||||
err += "\n" + (std::string)exc["stack"];
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Engine
|
|
||||||
{
|
|
||||||
// 引擎线程
|
|
||||||
std::thread thread;
|
|
||||||
// 任务队列
|
|
||||||
std::queue<EngineTask> tasks;
|
|
||||||
// 同步
|
|
||||||
std::mutex m_lock;
|
|
||||||
// 是否关闭提交
|
|
||||||
std::atomic<bool> stoped;
|
|
||||||
|
|
||||||
void handleException(qjs::Value exc)
|
|
||||||
{
|
|
||||||
std::cout << getStackTrack(exc) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline Engine(std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel) : stoped{false}
|
|
||||||
{
|
|
||||||
thread = std::thread([this, channel] { // 工作线程函数
|
|
||||||
// 创建运行环境
|
|
||||||
Runtime rt;
|
|
||||||
js_init_handlers(rt.rt, channel);
|
|
||||||
Context ctx(rt);
|
|
||||||
auto &module = ctx.addModule("__DartImpl");
|
|
||||||
module.function<&js_dart_future>("__invoke");
|
|
||||||
ctx.eval(
|
|
||||||
R"xxx(
|
|
||||||
import * as __DartImpl from "__DartImpl";
|
|
||||||
globalThis.dart = (method, ...args) => new Promise((res, rej) =>
|
|
||||||
__DartImpl.__invoke((v) => res(JSON.parse(v)), rej, method, JSON.stringify(args)));
|
|
||||||
)xxx",
|
|
||||||
"<dart>", JS_EVAL_TYPE_MODULE);
|
|
||||||
std::vector<EngineTaskResolver> unresolvedTask;
|
|
||||||
// 循环
|
|
||||||
while (!this->stoped)
|
|
||||||
{
|
|
||||||
// 获取待执行的task
|
|
||||||
EngineTask task;
|
|
||||||
{ // 获取一个待执行的 task
|
|
||||||
std::unique_lock<std::mutex> lock{this->m_lock}; // unique_lock 相比 lock_guard 的好处是:可以随时 unlock() 和 lock()
|
|
||||||
if (!this->tasks.empty())
|
|
||||||
{
|
|
||||||
task = this->tasks.front(); // 取一个 task
|
|
||||||
this->tasks.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 执行task
|
|
||||||
if (task.resolve)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ctx.global()["__evalstr"] = JS_NewString(ctx.ctx, task.command.c_str());
|
|
||||||
Value ret = ctx.eval(
|
|
||||||
R"xxx(
|
|
||||||
(() => {
|
|
||||||
const __ret = Promise.resolve(eval(__evalstr))
|
|
||||||
.then(v => {
|
|
||||||
__ret.__value = v;
|
|
||||||
__ret.__resolved = true;
|
|
||||||
}).catch(e => {
|
|
||||||
__ret.__error = e;
|
|
||||||
__ret.__rejected = true;
|
|
||||||
});
|
|
||||||
return __ret;
|
|
||||||
})()
|
|
||||||
)xxx",
|
|
||||||
task.name.c_str());
|
|
||||||
unresolvedTask.emplace_back(EngineTaskResolver{ret, std::move(task.resolve), std::move(task.reject)});
|
|
||||||
}
|
|
||||||
catch (exception e)
|
|
||||||
{
|
|
||||||
task.reject(getStackTrack(ctx.getException()));
|
|
||||||
}
|
|
||||||
// 执行microtask
|
|
||||||
JSContext *pctx;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int err = JS_ExecutePendingJob(rt.rt, &pctx);
|
|
||||||
if (err <= 0)
|
|
||||||
{
|
|
||||||
if (err < 0)
|
|
||||||
std::cout << getStackTrack(ctx.getException()) << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO 检查promise状态
|
|
||||||
for (auto it = unresolvedTask.begin(); it != unresolvedTask.end();)
|
|
||||||
{
|
|
||||||
bool finished = false;
|
|
||||||
if (it->result["__resolved"])
|
|
||||||
{
|
|
||||||
it->resolve((std::string)it->result["__value"]);
|
|
||||||
finished = true;
|
|
||||||
};
|
|
||||||
if (it->result["__rejected"])
|
|
||||||
{
|
|
||||||
it->reject(getStackTrack(it->result["__error"]));
|
|
||||||
finished = true;
|
|
||||||
};
|
|
||||||
if (finished)
|
|
||||||
it = unresolvedTask.erase(it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
// 检查dart交互
|
|
||||||
bool idle = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
idle = js_dart_poll(ctx.ctx);
|
|
||||||
}
|
|
||||||
catch (exception e)
|
|
||||||
{
|
|
||||||
handleException(ctx.getException());
|
|
||||||
}
|
|
||||||
// 空闲时reject所有task
|
|
||||||
if (idle && !JS_IsJobPending(rt.rt) && !unresolvedTask.empty())
|
|
||||||
{
|
|
||||||
for (EngineTaskResolver &task : unresolvedTask)
|
|
||||||
{
|
|
||||||
task.reject("Promise cannot resolve");
|
|
||||||
}
|
|
||||||
unresolvedTask.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
js_free_handlers(rt.rt);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
inline ~Engine()
|
|
||||||
{
|
|
||||||
stoped.store(true);
|
|
||||||
if (thread.joinable())
|
|
||||||
thread.join(); // 等待任务结束, 前提:线程一定会执行完
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// 提交一个任务
|
|
||||||
void commit(EngineTask task)
|
|
||||||
{
|
|
||||||
if (stoped.load()) // stop == true ??
|
|
||||||
throw std::runtime_error("commit on stopped engine.");
|
|
||||||
{ // 添加任务到队列
|
|
||||||
std::lock_guard<std::mutex> lock{m_lock}; //对当前块的语句加锁 lock_guard 是 mutex 的 stack 封装类,构造的时候 lock(),析构的时候 unlock()
|
|
||||||
tasks.emplace(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace qjs
|
|
@@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Linux klist like system
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016-2017 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef LIST_H
|
|
||||||
#define LIST_H
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#include <stddef.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct list_head {
|
|
||||||
struct list_head *prev;
|
|
||||||
struct list_head *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LIST_HEAD_INIT(el) { &(el), &(el) }
|
|
||||||
|
|
||||||
/* return the pointer of type 'type *' containing 'el' as field 'member' */
|
|
||||||
#define list_entry(el, type, member) \
|
|
||||||
((type *)((uint8_t *)(el) - offsetof(type, member)))
|
|
||||||
|
|
||||||
static inline void init_list_head(struct list_head *head)
|
|
||||||
{
|
|
||||||
head->prev = head;
|
|
||||||
head->next = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* insert 'el' between 'prev' and 'next' */
|
|
||||||
static inline void __list_add(struct list_head *el,
|
|
||||||
struct list_head *prev, struct list_head *next)
|
|
||||||
{
|
|
||||||
prev->next = el;
|
|
||||||
el->prev = prev;
|
|
||||||
el->next = next;
|
|
||||||
next->prev = el;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add 'el' at the head of the list 'head' (= after element head) */
|
|
||||||
static inline void list_add(struct list_head *el, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(el, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add 'el' at the end of the list 'head' (= before element head) */
|
|
||||||
static inline void list_add_tail(struct list_head *el, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(el, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void list_del(struct list_head *el)
|
|
||||||
{
|
|
||||||
struct list_head *prev, *next;
|
|
||||||
prev = el->prev;
|
|
||||||
next = el->next;
|
|
||||||
prev->next = next;
|
|
||||||
next->prev = prev;
|
|
||||||
el->prev = NULL; /* fail safe */
|
|
||||||
el->next = NULL; /* fail safe */
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int list_empty(struct list_head *el)
|
|
||||||
{
|
|
||||||
return el->next == el;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define list_for_each(el, head) \
|
|
||||||
for(el = (head)->next; el != (head); el = el->next)
|
|
||||||
|
|
||||||
#define list_for_each_safe(el, el1, head) \
|
|
||||||
for(el = (head)->next, el1 = el->next; el != (head); \
|
|
||||||
el = el1, el1 = el->next)
|
|
||||||
|
|
||||||
#define list_for_each_prev(el, head) \
|
|
||||||
for(el = (head)->prev; el != (head); el = el->prev)
|
|
||||||
|
|
||||||
#define list_for_each_prev_safe(el, el1, head) \
|
|
||||||
for(el = (head)->prev, el1 = el->prev; el != (head); \
|
|
||||||
el = el1, el1 = el->prev)
|
|
||||||
|
|
||||||
#endif /* LIST_H */
|
|
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* QuickJS C library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef QUICKJS_LIBC_H
|
|
||||||
#define QUICKJS_LIBC_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "quickjs.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
|
|
||||||
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
|
|
||||||
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
|
|
||||||
void js_std_loop(JSContext *ctx);
|
|
||||||
void js_std_init_handlers(JSRuntime *rt);
|
|
||||||
void js_std_free_handlers(JSRuntime *rt);
|
|
||||||
void js_std_dump_error(JSContext *ctx);
|
|
||||||
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
|
|
||||||
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
|
|
||||||
JS_BOOL use_realpath, JS_BOOL is_main);
|
|
||||||
JSModuleDef *js_module_loader(JSContext *ctx,
|
|
||||||
const char *module_name, void *opaque);
|
|
||||||
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
|
||||||
int flags);
|
|
||||||
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
|
||||||
JSValueConst reason,
|
|
||||||
JS_BOOL is_handled, void *opaque);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" { */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* QUICKJS_LIBC_H */
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user