add function channel

This commit is contained in:
ekibun
2020-08-15 14:52:53 +08:00
parent 2731f97c63
commit 7b35868c5c
12 changed files with 313 additions and 52 deletions

13
.vscode/launch.json vendored
View File

@@ -4,9 +4,20 @@
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"name": "(Windows) 启动",
"type": "cppvsdbg",
"request": "launch",
"program": "example/build/windows/runner/Debug/flutter_qjs_example.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false
},
{ {
"name": "Flutter", "name": "Flutter",
"program": "lib/main.dart", "program": "example/lib/main.dart",
"request": "launch", "request": "launch",
"type": "dart" "type": "dart"
} }

View File

@@ -98,7 +98,8 @@
"numeric": "cpp", "numeric": "cpp",
"cfenv": "cpp", "cfenv": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"typeindex": "cpp" "typeindex": "cpp",
"__functional_03": "cpp"
}, },
"java.configuration.updateBuildConfiguration": "interactive" "java.configuration.updateBuildConfiguration": "interactive"
} }

22
LICENSE
View File

@@ -1 +1,21 @@
TODO: Add your license here. MIT License
Copyright (c) 2019 https://github.com/czy0729
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.

View File

@@ -1,6 +1,6 @@
# flutter_qjs # flutter_qjs
A new flutter plugin project. A quickjs engine for flutter.
## Getting Started ## Getting Started

View File

@@ -3,16 +3,17 @@
* @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-13 13:47:16 * @LastEditTime: 2020-08-15 14:45:00
*/ */
#pragma once #pragma once
#include "quickjspp/quickjspp.hpp" #include "quickjspp/quickjspp.hpp"
#include "quickjspp/quickjs/list.h"
#include <future> #include <future>
#include <string.h> #include <string.h>
namespace qjs namespace qjs
{ {
#include "quickjspp/quickjs/list.h"
static JSClassID js_dart_promise_class_id; static JSClassID js_dart_promise_class_id;
typedef struct typedef struct
@@ -22,11 +23,12 @@ namespace qjs
} JSOSFutureArgv; } JSOSFutureArgv;
using JSFutureReturn = std::function<JSOSFutureArgv(JSContext *)>; using JSFutureReturn = std::function<JSOSFutureArgv(JSContext *)>;
using DartChannel = std::function<std::future<JSFutureReturn>(std::string, std::string)>; using DartChannel = std::function<std::promise<JSFutureReturn> *(std::string, Value)>;
typedef struct typedef struct
{ {
struct list_head link; struct list_head link;
std::promise<JSFutureReturn> *promise;
std::shared_future<JSFutureReturn> future; std::shared_future<JSFutureReturn> future;
JSValue resolve; JSValue resolve;
JSValue reject; JSValue reject;
@@ -35,10 +37,10 @@ namespace qjs
typedef struct JSThreadState typedef struct JSThreadState
{ {
struct list_head os_future; /* list of JSOSFuture.link */ struct list_head os_future; /* list of JSOSFuture.link */
std::function<std::future<JSFutureReturn>(std::string, std::string)> channel; DartChannel channel;
} JSThreadState; } JSThreadState;
static JSValue js_add_future(Value resolve, Value reject, std::shared_future<JSFutureReturn> future) static JSValue js_add_future(Value resolve, Value reject, std::promise<JSFutureReturn> *promise)
{ {
JSRuntime *rt = JS_GetRuntime(resolve.ctx); JSRuntime *rt = JS_GetRuntime(resolve.ctx);
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt); JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
@@ -61,7 +63,8 @@ namespace qjs
JS_FreeValue(resolve.ctx, obj); JS_FreeValue(resolve.ctx, obj);
return JS_EXCEPTION; return JS_EXCEPTION;
} }
th->future = future; th->promise = promise;
th->future = promise->get_future();
th->resolve = JS_DupValue(resolve.ctx, jsResolve); th->resolve = JS_DupValue(resolve.ctx, jsResolve);
th->reject = JS_DupValue(reject.ctx, jsReject); th->reject = JS_DupValue(reject.ctx, jsReject);
list_add_tail(&th->link, &ts->os_future); list_add_tail(&th->link, &ts->os_future);
@@ -69,7 +72,7 @@ namespace qjs
return obj; return obj;
} }
JSValue js_dart_future(Value resolve, Value reject, std::string name, std::string args) JSValue js_dart_future(Value resolve, Value reject, std::string name, Value args)
{ {
JSRuntime *rt = JS_GetRuntime(resolve.ctx); JSRuntime *rt = JS_GetRuntime(resolve.ctx);
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt); JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
@@ -116,6 +119,7 @@ namespace qjs
{ {
JSOSFuture *th = list_entry(el, JSOSFuture, link); JSOSFuture *th = list_entry(el, JSOSFuture, link);
th->future.get(); th->future.get();
delete th->promise;
unlink_future(rt, th); unlink_future(rt, th);
free_future(rt, th); free_future(rt, th);
} }
@@ -159,7 +163,6 @@ namespace qjs
{ {
JSOSFutureArgv argv = th->future.get()(ctx); JSOSFutureArgv argv = th->future.get()(ctx);
JSValue resolve, reject; JSValue resolve, reject;
int64_t delay;
/* the timer expired */ /* the timer expired */
resolve = th->resolve; resolve = th->resolve;
th->resolve = JS_UNDEFINED; th->resolve = JS_UNDEFINED;

View File

@@ -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-13 13:47:28 * @LastEditTime: 2020-08-15 13:13:43
*/ */
#pragma once #pragma once
@@ -21,8 +21,7 @@ namespace qjs
{ {
struct EngineTask struct EngineTask
{ {
std::string command; std::function<Value(Context&)> invoke;
std::string name;
std::function<void(std::string)> resolve; std::function<void(std::string)> resolve;
std::function<void(std::string)> reject; std::function<void(std::string)> reject;
}; };
@@ -72,10 +71,26 @@ namespace qjs
R"xxx( R"xxx(
import * as __DartImpl from "__DartImpl"; import * as __DartImpl from "__DartImpl";
globalThis.dart = (method, ...args) => new Promise((res, rej) => globalThis.dart = (method, ...args) => new Promise((res, rej) =>
__DartImpl.__invoke((v) => res(JSON.parse(v)), rej, method, JSON.stringify(args))); __DartImpl.__invoke(res, rej, method, args));
)xxx", )xxx",
"<dart>", JS_EVAL_TYPE_MODULE); "<dart>", JS_EVAL_TYPE_MODULE);
std::vector<EngineTaskResolver> unresolvedTask; std::vector<EngineTaskResolver> unresolvedTask;
Value promiseWrapper = ctx.eval(
R"xxx(
(value) => {
const __ret = Promise.resolve(value)
.then(v => {
__ret.__value = v;
__ret.__resolved = true;
}).catch(e => {
__ret.__error = e;
__ret.__rejected = true;
});
return __ret;
}
)xxx",
"<PromiseWrapper>", JS_EVAL_TYPE_GLOBAL);
// 循环 // 循环
while (!this->stoped) while (!this->stoped)
{ {
@@ -93,25 +108,11 @@ namespace qjs
if (task.resolve) if (task.resolve)
try try
{ {
ctx.global()["__evalstr"] = JS_NewString(ctx.ctx, task.command.c_str()); Value val = task.invoke(ctx);
Value ret = ctx.eval( Value ret = Value{ctx.ctx, JS_Call(ctx.ctx, promiseWrapper.v, ctx.global().v, 1, &(val.v))};
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)}); unresolvedTask.emplace_back(EngineTaskResolver{ret, std::move(task.resolve), std::move(task.reject)});
} }
catch (exception e) catch (exception)
{ {
task.reject(getStackTrack(ctx.getException())); task.reject(getStackTrack(ctx.getException()));
} }
@@ -152,16 +153,16 @@ namespace qjs
{ {
idle = js_dart_poll(ctx.ctx); idle = js_dart_poll(ctx.ctx);
} }
catch (exception e) catch (exception)
{ {
handleException(ctx.getException()); handleException(ctx.getException());
} }
// 空闲时reject所有task // 空闲时reject所有task
if (idle && !JS_IsJobPending(rt.rt) && !unresolvedTask.empty()) if (idle && !JS_IsJobPending(rt.rt) && !unresolvedTask.empty())
{ {
for (EngineTaskResolver &task : unresolvedTask) for (EngineTaskResolver &_task : unresolvedTask)
{ {
task.reject("Promise cannot resolve"); _task.reject("Promise cannot resolve");
} }
unresolvedTask.clear(); unresolvedTask.clear();
} }

View File

@@ -3,7 +3,7 @@
* @Author: ekibun * @Author: ekibun
* @Date: 2020-07-18 23:28:55 * @Date: 2020-07-18 23:28:55
* @LastEditors: ekibun * @LastEditors: ekibun
* @LastEditTime: 2020-08-08 17:38:48 * @LastEditTime: 2020-08-15 14:01:09
*/ */
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -48,6 +48,8 @@ class _TestPageState extends State<TestPage> {
case "http": case "http":
Response response = await Dio().get(arg[0]); Response response = await Dio().get(arg[0]);
return response.data; return response.data;
case "hello":
return await arg[0](["hello: "]);
default: default:
} }
}; };

View File

@@ -32,7 +32,7 @@ add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets. # Compilation settings that should be applied to most targets.
function(APPLY_STANDARD_SETTINGS TARGET) function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX- /wd"4100") target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>") target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")

View File

@@ -3,10 +3,9 @@
* @Author: ekibun * @Author: ekibun
* @Date: 2020-08-08 08:29:09 * @Date: 2020-08-08 08:29:09
* @LastEditors: ekibun * @LastEditors: ekibun
* @LastEditTime: 2020-08-08 17:40:35 * @LastEditTime: 2020-08-15 13:58:11
*/ */
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@@ -19,12 +18,30 @@ class FlutterJs {
final int engineId = await _channel.invokeMethod("initEngine"); final int engineId = await _channel.invokeMethod("initEngine");
_channel.setMethodCallHandler((call) async { _channel.setMethodCallHandler((call) async {
if (methodHandler == null) return call.noSuchMethod(null); if (methodHandler == null) return call.noSuchMethod(null);
List args = jsonDecode(call.arguments); return await methodHandler(call.method, _wrapFunctionArguments(call.arguments));
return jsonEncode(await methodHandler(call.method, args));
}); });
return engineId; return engineId;
} }
static dynamic _wrapFunctionArguments(dynamic val) {
if (val is List) {
for (var i = 0; i < val.length; ++i) {
val[i] = _wrapFunctionArguments(val[i]);
}
} else if (val is Map) {
if (val["__js_function__"] != 0) {
var functionId = val["__js_function__"];
return (List<dynamic> args) async {
var arguments = {"function": functionId, "arguments": args};
return await _channel.invokeMethod("call", arguments);
};
}else for(var key in val.keys) {
val[key] = _wrapFunctionArguments(val[key]);
}
}
return val;
}
static Future<String> evaluate(String command, String name) async { static Future<String> evaluate(String command, String name) async {
var arguments = {"script": command, "name": command}; var arguments = {"script": command, "name": command};
final String jsResult = await _channel.invokeMethod("evaluate", arguments); final String jsResult = await _channel.invokeMethod("evaluate", arguments);

176
windows/dart_js_wrapper.hpp Normal file
View File

@@ -0,0 +1,176 @@
/*
* @Description:
* @Author: ekibun
* @Date: 2020-08-14 21:45:02
* @LastEditors: ekibun
* @LastEditTime: 2020-08-15 14:08:04
*/
#include "../cxx/js_engine.hpp"
#include <flutter/standard_method_codec.h>
#include <variant>
namespace std
{
template <>
struct hash<qjs::Value>
{
std::size_t operator()(const qjs::Value &key) const
{
return std::hash<std::string>()((std::string)key);
}
};
template <>
struct hash<flutter::EncodableValue>
{
std::size_t operator()(const flutter::EncodableValue &key) const
{
return key.index();
}
};
} // namespace std
namespace qjs
{
JSValue dartToJsAtom(JSContext *ctx, flutter::EncodableValue val)
{
if (std::holds_alternative<bool>(val))
return JS_NewBool(ctx, std::get<bool>(val));
if (std::holds_alternative<int32_t>(val))
return JS_NewInt32(ctx, std::get<int32_t>(val));
if (std::holds_alternative<int64_t>(val))
return JS_NewInt64(ctx, std::get<int64_t>(val));
if (std::holds_alternative<double>(val))
return JS_NewFloat64(ctx, std::get<double>(val));
if (std::holds_alternative<std::string>(val))
return JS_NewString(ctx, std::get<std::string>(val).c_str());
return JS_UNDEFINED;
}
JSValue dartToJs(JSContext *ctx, flutter::EncodableValue val, std::unordered_map<flutter::EncodableValue, JSValue> cache)
{
if (val.IsNull())
return JS_UNDEFINED;
if (cache.find(val) != cache.end())
return cache[val];
{
JSValue atomValue = dartToJsAtom(ctx, val);
if (!JS_IsUndefined(atomValue))
return atomValue;
}
if (std::holds_alternative<std::vector<uint8_t>>(val))
{
auto buf = std::get<std::vector<uint8_t>>(val);
return JS_NewArrayBufferCopy(ctx, buf.data(), buf.size());
}
if (std::holds_alternative<std::vector<int32_t>>(val))
{
auto buf = std::get<std::vector<int32_t>>(val);
return JS_NewArrayBufferCopy(ctx, (uint8_t *)buf.data(), buf.size() * 4);
}
if (std::holds_alternative<std::vector<int64_t>>(val))
{
auto buf = std::get<std::vector<int64_t>>(val);
return JS_NewArrayBufferCopy(ctx, (uint8_t *)buf.data(), buf.size() * 8);
}
if (std::holds_alternative<std::vector<double>>(val))
{
auto buf = std::get<std::vector<double>>(val);
JSValue array = JS_NewArray(ctx);
cache[val] = array;
auto size = (uint32_t)buf.size();
for (uint32_t i = 0; i < size; i++)
JS_DefinePropertyValue(
ctx, array, JS_NewAtomUInt32(ctx, i), JS_NewFloat64(ctx, buf[i]),
JS_PROP_C_W_E);
return array;
}
if (std::holds_alternative<flutter::EncodableList>(val))
{
auto list = std::get<flutter::EncodableList>(val);
JSValue array = JS_NewArray(ctx);
cache[val] = array;
auto size = (uint32_t)list.size();
for (uint32_t i = 0; i < size; i++)
JS_DefinePropertyValue(
ctx, array, JS_NewAtomUInt32(ctx, i), dartToJs(ctx, list[i], cache),
JS_PROP_C_W_E);
return array;
}
if (std::holds_alternative<flutter::EncodableMap>(val))
{
auto map = std::get<flutter::EncodableMap>(val);
JSValue obj = JS_NewObject(ctx);
cache[val] = obj;
for (auto iter = map.begin(); iter != map.end(); ++iter)
JS_DefinePropertyValue(
ctx, obj, JS_ValueToAtom(ctx, dartToJs(ctx, iter->first, cache)), dartToJs(ctx, iter->second, cache),
JS_PROP_C_W_E);
return obj;
}
return JS_UNDEFINED;
}
flutter::EncodableValue jsToDart(Value val, std::unordered_map<Value, flutter::EncodableValue> cache)
{
if (cache.find(val) != cache.end())
return cache[val];
if (JS_IsBool(val.v))
return (bool)val;
if (JS_IsNumber(val.v))
return (double)val;
if (JS_IsString(val.v))
return (std::string)val;
{ // ArrayBuffer
size_t size;
uint8_t *buf = JS_GetArrayBuffer(val.ctx, &size, val.v);
if (buf)
return (std::vector<uint8_t>(buf, buf + size));
}
flutter::EncodableValue ret;
if (JS_IsUndefined(val.v) || JS_IsNull(val.v) || JS_IsUninitialized(val.v))
goto exception;
if (JS_IsObject(val.v))
{
if (JS_IsFunction(val.ctx, val.v))
{
flutter::EncodableMap retMap;
retMap[std::string("__js_function__")] = (int64_t) new JSValue { JS_DupValue(val.ctx, val.v) };
ret = retMap;
}
else if (JS_IsArray(val.ctx, val.v) > 0)
{
flutter::EncodableList retList;
cache[val] = retList;
uint32_t arrlen = (uint32_t)val["length"];
for (uint32_t i = 0; i < arrlen; i++)
{
retList.push_back(jsToDart(val[i], cache));
}
ret = retList;
}
else
{
qjs::JSPropertyEnum *ptab;
uint32_t plen;
if (JS_GetOwnPropertyNames(val.ctx, &ptab, &plen, val.v, -1))
goto exception;
flutter::EncodableMap retMap;
cache[val] = retMap;
for (uint32_t i = 0; i < plen; i++)
{
retMap[jsToDart({val.ctx, JS_AtomToValue(val.ctx, ptab[i].atom)}, cache)] =
jsToDart({val.ctx, JS_GetProperty(val.ctx, val.v, ptab[i].atom)}, cache);
JS_FreeAtom(val.ctx, ptab[i].atom);
}
js_free(val.ctx, ptab);
ret = retMap;
}
goto done;
}
exception:
ret = flutter::EncodableValue();
done:
return ret;
}
} // namespace qjs

View File

@@ -8,7 +8,7 @@
#include <flutter/standard_method_codec.h> #include <flutter/standard_method_codec.h>
#include <flutter/method_result_functions.h> #include <flutter/method_result_functions.h>
#include "../cxx/js_engine.hpp" #include "dart_js_wrapper.hpp"
namespace namespace
{ {
@@ -30,17 +30,17 @@ 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) std::promise<qjs::JSFutureReturn> *invokeChannelMethod(std::string name, qjs::Value args)
{ {
auto promise = new std::promise<qjs::JSFutureReturn>(); auto promise = new std::promise<qjs::JSFutureReturn>();
channel->InvokeMethod( channel->InvokeMethod(
name, name,
std::make_unique<flutter::EncodableValue>(args), std::make_unique<flutter::EncodableValue>(qjs::jsToDart(args, std::unordered_map<qjs::Value, flutter::EncodableValue>())),
std::make_unique<flutter::MethodResultFunctions<flutter::EncodableValue>>( std::make_unique<flutter::MethodResultFunctions<flutter::EncodableValue>>(
(flutter::ResultHandlerSuccess<flutter::EncodableValue>)[promise]( (flutter::ResultHandlerSuccess<flutter::EncodableValue>)[promise](
const flutter::EncodableValue *result) { const flutter::EncodableValue *result) {
promise->set_value((qjs::JSFutureReturn)[rep = std::get<std::string>(*result)](qjs::JSContext * ctx) { promise->set_value((qjs::JSFutureReturn)[result = result ? *result : flutter::EncodableValue()](qjs::JSContext * ctx) {
qjs::JSValue *ret = new qjs::JSValue{JS_NewString(ctx, rep.c_str())}; qjs::JSValue *ret = new qjs::JSValue{qjs::dartToJs(ctx, result, std::unordered_map<flutter::EncodableValue, qjs::JSValue>())};
return qjs::JSOSFutureArgv{1, ret}; return qjs::JSOSFutureArgv{1, ret};
}); });
}, },
@@ -59,7 +59,7 @@ namespace
return qjs::JSOSFutureArgv{-1, ret}; return qjs::JSOSFutureArgv{-1, ret};
}); });
})); }));
return promise->get_future(); return promise;
} }
// static // static
@@ -111,7 +111,7 @@ namespace
if (method_call.method_name().compare("initEngine") == 0) if (method_call.method_name().compare("initEngine") == 0)
{ {
engine = new qjs::Engine((qjs::DartChannel)invokeChannelMethod); engine = new qjs::Engine((qjs::DartChannel)invokeChannelMethod);
flutter::EncodableValue response((long)engine); flutter::EncodableValue response = (int64_t)engine;
result->Success(&response); result->Success(&response);
} }
else if (method_call.method_name().compare("evaluate") == 0) else if (method_call.method_name().compare("evaluate") == 0)
@@ -121,9 +121,39 @@ namespace
std::string name = std::get<std::string>(ValueOrNull(args, "name")); std::string name = std::get<std::string>(ValueOrNull(args, "name"));
auto presult = result.release(); auto presult = result.release();
engine->commit(qjs::EngineTask{ engine->commit(qjs::EngineTask{
script, name, [script, name](qjs::Context &ctx) {
return ctx.eval(script, name.c_str(), JS_EVAL_TYPE_GLOBAL);
},
[presult](std::string resolve) { [presult](std::string resolve) {
flutter::EncodableValue response(resolve); flutter::EncodableValue response = resolve;
presult->Success(&response);
},
[presult](std::string reject) {
presult->Error("FlutterJSException", reject);
}});
}
else if (method_call.method_name().compare("call") == 0)
{
flutter::EncodableMap args = *std::get_if<flutter::EncodableMap>(method_call.arguments());
qjs::JSValue *function = (qjs::JSValue *)std::get<int64_t>(ValueOrNull(args, "function"));
flutter::EncodableList arguments = std::get<flutter::EncodableList>(ValueOrNull(args, "arguments"));
auto presult = result.release();
engine->commit(qjs::EngineTask{
[function, arguments](qjs::Context &ctx) {
size_t argscount = arguments.size();
qjs::JSValue *callargs = new qjs::JSValue[argscount];
for (size_t i = 0; i < argscount; i++)
{
callargs[i] = qjs::dartToJs(ctx.ctx, arguments[i], std::unordered_map<flutter::EncodableValue, qjs::JSValue>());
}
qjs::JSValue ret = JS_Call(ctx.ctx, *function, qjs::JSValue{qjs::JSValueUnion{0}, qjs::JS_TAG_UNDEFINED}, (int)argscount, callargs);
qjs::JS_FreeValue(ctx.ctx, *function);
if (qjs::JS_IsException(ret))
throw qjs::exception{};
return qjs::Value{ctx.ctx, ret};
},
[presult](std::string resolve) {
flutter::EncodableValue response = resolve;
presult->Success(&response); presult->Success(&response);
}, },
[presult](std::string reject) { [presult](std::string reject) {