зеркало из https://github.com/microsoft/napajs.git
Merge latest changes from napa/vanilla
This commit is contained in:
Родитель
ee8e4fe673
Коммит
a0c478b8c7
|
@ -16,7 +16,7 @@ zone.execute(
|
|||
return text;
|
||||
},
|
||||
['hello world'])
|
||||
.then((result: napa.zone.ExecuteResponse) => {
|
||||
.then((result: napa.zone.Result) => {
|
||||
console.log(result.value);
|
||||
});
|
||||
```
|
||||
|
|
|
@ -20,102 +20,102 @@ TEST_CASE("zone apis", "[api]") {
|
|||
SECTION("broadcast valid javascript") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto response = zone.BroadcastSync("var i = 3 + 5;");
|
||||
auto result = zone.BroadcastSync("var i = 3 + 5;");
|
||||
|
||||
REQUIRE(response == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(result == NAPA_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
SECTION("broadcast illegal javascript") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto response = zone.BroadcastSync("var i = 3 +");
|
||||
auto result = zone.BroadcastSync("var i = 3 +");
|
||||
|
||||
REQUIRE(response == NAPA_RESPONSE_BROADCAST_SCRIPT_ERROR);
|
||||
REQUIRE(result == NAPA_RESULT_BROADCAST_SCRIPT_ERROR);
|
||||
}
|
||||
|
||||
SECTION("broadcast and execute javascript") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto responseCode = zone.BroadcastSync("function func(a, b) { return Number(a) + Number(b); }");
|
||||
REQUIRE(responseCode == NAPA_RESPONSE_SUCCESS);
|
||||
auto resultCode = zone.BroadcastSync("function func(a, b) { return Number(a) + Number(b); }");
|
||||
REQUIRE(resultCode == NAPA_RESULT_SUCCESS);
|
||||
|
||||
napa::ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("func");
|
||||
request.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
napa::FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("func");
|
||||
spec.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
|
||||
auto response = zone.ExecuteSync(request);
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "5");
|
||||
auto result = zone.ExecuteSync(spec);
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "5");
|
||||
}
|
||||
|
||||
SECTION("broadcast and execute javascript async") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise;
|
||||
std::promise<napa::Result> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
zone.Broadcast("function func(a, b) { return Number(a) + Number(b); }", [&promise, &zone](napa::ResponseCode) {
|
||||
napa::ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("func");
|
||||
request.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
zone.Broadcast("function func(a, b) { return Number(a) + Number(b); }", [&promise, &zone](napa::ResultCode) {
|
||||
napa::FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("func");
|
||||
spec.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
|
||||
zone.Execute(request, [&promise](napa::ExecuteResponse response) {
|
||||
promise.set_value(std::move(response));
|
||||
zone.Execute(spec, [&promise](napa::Result result) {
|
||||
promise.set_value(std::move(result));
|
||||
});
|
||||
});
|
||||
|
||||
auto response = future.get();
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "5");
|
||||
auto result = future.get();
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "5");
|
||||
}
|
||||
|
||||
SECTION("broadcast and execute javascript without timing out") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise;
|
||||
std::promise<napa::Result> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
// Warmup to avoid loading napajs on first call
|
||||
zone.BroadcastSync("require('napajs');");
|
||||
|
||||
zone.Broadcast("function func(a, b) { return Number(a) + Number(b); }", [&promise, &zone](napa::ResponseCode) {
|
||||
napa::ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("func");
|
||||
request.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
request.options.timeout = 100;
|
||||
zone.Broadcast("function func(a, b) { return Number(a) + Number(b); }", [&promise, &zone](napa::ResultCode) {
|
||||
napa::FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("func");
|
||||
spec.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
spec.options.timeout = 100;
|
||||
|
||||
zone.Execute(request, [&promise](napa::ExecuteResponse response) {
|
||||
promise.set_value(std::move(response));
|
||||
zone.Execute(spec, [&promise](napa::Result result) {
|
||||
promise.set_value(std::move(result));
|
||||
});
|
||||
});
|
||||
|
||||
auto response = future.get();
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "5");
|
||||
auto result = future.get();
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "5");
|
||||
}
|
||||
|
||||
SECTION("broadcast and execute javascript with exceeded timeout") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise;
|
||||
std::promise<napa::Result> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
// Warmup to avoid loading napajs on first call
|
||||
zone.BroadcastSync("require('napajs');");
|
||||
|
||||
zone.Broadcast("function func() { while(true) {} }", [&promise, &zone](napa::ResponseCode) {
|
||||
napa::ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("func");
|
||||
request.options.timeout = 200;
|
||||
zone.Broadcast("function func() { while(true) {} }", [&promise, &zone](napa::ResultCode) {
|
||||
napa::FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("func");
|
||||
spec.options.timeout = 200;
|
||||
|
||||
zone.Execute(request, [&promise](napa::ExecuteResponse response) {
|
||||
promise.set_value(std::move(response));
|
||||
zone.Execute(spec, [&promise](napa::Result result) {
|
||||
promise.set_value(std::move(result));
|
||||
});
|
||||
});
|
||||
|
||||
auto response = future.get();
|
||||
REQUIRE(response.code == NAPA_RESPONSE_TIMEOUT);
|
||||
REQUIRE(response.errorMessage == "Execute exceeded timeout");
|
||||
auto result = future.get();
|
||||
REQUIRE(result.code == NAPA_RESULT_TIMEOUT);
|
||||
REQUIRE(result.errorMessage == "Terminated due to timeout");
|
||||
}
|
||||
|
||||
SECTION("execute 2 javascript functions, one succeeds and one times out") {
|
||||
|
@ -125,66 +125,66 @@ TEST_CASE("zone apis", "[api]") {
|
|||
zone.BroadcastSync("require('napajs');");
|
||||
|
||||
auto res = zone.BroadcastSync("function f1(a, b) { return Number(a) + Number(b); }");
|
||||
REQUIRE(res == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(res == NAPA_RESULT_SUCCESS);
|
||||
res = zone.BroadcastSync("function f2() { while(true) {} }");
|
||||
REQUIRE(res == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(res == NAPA_RESULT_SUCCESS);
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise1;
|
||||
std::promise<napa::Result> promise1;
|
||||
auto future1 = promise1.get_future();
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise2;
|
||||
std::promise<napa::Result> promise2;
|
||||
auto future2 = promise2.get_future();
|
||||
|
||||
napa::ExecuteRequest request1;
|
||||
napa::FunctionSpec request1;
|
||||
request1.function = NAPA_STRING_REF("f1");
|
||||
request1.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
request1.options.timeout = 100;
|
||||
|
||||
napa::ExecuteRequest request2;
|
||||
napa::FunctionSpec request2;
|
||||
request2.function = NAPA_STRING_REF("f2");
|
||||
request2.options.timeout = 100;
|
||||
|
||||
zone.Execute(request1, [&promise1](napa::ExecuteResponse response) {
|
||||
promise1.set_value(std::move(response));
|
||||
zone.Execute(request1, [&promise1](napa::Result result) {
|
||||
promise1.set_value(std::move(result));
|
||||
});
|
||||
|
||||
zone.Execute(request2, [&promise2](napa::ExecuteResponse response) {
|
||||
promise2.set_value(std::move(response));
|
||||
zone.Execute(request2, [&promise2](napa::Result result) {
|
||||
promise2.set_value(std::move(result));
|
||||
});
|
||||
|
||||
auto response = future1.get();
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "5");
|
||||
auto result = future1.get();
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "5");
|
||||
|
||||
response = future2.get();
|
||||
REQUIRE(response.code == NAPA_RESPONSE_TIMEOUT);
|
||||
REQUIRE(response.errorMessage == "Execute exceeded timeout");
|
||||
result = future2.get();
|
||||
REQUIRE(result.code == NAPA_RESULT_TIMEOUT);
|
||||
REQUIRE(result.errorMessage == "Terminated due to timeout");
|
||||
}
|
||||
|
||||
SECTION("broadcast javascript requiring a module") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto responseCode = zone.BroadcastSync("var path = require('path'); function func() { return path.extname('test.txt'); }");
|
||||
REQUIRE(responseCode == NAPA_RESPONSE_SUCCESS);
|
||||
auto resultCode = zone.BroadcastSync("var path = require('path'); function func() { return path.extname('test.txt'); }");
|
||||
REQUIRE(resultCode == NAPA_RESULT_SUCCESS);
|
||||
|
||||
napa::ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("func");
|
||||
napa::FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("func");
|
||||
|
||||
auto response = zone.ExecuteSync(request);
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "\".txt\"");
|
||||
auto result = zone.ExecuteSync(spec);
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "\".txt\"");
|
||||
}
|
||||
|
||||
SECTION("execute function in a module") {
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
napa::ExecuteRequest request;
|
||||
request.module = NAPA_STRING_REF("path");
|
||||
request.function = NAPA_STRING_REF("extname");
|
||||
request.arguments = { NAPA_STRING_REF("\"test.txt\"") };
|
||||
napa::FunctionSpec spec;
|
||||
spec.module = NAPA_STRING_REF("path");
|
||||
spec.function = NAPA_STRING_REF("extname");
|
||||
spec.arguments = { NAPA_STRING_REF("\"test.txt\"") };
|
||||
|
||||
auto response = zone.ExecuteSync(request);
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "\".txt\"");
|
||||
auto result = zone.ExecuteSync(spec);
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "\".txt\"");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings>4100;4251;4459;4996</DisableSpecificWarnings>
|
||||
<PreprocessorDefinitions>BUILDING_NAPA_EXTENSION;NAPA_EXPORTS;BUILDING_V8_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NAPA_EXPORTS;NAPA_BINDING_EXPORTS;BUILDING_NAPA_EXTENSION;BUILDING_V8_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\test\component;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -49,30 +49,32 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\api\api.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\memory\built-in-allocators.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\async-runner.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\binary-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\core-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\javascript-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\json-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-cache.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-loader-helpers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-resolver.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\worker-context.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\binary-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\core-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\javascript-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\json-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-cache.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-loader-helpers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-resolver.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\platform\win\platform.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\platform\win\thread-local-storage.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\providers\providers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\async-complete-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\worker.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\broadcast-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\execute-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\simple-thread-pool.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\terminable-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\timeout-service.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\settings\settings-parser.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\store\store.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\zone-impl.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\v8\v8-common.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\async-complete-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\call-context.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\call-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\eval-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\napa-zone.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\node-zone.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\simple-thread-pool.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\terminable-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\timeout-service.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\worker.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\worker-context.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Core modules -->
|
||||
|
@ -82,8 +84,9 @@
|
|||
<!-- Test code -->
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\worker-tests.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\node-zone-tests.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\tasks-tests.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\worker-tests.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Test artifacts binplace -->
|
||||
|
|
|
@ -14,7 +14,7 @@ private:
|
|||
class NapaInitialization {
|
||||
public:
|
||||
NapaInitialization() {
|
||||
napa::PlatformSettings settings;
|
||||
napa::settings::PlatformSettings settings;
|
||||
settings.loggingProvider = "console";
|
||||
napa::providers::Initialize(settings);
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "zone/node-zone.h"
|
||||
|
||||
#include <future>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::zone;
|
||||
|
||||
TEST_CASE("node zone not available before init", "[node-zone]") {
|
||||
auto zone = NodeZone::Get();
|
||||
REQUIRE(zone == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("node zone delegate should work after init", "[node-zone]") {
|
||||
auto broadcast = [](const std::string& source, BroadcastCallback callback){
|
||||
callback(NAPA_RESULT_SUCCESS);
|
||||
};
|
||||
|
||||
auto execute = [](const FunctionSpec& spec, ExecuteCallback callback) {
|
||||
callback({ NAPA_RESULT_SUCCESS, "", std::string("hello world"), nullptr });
|
||||
};
|
||||
|
||||
NodeZone::Init(broadcast, execute);
|
||||
|
||||
auto zone = NodeZone::Get();
|
||||
REQUIRE(zone != nullptr);
|
||||
|
||||
{
|
||||
std::promise<ResultCode> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
zone->Broadcast("", [&promise](ResultCode resultCode) {
|
||||
promise.set_value(NAPA_RESULT_SUCCESS);
|
||||
});
|
||||
|
||||
REQUIRE(future.get() == NAPA_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
{
|
||||
std::promise<Result> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
FunctionSpec spec;
|
||||
zone->Execute(spec, [&promise](Result result) {
|
||||
promise.set_value(std::move(result));
|
||||
});
|
||||
|
||||
auto result = future.get();
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "hello world");
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "module/loader/module-loader.h"
|
||||
#include "providers/providers.h"
|
||||
#include "scheduler/broadcast-task.h"
|
||||
#include "scheduler/execute-task.h"
|
||||
#include "scheduler/task-decorators.h"
|
||||
#include "zone/eval-task.h"
|
||||
#include "zone/call-task.h"
|
||||
#include "zone/task-decorators.h"
|
||||
#include "zone/worker-context.h"
|
||||
#include "settings/settings.h"
|
||||
#include "v8/array-buffer-allocator.h"
|
||||
#include "napa-initialization-guard.h"
|
||||
|
@ -13,7 +15,7 @@
|
|||
#include <vector>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::scheduler;
|
||||
using namespace napa::zone;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// Make sure V8 it initialized exactly once.
|
||||
|
@ -31,139 +33,142 @@ TEST_CASE("tasks", "[tasks]") {
|
|||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
context->SetSecurityToken(v8::Undefined(isolate));
|
||||
v8::Context::Scope contextScope(context);
|
||||
|
||||
// Set a simple zone main function
|
||||
BroadcastTask("function __zone_execute__(module, func, args) { return this[func].apply(this, args); }").Execute();
|
||||
INIT_WORKER_CONTEXT();
|
||||
CREATE_MODULE_LOADER();
|
||||
|
||||
EvalTask("require('../lib/index');").Execute();
|
||||
|
||||
SECTION("load valid javascript") {
|
||||
ResponseCode loadResponseCode;
|
||||
BroadcastTask("var i = 3 + 5;", "", [&loadResponseCode](ResponseCode code) {
|
||||
ResultCode loadResponseCode;
|
||||
EvalTask("var i = 3 + 5;", "", [&loadResponseCode](ResultCode code) {
|
||||
loadResponseCode = code;
|
||||
}).Execute();
|
||||
|
||||
REQUIRE(loadResponseCode == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(loadResponseCode == NAPA_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
SECTION("load fails when javascript is malformed") {
|
||||
ResponseCode loadResponseCode;
|
||||
BroadcastTask("var j = 3 +", "", [&loadResponseCode](ResponseCode code) {
|
||||
ResultCode loadResponseCode;
|
||||
EvalTask("var j = 3 +", "", [&loadResponseCode](ResultCode code) {
|
||||
loadResponseCode = code;
|
||||
}).Execute();
|
||||
|
||||
REQUIRE(loadResponseCode == NAPA_RESPONSE_BROADCAST_SCRIPT_ERROR);
|
||||
REQUIRE(loadResponseCode == NAPA_RESULT_BROADCAST_SCRIPT_ERROR);
|
||||
}
|
||||
|
||||
SECTION("load fails when javascript exception is thrown") {
|
||||
ResponseCode loadResponseCode;
|
||||
BroadcastTask("throw Error('error');", "", [&loadResponseCode](ResponseCode code) {
|
||||
ResultCode loadResponseCode;
|
||||
EvalTask("throw Error('error');", "", [&loadResponseCode](ResultCode code) {
|
||||
loadResponseCode = code;
|
||||
}).Execute();
|
||||
|
||||
REQUIRE(loadResponseCode == NAPA_RESPONSE_BROADCAST_SCRIPT_ERROR);
|
||||
REQUIRE(loadResponseCode == NAPA_RESULT_BROADCAST_SCRIPT_ERROR);
|
||||
}
|
||||
|
||||
SECTION("execute succeeds with a valid and existing function") {
|
||||
BroadcastTask("function foo(a, b) { return Number(a) + Number(b); }").Execute();
|
||||
EvalTask("function foo(a, b) { return a + b; }").Execute();
|
||||
|
||||
ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("foo");
|
||||
request.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("foo");
|
||||
spec.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
|
||||
ExecuteResponse response;
|
||||
ExecuteTask(request, [&](ExecuteResponse res) {
|
||||
response = std::move(res);
|
||||
}).Execute();
|
||||
Result result;
|
||||
CallTask(std::make_shared<CallContext>(spec, [&](Result res) {
|
||||
result = std::move(res);
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "8");
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "8");
|
||||
}
|
||||
|
||||
SECTION("execute fails for non-existing function") {
|
||||
ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("bar");
|
||||
request.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("bar");
|
||||
spec.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
|
||||
ExecuteResponse response;
|
||||
ExecuteTask(request, [&](ExecuteResponse res) {
|
||||
response = std::move(res);
|
||||
}).Execute();
|
||||
Result result;
|
||||
CallTask(std::make_shared<CallContext>(spec, [&](Result res) {
|
||||
result = std::move(res);
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response.code == NAPA_RESPONSE_EXECUTE_FUNC_ERROR);
|
||||
REQUIRE(result.code == NAPA_RESULT_EXECUTE_FUNC_ERROR);
|
||||
}
|
||||
|
||||
SECTION("execute fails when function throws exception") {
|
||||
BroadcastTask("function f1(a, b) { throw 'an error' }").Execute();
|
||||
EvalTask("function f1(a, b) { throw 'an error' }").Execute();
|
||||
|
||||
ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("f1");
|
||||
request.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("f1");
|
||||
spec.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
|
||||
ExecuteResponse response;
|
||||
ExecuteTask(request, [&](ExecuteResponse res) {
|
||||
response = std::move(res);
|
||||
}).Execute();
|
||||
Result result;
|
||||
CallTask(std::make_shared<CallContext>(spec, [&](Result res) {
|
||||
result = std::move(res);
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response.code == NAPA_RESPONSE_EXECUTE_FUNC_ERROR);
|
||||
REQUIRE(response.errorMessage == "an error");
|
||||
REQUIRE(result.code == NAPA_RESULT_EXECUTE_FUNC_ERROR);
|
||||
REQUIRE(result.errorMessage == "an error");
|
||||
}
|
||||
|
||||
SECTION("execute succeeds when timeout was not exceeded") {
|
||||
BroadcastTask("function f2(a, b) { return Number(a) + Number(b); }").Execute();
|
||||
EvalTask("function f2(a, b) { return a + b; }").Execute();
|
||||
|
||||
ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("f2");
|
||||
request.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("f2");
|
||||
spec.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
|
||||
ExecuteResponse response;
|
||||
TimeoutTaskDecorator<ExecuteTask>(100ms, request, [&](ExecuteResponse res) {
|
||||
response = std::move(res);
|
||||
}).Execute();
|
||||
Result result;
|
||||
TimeoutTaskDecorator<CallTask>(100ms, std::make_shared<CallContext>(spec, [&](Result res) {
|
||||
result = std::move(res);
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response.returnValue == "8");
|
||||
REQUIRE(result.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(result.returnValue == "8");
|
||||
}
|
||||
|
||||
SECTION("execute fails when timeout exceeded") {
|
||||
BroadcastTask("function f3() { while(true) {} }").Execute();
|
||||
EvalTask("function f3() { while(true) {} }").Execute();
|
||||
|
||||
ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("f3");
|
||||
FunctionSpec spec;
|
||||
spec.function = NAPA_STRING_REF("f3");
|
||||
|
||||
ExecuteResponse response;
|
||||
TimeoutTaskDecorator<ExecuteTask>(30ms, request, [&](ExecuteResponse res) {
|
||||
response = std::move(res);
|
||||
}).Execute();
|
||||
Result result;
|
||||
TimeoutTaskDecorator<CallTask>(30ms, std::make_shared<CallContext>(spec, [&](Result res) {
|
||||
result = std::move(res);
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response.code == NAPA_RESPONSE_TIMEOUT);
|
||||
REQUIRE(response.errorMessage == "Execute exceeded timeout");
|
||||
REQUIRE(result.code == NAPA_RESULT_TIMEOUT);
|
||||
REQUIRE(result.errorMessage == "Terminated due to timeout");
|
||||
}
|
||||
|
||||
SECTION("execute succeeds after a failed task") {
|
||||
BroadcastTask("function f4() { while(true) {} }").Execute();
|
||||
BroadcastTask("function f5(a, b) { return Number(a) + Number(b); }").Execute();
|
||||
EvalTask("function f4() { while(true) {} }").Execute();
|
||||
EvalTask("function f5(a, b) { return Number(a) + Number(b); }").Execute();
|
||||
|
||||
ExecuteRequest request1;
|
||||
FunctionSpec request1;
|
||||
request1.function = NAPA_STRING_REF("f4");
|
||||
|
||||
ExecuteResponse response1;
|
||||
TimeoutTaskDecorator<ExecuteTask>(30ms, request1, [&](ExecuteResponse res) {
|
||||
Result response1;
|
||||
TimeoutTaskDecorator<CallTask>(30ms, std::make_shared<CallContext>(request1, [&](Result res) {
|
||||
response1 = std::move(res);
|
||||
}).Execute();
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response1.code == NAPA_RESPONSE_TIMEOUT);
|
||||
REQUIRE(response1.errorMessage == "Execute exceeded timeout");
|
||||
REQUIRE(response1.code == NAPA_RESULT_TIMEOUT);
|
||||
REQUIRE(response1.errorMessage == "Terminated due to timeout");
|
||||
|
||||
ExecuteRequest request2;
|
||||
FunctionSpec request2;
|
||||
request2.function = NAPA_STRING_REF("f5");
|
||||
request2.arguments = { NAPA_STRING_REF("3"), NAPA_STRING_REF("5") };
|
||||
|
||||
ExecuteResponse response2;
|
||||
TimeoutTaskDecorator<ExecuteTask>(100ms, request2, [&](ExecuteResponse res) {
|
||||
Result response2;
|
||||
TimeoutTaskDecorator<CallTask>(100ms, std::make_shared<CallContext>(request2, [&](Result res) {
|
||||
response2 = std::move(res);
|
||||
}).Execute();
|
||||
})).Execute();
|
||||
|
||||
REQUIRE(response2.code == NAPA_RESPONSE_SUCCESS);
|
||||
REQUIRE(response2.code == NAPA_RESULT_SUCCESS);
|
||||
REQUIRE(response2.returnValue == "8");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "scheduler/worker.h"
|
||||
#include "zone/worker.h"
|
||||
#include "napa-initialization-guard.h"
|
||||
|
||||
#include "v8.h"
|
||||
|
@ -10,7 +10,9 @@
|
|||
#include <mutex>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::scheduler;
|
||||
using namespace napa::settings;
|
||||
using namespace napa::zone;
|
||||
|
||||
|
||||
|
||||
class TestTask : public Task {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <napa-module.h>
|
||||
#include <napa-async.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
@ -22,7 +23,7 @@ void Increase(const FunctionCallbackInfo<Value>& args) {
|
|||
|
||||
auto value = args[0]->Uint32Value();
|
||||
|
||||
napa::module::PostAsyncWork(Local<Function>::Cast(args[1]),
|
||||
napa::zone::PostAsyncWork(Local<Function>::Cast(args[1]),
|
||||
[value]() {
|
||||
// This runs at the separate thread.
|
||||
_now += value;
|
||||
|
@ -51,7 +52,7 @@ void IncreaseSync(const FunctionCallbackInfo<Value>& args) {
|
|||
|
||||
auto value = args[0]->Uint32Value();
|
||||
|
||||
napa::module::DoAsyncWork(Local<Function>::Cast(args[1]),
|
||||
napa::zone::DoAsyncWork(Local<Function>::Cast(args[1]),
|
||||
[value](auto complete) {
|
||||
// This runs at the same thread.
|
||||
_now += value;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include <catch.hpp>
|
||||
|
||||
#include <module/module-loader.h>
|
||||
#include <napa/module/platform.h>
|
||||
#include <module/loader/module-loader.h>
|
||||
#include <napa/module/module-internal.h>
|
||||
#include <napa/v8-helpers.h>
|
||||
#include <scheduler/scheduler.h>
|
||||
#include <zone/zone-impl.h>
|
||||
#include <platform/platform.h>
|
||||
#include <zone/scheduler.h>
|
||||
#include <zone/napa-zone.h>
|
||||
#include <v8/array-buffer-allocator.h>
|
||||
#include <v8/v8-common.h>
|
||||
|
||||
|
@ -22,7 +22,9 @@
|
|||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
using namespace napa::scheduler;
|
||||
using namespace napa::settings;
|
||||
using namespace napa::zone;
|
||||
|
||||
|
||||
class V8InitializationGuard {
|
||||
public:
|
||||
|
@ -311,7 +313,7 @@ TEST_CASE("resolve full path modules", "[module-loader]") {
|
|||
|
||||
class AsyncTestTask : public Task {
|
||||
public:
|
||||
AsyncTestTask(ZoneImpl* zone, std::string filename)
|
||||
AsyncTestTask(zone::NapaZone* zone, std::string filename)
|
||||
: _zone(zone), _filename(std::move(filename)), _succeeded(false) {}
|
||||
|
||||
void Execute() override {
|
||||
|
@ -361,7 +363,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
ZoneImpl* _zone;
|
||||
zone::NapaZone* _zone;
|
||||
|
||||
std::string _filename;
|
||||
bool _succeeded = false;
|
||||
|
@ -375,7 +377,7 @@ TEST_CASE("async", "[module-loader]") {
|
|||
settings.id = "zone";
|
||||
settings.workers = 1;
|
||||
|
||||
auto zone = ZoneImpl::Create(settings);
|
||||
auto zone = zone::NapaZone::Create(settings);
|
||||
|
||||
auto scheduler = zone->GetScheduler();
|
||||
scheduler->ScheduleOnAllWorkers(std::make_shared<AsyncTestTask>(zone.get(), std::string()));
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
</Link>
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings>4100;4251;4996</DisableSpecificWarnings>
|
||||
<PreprocessorDefinitions>BUILDING_NAPA_EXTENSION;NAPA_EXPORTS;BUILDING_V8_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NAPA_EXPORTS;NAPA_BINDING_EXPORTS;BUILDING_NAPA_EXTENSION;BUILDING_V8_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
|
@ -49,26 +49,29 @@
|
|||
</ItemGroup>
|
||||
<!-- To avoid exporting module-loader APIs -->
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\async-runner.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\binary-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\core-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\javascript-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\json-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-cache.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-loader-helpers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-resolver.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\binary-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\core-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\javascript-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\json-module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-cache.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-loader.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-loader-helpers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-resolver.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\platform\win\platform.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\providers\providers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\async-complete-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\broadcast-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\execute-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\simple-thread-pool.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\terminable-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\timeout-service.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\worker.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\zone-impl.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\v8\v8-common.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\async-complete-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\async-runner.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\call-context.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\call-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\eval-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\napa-zone.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\node-zone.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\simple-thread-pool.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\terminable-task.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\timeout-service.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\worker.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(NapaVanillaRoot)\src\module\core-modules\napa\napa-core-modules.proj" />
|
||||
<Import Project="$(NapaVanillaRoot)\src\module\core-modules\node\node-core-modules.proj" />
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "napa/module/platform.h"
|
||||
#include "module/core-modules/node/file-system-helpers.h"
|
||||
#include <platform/platform.h>
|
||||
#include <module/core-modules/node/file-system-helpers.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
|
||||
TEST_CASE("File system helpers reads/writes a file correctly.", "[file-system-helpers]") {
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <module/module-resolver.h>
|
||||
#include <napa/module/platform.h>
|
||||
#include <module/loader/module-resolver.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
ModuleResolver& GetModuleResolver() {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings>4100;4996;4459</DisableSpecificWarnings>
|
||||
<PreprocessorDefinitions>NAPA_EXPORTS;NAPA_LOG_DISABLED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NAPA_EXPORTS;NAPA_BINDING_EXPORTS;NAPA_LOG_DISABLED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
|
@ -37,13 +37,13 @@
|
|||
<!-- Product code that is tested and needs to compile -->
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\core-modules\node\file-system-helpers.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\module-resolver.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\worker-context.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\module\loader\module-resolver.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\platform\win\platform.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\platform\win\thread-local-storage.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\simple-thread-pool.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\scheduler\timeout-service.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\settings\settings-parser.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\simple-thread-pool.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\timeout-service.cpp" />
|
||||
<ClCompile Include="$(NapaVanillaRoot)\src\zone\worker-context.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Test code -->
|
||||
|
@ -51,8 +51,8 @@
|
|||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="module\file-system-helpers-tests.cpp" />
|
||||
<ClCompile Include="module\module-resolver-tests.cpp" />
|
||||
<ClCompile Include="scheduler\scheduler-tests.cpp" />
|
||||
<ClCompile Include="scheduler\timeout-service-tests.cpp" />
|
||||
<ClCompile Include="zone\scheduler-tests.cpp" />
|
||||
<ClCompile Include="zone\timeout-service-tests.cpp" />
|
||||
<ClCompile Include="settings\parser-tests.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -7,68 +7,68 @@
|
|||
using namespace napa;
|
||||
|
||||
TEST_CASE("Parsing nothing doesn't fail", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("", settings));
|
||||
REQUIRE(settings_parser::ParseFromConsole(0, nullptr, settings));
|
||||
REQUIRE(settings::ParseFromString("", settings));
|
||||
REQUIRE(settings::ParseFromConsole(0, nullptr, settings));
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing from string", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
settings.workers = 1;
|
||||
settings.loggingProvider = "";
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("--workers 5 --loggingProvider myProvider", settings));
|
||||
REQUIRE(settings::ParseFromString("--workers 5 --loggingProvider myProvider", settings));
|
||||
|
||||
REQUIRE(settings.workers == 5);
|
||||
REQUIRE(settings.loggingProvider == "myProvider");
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing from console", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
settings.workers = 1;
|
||||
settings.loggingProvider = "";
|
||||
|
||||
std::vector<char*> args = { "--workers", "5", "--loggingProvider", "myProvider" };
|
||||
|
||||
REQUIRE(settings_parser::ParseFromConsole(static_cast<int>(args.size()), args.data(), settings));
|
||||
REQUIRE(settings::ParseFromConsole(static_cast<int>(args.size()), args.data(), settings));
|
||||
|
||||
REQUIRE(settings.workers == 5);
|
||||
REQUIRE(settings.loggingProvider == "myProvider");
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing non existing setting fails", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("--thisSettingDoesNotExist noValue", settings) == false);
|
||||
REQUIRE(settings::ParseFromString("--thisSettingDoesNotExist noValue", settings) == false);
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing does not change defaults if setting is not provided", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
settings.workers = 2412;
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("--loggingProvider myProvider", settings));
|
||||
REQUIRE(settings::ParseFromString("--loggingProvider myProvider", settings));
|
||||
|
||||
REQUIRE(settings.workers == 2412);
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing with extra white spaces succeeds", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
settings.workers = 1;
|
||||
settings.loggingProvider = "";
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString(" --workers 5 --loggingProvider \t myProvider \t\t ", settings));
|
||||
REQUIRE(settings::ParseFromString(" --workers 5 --loggingProvider \t myProvider \t\t ", settings));
|
||||
|
||||
REQUIRE(settings.workers == 5);
|
||||
REQUIRE(settings.loggingProvider == "myProvider");
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing with multiple values for one setting", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
settings.workers = 1;
|
||||
settings.v8Flags = {};
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("--v8Flags one two three --workers 5", settings));
|
||||
REQUIRE(settings::ParseFromString("--v8Flags one two three --workers 5", settings));
|
||||
|
||||
REQUIRE(settings.workers == 5);
|
||||
REQUIRE(settings.v8Flags.size() == 3);
|
||||
|
@ -78,13 +78,13 @@ TEST_CASE("Parsing with multiple values for one setting", "[settings-parser]") {
|
|||
}
|
||||
|
||||
TEST_CASE("Parsing with empty string succeeds", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("", settings) == true);
|
||||
REQUIRE(settings::ParseFromString("", settings) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing with different value type fails", "[settings-parser]") {
|
||||
PlatformSettings settings;
|
||||
settings::PlatformSettings settings;
|
||||
|
||||
REQUIRE(settings_parser::ParseFromString("--workers five", settings) == false);
|
||||
REQUIRE(settings::ParseFromString("--workers five", settings) == false);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "zone/scheduler.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::scheduler;
|
||||
|
||||
using namespace napa::zone;
|
||||
using namespace napa::settings;
|
||||
|
||||
class TestTask : public Task {
|
||||
public:
|
|
@ -1,11 +1,11 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "scheduler/timeout-service.h"
|
||||
#include "zone/timeout-service.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
using namespace napa::scheduler;
|
||||
using namespace napa::zone;
|
||||
using namespace std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
|
|
@ -40,7 +40,7 @@ As you can count on NPM, most modules are pure JavaScript. These are only a few
|
|||
| ------------------------------------------------------------ | ---------- | ------------- | -------------- | ------------ |
|
||||
| Export JavaScript function only | | | | hello-world [[.md](../../examples/modules/hello-world/README.md) [.cpp](../../examples/modules/hello-world/node/addon.cpp) [test](../../examples/modules/hello-world/test/test.ts)] |
|
||||
| Export JavaScript object (ObjectWrap) | X | | | plus-number [[.md](../../examples/modules/plus-number/README.md) [.cpp](../../examples/modules/plus-number/node/addon.cpp) [test](../../examples/modules/plus-number/test/module-test/test.ts)] |
|
||||
| Share C++ object across isolates | X | X | | allocator-wrap [[.h](../../src/module/core-modules/napa-wraps/allocator-wrap.h) [.cpp](../../src/module/core-modules/napa-wraps/allocator-wrap.cpp)] |
|
||||
| Share C++ object across isolates | X | X | | allocator-wrap [[.h](../../src/module/core-modules/napa/allocator-wrap.h) [.cpp](../../src/module/core-modules/napa/allocator-wrap.cpp)] |
|
||||
| Export asynchronous JavaScript function | X | | X | async-number [[.md](../../examples/modules/async-number/README.md) [.cpp](../../examples/modules/async-number/node/addon.cpp) [test](../../examples/modules/async-number/test/test.ts)] |
|
||||
|
||||
## Special topics
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
## Table of Contents
|
||||
- [`create(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zone`](#create-id-string-settings-zonesettings-default_settings-zone)
|
||||
- [`getOrCreate(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zone`](#getOrCreate-id-string-settings-zonesettings-default_settings-zone)
|
||||
- [`get(id: string): Zone`](#get-id-string-zone)
|
||||
- [`current: Zone`](#current-zone)
|
||||
- [`node: Zone`](#node-zone)
|
||||
|
@ -15,11 +14,11 @@
|
|||
- [`zone.broadcast(function: (...args: any[]) => void, args: any[]): Promise<void>`](#zone-broadcast-function-args-any-void-args-any-promise-void)
|
||||
- [`zone.broadcastSync(code: string): void`](#zone-broadcastsync-code-string-void)
|
||||
- [`zone.broadcastSync(function: (...args: any[]) => void, args: any[]): void`](#zone-broadcastsync-function-args-any-void-args-any-void)
|
||||
- [`zone.execute(moduleName: string, functionName: string, args: any[], timeout: number): Promise<ExecuteResult>`](#zone-execute-modulename-string-functionname-string-args-any-timeout-number-promise-executeresult)
|
||||
- [`zone.execute(function: (...args[]) => any, args: any[], timeout: number): Promise<ExecuteResult>`](#zone-execute-function-args-any-args-any-timeout-number-promise-executeresult)
|
||||
- [`zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number): ExecuteResult`](#zone-executesync-modulename-string-functionname-string-args-any-timeout-number-executeresult)
|
||||
- [`zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number): ExecuteResult`](#zone-executesync-function-args-any-any-args-any-timeout-number-executeresult)
|
||||
- interface [`ExecuteResult`](#interface-executeresult)
|
||||
- [`zone.execute(moduleName: string, functionName: string, args: any[], timeout: number): Promise<Result>`](#zone-execute-modulename-string-functionname-string-args-any-timeout-number-promise-result)
|
||||
- [`zone.execute(function: (...args[]) => any, args: any[], timeout: number): Promise<Result>`](#zone-execute-function-args-any-args-any-timeout-number-promise-result)
|
||||
- [`zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number): Result`](#zone-executesync-modulename-string-functionname-string-args-any-timeout-number-result)
|
||||
- [`zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number): Result`](#zone-executesync-function-args-any-any-args-any-timeout-number-result)
|
||||
- interface [`Result`](#interface-result)
|
||||
- [`result.value: any`](#result-value-any)
|
||||
- [`result.payload: string`](#result-payload-string)
|
||||
- [`result.transportContext: transport.TransportContext`](#result-transportcontext-transport-transportcontext)
|
||||
|
@ -40,15 +39,6 @@ let zone = napa.zone.create('zone1', {
|
|||
workers: 1
|
||||
});
|
||||
```
|
||||
### getOrCreate(id: string, settings: ZoneSettings): Zone
|
||||
It gets a reference of zone by an id if a zone with the id already exists, otherwise create a new one and return its reference.
|
||||
|
||||
Example:
|
||||
```ts
|
||||
let zone = napa.zone.getOrCreate('zone1', {
|
||||
workers: 4
|
||||
});
|
||||
```
|
||||
### get(id: string): Zone
|
||||
It gets a reference of zone by an id. Error will be thrown if the zone doesn't exist.
|
||||
|
||||
|
@ -154,12 +144,12 @@ catch (error) {
|
|||
}
|
||||
```
|
||||
### zone.execute(moduleName: string, functionName: string, args: any[], timeout: number = 0): Promise\<any\>
|
||||
Execute a function asynchronously on arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns a Promise of [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
|
||||
Execute a function asynchronously on arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns a Promise of [`Result`](#interface-result). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
|
||||
|
||||
Example: Execute function 'bar' in module 'foo', with arguments [1, 'hello', { field1: 1 }]. 300ms timeout is applied.
|
||||
```ts
|
||||
zone.execute('foo', 'bar', [1, "hello", {field1: 1}], 300)
|
||||
.then((result: ExecuteResult) => {
|
||||
.then((result: Result) => {
|
||||
console.log('execute succeeded:', result.value);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -170,14 +160,14 @@ zone.execute('foo', 'bar', [1, "hello", {field1: 1}], 300)
|
|||
|
||||
### zone.execute(function: (...args: any[]) => any, args: any[], timeout: number = 0): Promise\<any\>
|
||||
|
||||
Execute an anonymous function asynchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns a Promise of [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
|
||||
Execute an anonymous function asynchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns a Promise of [`Result`](#interface-result). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
|
||||
|
||||
Example:
|
||||
```ts
|
||||
zone.execute((a: number, b: string, c: object) => {
|
||||
return a + b + JSON.stringify(c);
|
||||
}, [1, "hello", {field1: 1}])
|
||||
.then((result: ExecuteResult) => {
|
||||
.then((result: Result) => {
|
||||
console.log('execute succeeded:', result.value);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -188,7 +178,7 @@ zone.execute((a: number, b: string, c: object) => {
|
|||
|
||||
### zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number = 0): any
|
||||
|
||||
Execute a function synchronously on arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns an [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
|
||||
Execute a function synchronously on arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns an [`Result`](#interface-result). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
|
||||
|
||||
Example: Execute function 'bar' in module 'foo', with arguments [1, 'hello', { field1: 1 }]. 300ms timeout is applied.
|
||||
```ts
|
||||
|
@ -203,7 +193,7 @@ catch (error) {
|
|||
```
|
||||
|
||||
### zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number = 0): any
|
||||
Execute an annoymouse function synchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns an [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
|
||||
Execute an annoymouse function synchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns an [`Result`](#interface-result). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
|
||||
|
||||
Example: Execute annoymouse function sychronously, with arguments [1, 'hello', { field1: 1 }]. No timeout is applied.
|
||||
```ts
|
||||
|
@ -219,7 +209,7 @@ catch (error) {
|
|||
|
||||
```
|
||||
|
||||
## Interface `ExecuteResult`
|
||||
## Interface `Result`
|
||||
Interface to access return value of `zone.execute` or `zone.executeSync`.
|
||||
|
||||
### result.value: any
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <napa-module.h>
|
||||
#include <napa-async.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
@ -22,7 +23,7 @@ void Increase(const FunctionCallbackInfo<Value>& args) {
|
|||
|
||||
auto value = args[0]->Uint32Value();
|
||||
|
||||
napa::module::PostAsyncWork(Local<Function>::Cast(args[1]),
|
||||
napa::zone::PostAsyncWork(Local<Function>::Cast(args[1]),
|
||||
[value]() {
|
||||
// This runs at the separate thread.
|
||||
_now += value;
|
||||
|
@ -51,7 +52,7 @@ void IncreaseSync(const FunctionCallbackInfo<Value>& args) {
|
|||
|
||||
auto value = args[0]->Uint32Value();
|
||||
|
||||
napa::module::DoAsyncWork(Local<Function>::Cast(args[1]),
|
||||
napa::zone::DoAsyncWork(Local<Function>::Cast(args[1]),
|
||||
[value](auto complete) {
|
||||
// This runs at the same thread.
|
||||
_now += value;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(EnvironmentConfig)" />
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectFile Include="async-number\dirs.proj" />
|
||||
<ProjectFile Include="hello-world\dirs.proj" />
|
||||
<ProjectFile Include="plus-number\dirs.proj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(ExtendedTargetsPath)\Traversal.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef BUILDING_NAPA_EXTENSION
|
||||
#include "napa/zone/napa-async-runner.h"
|
||||
#else
|
||||
#include "napa/zone/node-async-runner.h"
|
||||
#endif
|
||||
|
20
inc/napa-c.h
20
inc/napa-c.h
|
@ -30,7 +30,7 @@ EXTERN_C NAPA_API napa_zone_handle napa_zone_get_current();
|
|||
|
||||
/// <summary> Releases the zone handle. When all handles for a zone are released the zone is destoryed. </summary>
|
||||
/// <param name="handle"> The zone handle. </param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_zone_release(napa_zone_handle handle);
|
||||
EXTERN_C NAPA_API napa_result_code napa_zone_release(napa_zone_handle handle);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the napa zone, providing specific settings.
|
||||
|
@ -39,7 +39,7 @@ EXTERN_C NAPA_API napa_response_code napa_zone_release(napa_zone_handle handle);
|
|||
/// </summary>
|
||||
/// <param name="handle"> The zone handle. </param>
|
||||
/// <param name="settings"> The settings string. </param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_zone_init(
|
||||
EXTERN_C NAPA_API napa_result_code napa_zone_init(
|
||||
napa_zone_handle handle,
|
||||
napa_string_ref settings);
|
||||
|
||||
|
@ -60,12 +60,12 @@ EXTERN_C NAPA_API void napa_zone_broadcast(
|
|||
|
||||
/// <summary> Executes a pre-loaded function asynchronously in a single zone wroker. </summary>
|
||||
/// <param name="handle"> The zone handle. </param>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
/// <param name="spec"> The function spec to call. </param>
|
||||
/// <param name="callback"> A callback that is triggered when execution is done. </param>
|
||||
/// <param name="context"> An opaque pointer that is passed back in the callback. </param>
|
||||
EXTERN_C NAPA_API void napa_zone_execute(
|
||||
napa_zone_handle handle,
|
||||
napa_zone_execute_request request,
|
||||
napa_zone_function_spec spec,
|
||||
napa_zone_execute_callback callback,
|
||||
void* context);
|
||||
|
||||
|
@ -76,23 +76,23 @@ EXTERN_C NAPA_API void napa_zone_execute(
|
|||
/// TODO: specify public settings here.
|
||||
/// </summary>
|
||||
/// <param name="settings"> The settings string. </param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_initialize(napa_string_ref settings);
|
||||
EXTERN_C NAPA_API napa_result_code napa_initialize(napa_string_ref settings);
|
||||
|
||||
/// <summary>
|
||||
/// Same as napa_initialize only accepts arguments as provided by console
|
||||
/// </summary>
|
||||
/// <param name="argc"> Number of arguments. </param>
|
||||
/// <param name="argv"> The arguments. </param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_initialize_from_console(
|
||||
EXTERN_C NAPA_API napa_result_code napa_initialize_from_console(
|
||||
int argc,
|
||||
char* argv[]);
|
||||
|
||||
/// <summary> Invokes napa shutdown steps. All non released zones will be destroyed. </summary>
|
||||
EXTERN_C NAPA_API napa_response_code napa_shutdown();
|
||||
EXTERN_C NAPA_API napa_result_code napa_shutdown();
|
||||
|
||||
/// <summary> Convert the napa response code to its string representation. </summary>
|
||||
/// <param name="code"> The response code. </param>
|
||||
EXTERN_C NAPA_API const char* napa_response_code_to_string(napa_response_code code);
|
||||
/// <summary> Convert the napa result code to its string representation. </summary>
|
||||
/// <param name="code"> The result code. </param>
|
||||
EXTERN_C NAPA_API const char* napa_result_code_to_string(napa_result_code code);
|
||||
|
||||
/// <summary> Set customized allocator, which will be used for napa_allocate and napa_deallocate.
|
||||
/// If user doesn't call napa_allocator_set, C runtime malloc/free from napa.dll will be used. </summary>
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
#ifdef BUILDING_NAPA_EXTENSION
|
||||
#include "napa/module/module-internal.h"
|
||||
#include "napa/module/module-node-compat.h"
|
||||
#include "napa/module/napa-async-runner.h"
|
||||
#include "napa/module/object-wrap.h"
|
||||
#else
|
||||
#include "napa/module/node-async-runner.h"
|
||||
#include <node.h>
|
||||
#include <node_object_wrap.h>
|
||||
#endif
|
||||
|
|
58
inc/napa.h
58
inc/napa.h
|
@ -8,17 +8,17 @@
|
|||
namespace napa {
|
||||
|
||||
/// <summary> Initializes napa with global scope settings. </summary>
|
||||
inline ResponseCode Initialize(const std::string& settings = "") {
|
||||
inline ResultCode Initialize(const std::string& settings = "") {
|
||||
return napa_initialize(STD_STRING_TO_NAPA_STRING_REF(settings));
|
||||
}
|
||||
|
||||
/// <summary> Initialize napa using console provided arguments. </summary>
|
||||
inline ResponseCode InitializeFromConsole(int argc, char* argv[]) {
|
||||
inline ResultCode InitializeFromConsole(int argc, char* argv[]) {
|
||||
return napa_initialize_from_console(argc, argv);
|
||||
}
|
||||
|
||||
/// <summary> Shut down napa. </summary>
|
||||
inline ResponseCode Shutdown() {
|
||||
inline ResultCode Shutdown() {
|
||||
return napa_shutdown();
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,9 @@ namespace napa {
|
|||
_handle = napa_zone_create(STD_STRING_TO_NAPA_STRING_REF(id));
|
||||
|
||||
auto res = napa_zone_init(_handle, STD_STRING_TO_NAPA_STRING_REF(settings));
|
||||
if (res != NAPA_RESPONSE_SUCCESS) {
|
||||
if (res != NAPA_RESULT_SUCCESS) {
|
||||
napa_zone_release(_handle);
|
||||
throw std::runtime_error(napa_response_code_to_string(res));
|
||||
throw std::runtime_error(napa_result_code_to_string(res));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ namespace napa {
|
|||
napa_zone_broadcast(
|
||||
_handle,
|
||||
STD_STRING_TO_NAPA_STRING_REF(source),
|
||||
[](napa_response_code code, void* context) {
|
||||
[](napa_result_code code, void* context) {
|
||||
// Ensures the context is deleted when this scope ends.
|
||||
std::unique_ptr<BroadcastCallback> callback(reinterpret_cast<BroadcastCallback*>(context));
|
||||
|
||||
|
@ -69,11 +69,11 @@ namespace napa {
|
|||
|
||||
/// <summary> Compiles and run the provided source code on all zone workers synchronously. </summary>
|
||||
/// <param name="source"> The source code. </param>
|
||||
ResponseCode BroadcastSync(const std::string& source) {
|
||||
std::promise<ResponseCode> prom;
|
||||
ResultCode BroadcastSync(const std::string& source) {
|
||||
std::promise<ResultCode> prom;
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Broadcast(source, [&prom](ResponseCode code) {
|
||||
Broadcast(source, [&prom](ResultCode code) {
|
||||
prom.set_value(code);
|
||||
});
|
||||
|
||||
|
@ -81,47 +81,47 @@ namespace napa {
|
|||
}
|
||||
|
||||
/// <summary> Executes a pre-loaded JS function asynchronously. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
/// <param name="spec"> A function spec to call. </param>
|
||||
/// <param name="callback"> A callback that is triggered when execution is done. </param>
|
||||
void Execute(const ExecuteRequest& request, ExecuteCallback callback) {
|
||||
void Execute(const FunctionSpec& spec, ExecuteCallback callback) {
|
||||
// Will be deleted on when the callback scope ends.
|
||||
auto context = new ExecuteCallback(std::move(callback));
|
||||
|
||||
napa_zone_execute_request req;
|
||||
req.module = request.module;
|
||||
req.function = request.function;
|
||||
req.arguments = request.arguments.data();
|
||||
req.arguments_count = request.arguments.size();
|
||||
req.options = request.options;
|
||||
napa_zone_function_spec req;
|
||||
req.module = spec.module;
|
||||
req.function = spec.function;
|
||||
req.arguments = spec.arguments.data();
|
||||
req.arguments_count = spec.arguments.size();
|
||||
req.options = spec.options;
|
||||
|
||||
// Release ownership of transport context
|
||||
req.transport_context = reinterpret_cast<void*>(request.transportContext.release());
|
||||
req.transport_context = reinterpret_cast<void*>(spec.transportContext.release());
|
||||
|
||||
napa_zone_execute(_handle, req, [](napa_zone_execute_response response, void* context) {
|
||||
napa_zone_execute(_handle, req, [](napa_zone_result result, void* context) {
|
||||
// Ensures the context is deleted when this scope ends.
|
||||
std::unique_ptr<ExecuteCallback> callback(reinterpret_cast<ExecuteCallback*>(context));
|
||||
|
||||
ExecuteResponse res;
|
||||
res.code = response.code;
|
||||
res.errorMessage = NAPA_STRING_REF_TO_STD_STRING(response.error_message);
|
||||
res.returnValue = NAPA_STRING_REF_TO_STD_STRING(response.return_value);
|
||||
Result res;
|
||||
res.code = result.code;
|
||||
res.errorMessage = NAPA_STRING_REF_TO_STD_STRING(result.error_message);
|
||||
res.returnValue = NAPA_STRING_REF_TO_STD_STRING(result.return_value);
|
||||
|
||||
// Assume ownership of transport context
|
||||
res.transportContext.reset(
|
||||
reinterpret_cast<napa::transport::TransportContext*>(response.transport_context));
|
||||
reinterpret_cast<napa::transport::TransportContext*>(result.transport_context));
|
||||
|
||||
(*callback)(std::move(res));
|
||||
}, context);
|
||||
}
|
||||
|
||||
/// <summary> Executes a pre-loaded JS function synchronously. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
ExecuteResponse ExecuteSync(const ExecuteRequest& request) {
|
||||
std::promise<ExecuteResponse> prom;
|
||||
/// <param name="spec"> The function spec to call. </param>
|
||||
Result ExecuteSync(const FunctionSpec& spec) {
|
||||
std::promise<Result> prom;
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Execute(request, [&prom](ExecuteResponse response) {
|
||||
prom.set_value(std::move(response));
|
||||
Execute(spec, [&prom](Result result) {
|
||||
prom.set_value(std::move(result));
|
||||
});
|
||||
|
||||
return fut.get();
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
// API exported from napa.dll
|
||||
#ifdef NAPA_EXPORTS
|
||||
#define NAPA_API __declspec(dllexport)
|
||||
#else
|
||||
#define NAPA_API __declspec(dllimport)
|
||||
#endif // NAPA_EXPORTS
|
||||
|
||||
// API exported from napa-binding. (both napa.dll and napa-binding.node)
|
||||
#ifdef NAPA_BINDING_EXPORTS
|
||||
#define NAPA_BINDING_API __declspec(dllexport)
|
||||
#else
|
||||
#define NAPA_BINDING_API __declspec(dllimport)
|
||||
#endif // NAPA_BINDING_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C extern "C"
|
||||
#else
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa-assert.h>
|
||||
#include <napa/module/worker-context.h>
|
||||
#include <napa/exports.h>
|
||||
#include <napa/v8-helpers/maybe.h>
|
||||
#include <napa/v8-helpers/string.h>
|
||||
#include <napa/v8-helpers/flow.h>
|
||||
|
@ -14,14 +14,7 @@ namespace binding {
|
|||
|
||||
/// <summary> Get 'module' object of napa binding, which is napa-binding.node in Node.JS isolate or napa-binding from core-modules in Napa isolate. </summary>
|
||||
/// <returns> 'module' object for napa binding (napajs/bin/napa-binding.node or napa.dll) </returns>
|
||||
inline v8::Local<v8::Object> GetModule() {
|
||||
auto persistentModule =
|
||||
reinterpret_cast<v8::Persistent<v8::Object>*>(
|
||||
WorkerContext::Get(WorkerContextItem::NAPA_BINDING));
|
||||
|
||||
NAPA_ASSERT(persistentModule != nullptr, "\"napajs\" must be required before napa::module::binding::GetModule() can be called from C++.");
|
||||
return v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), *persistentModule);
|
||||
}
|
||||
NAPA_BINDING_API v8::Local<v8::Object> GetModule();
|
||||
|
||||
/// <summary> Get 'module.exports' from napa binding. </summary>
|
||||
/// <returns> 'module.exports' object for napa binding (napajs/bin/napa-binding.node or napa.dll) </returns>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "worker-context.h"
|
||||
|
||||
#include <napa/exports.h>
|
||||
|
||||
#include <array>
|
||||
|
@ -91,43 +89,12 @@ namespace module {
|
|||
/// <summary> It sets the persistent constructor at the current V8 isolate. </summary>
|
||||
/// <param name="name"> Unique constructor name. It's recommended to use the same name as module. </param>
|
||||
/// <param name="constructor"> V8 persistent function to constructor V8 object. </param>
|
||||
inline void SetPersistentConstructor(const char* name,
|
||||
v8::Local<v8::Function> constructor) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto constructorInfo =
|
||||
static_cast<ConstructorInfo*>(WorkerContext::Get(WorkerContextItem::CONSTRUCTOR));
|
||||
if (constructorInfo == nullptr) {
|
||||
constructorInfo = new ConstructorInfo();
|
||||
WorkerContext::Set(WorkerContextItem::CONSTRUCTOR, constructorInfo);
|
||||
}
|
||||
|
||||
constructorInfo->constructorMap.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(name),
|
||||
std::forward_as_tuple(isolate, constructor));
|
||||
}
|
||||
NAPA_API void SetPersistentConstructor(const char* name, v8::Local<v8::Function> constructor);
|
||||
|
||||
/// <summary> It gets the given persistent constructor from the current V8 isolate. </summary>
|
||||
/// <param name="name"> Unique constructor name given at SetPersistentConstructor() call. </param>
|
||||
/// <returns> V8 local function object. </returns>
|
||||
inline v8::Local<v8::Function> GetPersistentConstructor(const char* name) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
|
||||
auto constructorInfo =
|
||||
static_cast<ConstructorInfo*>(WorkerContext::Get(WorkerContextItem::CONSTRUCTOR));
|
||||
if (constructorInfo == nullptr) {
|
||||
return scope.Escape(v8::Local<v8::Function>());
|
||||
}
|
||||
|
||||
auto iter = constructorInfo->constructorMap.find(name);
|
||||
if (iter != constructorInfo->constructorMap.end()) {
|
||||
auto constructor = v8::Local<v8::Function>::New(isolate, iter->second);
|
||||
return scope.Escape(constructor);
|
||||
} else {
|
||||
return scope.Escape(v8::Local<v8::Function>());
|
||||
}
|
||||
}
|
||||
NAPA_API v8::Local<v8::Function> GetPersistentConstructor(const char* name);
|
||||
|
||||
} // End of namespace module.
|
||||
} // End of namespace napa.
|
|
@ -59,10 +59,16 @@ namespace module {
|
|||
return _object;
|
||||
}
|
||||
|
||||
/// <summary> Get reference of T, which is the type of contained native object. </summary>
|
||||
template <typename T>
|
||||
typename std::enable_if_t<!std::is_same<void, T>::value, T&> GetRef() {
|
||||
return *std::static_pointer_cast<T>(_object);
|
||||
}
|
||||
|
||||
/// <summary> It creates a new instance of WrapType of shared_ptr<T>, WrapType is a sub-class of ShareableWrap. </summary>
|
||||
/// <param name="object"> shared_ptr of object. </summary>
|
||||
/// <returns> V8 object of type ShareableWrap. </summary>
|
||||
template <typename T, typename WrapType>
|
||||
template <typename WrapType, typename T>
|
||||
static v8::Local<v8::Object> NewInstance(std::shared_ptr<T> object) {
|
||||
auto instance = napa::module::NewInstance<WrapType>().ToLocalChecked();
|
||||
Set(instance, std::move(object));
|
||||
|
@ -110,9 +116,9 @@ namespace module {
|
|||
/// <summary> It implements TransportableObject.load(payload: object, transportContext: TransportContext): void </summary>
|
||||
static void LoadCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 2, "2 arguments are required for \"load\".");
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "Argument \"payload\" shall be 'Object' type.");
|
||||
CHECK_ARG(isolate, args[1]->IsObject(), "Argument \"transportContext\" shall be 'TransportContextWrap' type.");
|
||||
|
@ -134,8 +140,8 @@ namespace module {
|
|||
/// <summary> It implements TransportableObject.save(payload: object, transportContext: TransportContext): void </summary>
|
||||
static void SaveCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 2, "2 arguments are required for \"save\".");
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "Argument \"payload\" should be 'Object' type.");
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
///
|
||||
/// Napa response codes definition file!
|
||||
///
|
||||
/// Guidelines:
|
||||
/// 1. Use NAPA_RESPONSE_CODE_DEF to define new codes.
|
||||
/// 2. Add new codes at the end of the list.
|
||||
/// 3. Make sure to add a comma at the end of the previous response code defintion
|
||||
///
|
||||
/// |----------------------- symbol name ---------- string representation --|
|
||||
/// NAPA_RESPONSE_CODE_DEF( EXAMPLE_NAME1, "Example string message1"),
|
||||
/// NAPA_RESPONSE_CODE_DEF( EXAMPLE_NAME2, "Example string message2")
|
||||
/// Always add news codes
|
||||
///
|
||||
|
||||
#ifndef NAPA_RESPONSE_CODE_DEF
|
||||
#error NAPA_RESPONSE_CODE_DEF must be defined before including response_code.inc
|
||||
#endif
|
||||
|
||||
NAPA_RESPONSE_CODE_DEF( SUCCESS, "Success"),
|
||||
NAPA_RESPONSE_CODE_DEF( UNDEFINED, "Undefined"),
|
||||
NAPA_RESPONSE_CODE_DEF( INTERNAL_ERROR, "Napa internal error"),
|
||||
NAPA_RESPONSE_CODE_DEF( TIMEOUT, "The request timed out"),
|
||||
NAPA_RESPONSE_CODE_DEF( ZONE_INIT_ERROR, "Failed to initialize zone"),
|
||||
NAPA_RESPONSE_CODE_DEF( BROADCAST_SCRIPT_ERROR, "Failed to broadcast JavaScript code in zone"),
|
||||
NAPA_RESPONSE_CODE_DEF( EXECUTE_FUNC_ERROR, "Failed to execute the JavaScript function"),
|
||||
NAPA_RESPONSE_CODE_DEF( SETTINGS_PARSER_ERROR, "Failed to parse settings"),
|
||||
NAPA_RESPONSE_CODE_DEF( PROVIDERS_INIT_ERROR, "Failed to initialize providers"),
|
||||
NAPA_RESPONSE_CODE_DEF( V8_INIT_ERROR, "Failed to initialize V8"),
|
||||
NAPA_RESPONSE_CODE_DEF( GLOBAL_VALUE_ERROR, "Failed to set global value")
|
|
@ -0,0 +1,29 @@
|
|||
///
|
||||
/// Napa result codes definition file!
|
||||
///
|
||||
/// Guidelines:
|
||||
/// 1. Use NAPA_RESULT_CODE_DEF to define new codes.
|
||||
/// 2. Add new codes at the end of the list.
|
||||
/// 3. Make sure to add a comma at the end of the previous result code defintion
|
||||
///
|
||||
/// |----------------------- symbol name ---------- string representation --|
|
||||
/// NAPA_RESULT_CODE_DEF( EXAMPLE_NAME1, "Example string message1"),
|
||||
/// NAPA_RESULT_CODE_DEF( EXAMPLE_NAME2, "Example string message2")
|
||||
/// Always add news codes
|
||||
///
|
||||
|
||||
#ifndef NAPA_RESULT_CODE_DEF
|
||||
#error NAPA_RESULT_CODE_DEF must be defined before including response_code.inc
|
||||
#endif
|
||||
|
||||
NAPA_RESULT_CODE_DEF( SUCCESS, "Success"),
|
||||
NAPA_RESULT_CODE_DEF( UNDEFINED, "Undefined"),
|
||||
NAPA_RESULT_CODE_DEF( INTERNAL_ERROR, "Napa internal error"),
|
||||
NAPA_RESULT_CODE_DEF( TIMEOUT, "The request timed out"),
|
||||
NAPA_RESULT_CODE_DEF( ZONE_INIT_ERROR, "Failed to initialize zone"),
|
||||
NAPA_RESULT_CODE_DEF( BROADCAST_SCRIPT_ERROR, "Failed to broadcast JavaScript code in zone"),
|
||||
NAPA_RESULT_CODE_DEF( EXECUTE_FUNC_ERROR, "Failed to execute the JavaScript function"),
|
||||
NAPA_RESULT_CODE_DEF( SETTINGS_PARSER_ERROR, "Failed to parse settings"),
|
||||
NAPA_RESULT_CODE_DEF( PROVIDERS_INIT_ERROR, "Failed to initialize providers"),
|
||||
NAPA_RESULT_CODE_DEF( V8_INIT_ERROR, "Failed to initialize V8"),
|
||||
NAPA_RESULT_CODE_DEF( GLOBAL_VALUE_ERROR, "Failed to set global value")
|
|
@ -42,8 +42,8 @@ namespace transport {
|
|||
/// <summary> It implements Transportable.marshall(context: TransportContext): object </summary>
|
||||
static void MarshallCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 1, "1 argument is required for calling 'marshall'.");
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "The 1st argument of 'marshall' shall be object of TransportContext.");
|
||||
|
@ -86,8 +86,8 @@ namespace transport {
|
|||
/// <summary> It implements Transportable.unmarshall(payload: object, context: TransportContext): void </summary>
|
||||
static void UnmarshallCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 2, "Two arguments are required for calling 'unmarshall'. ");
|
||||
|
||||
|
|
|
@ -25,21 +25,21 @@ namespace napa {
|
|||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents response code in napa zone apis. </summary>
|
||||
#define NAPA_RESPONSE_CODE_DEF(symbol, ...) NAPA_RESPONSE_##symbol
|
||||
/// <summary> Represents result code in napa zone apis. </summary>
|
||||
#define NAPA_RESULT_CODE_DEF(symbol, ...) NAPA_RESULT_##symbol
|
||||
|
||||
typedef enum {
|
||||
|
||||
#include "napa/response-codes.inc"
|
||||
#include "napa/result-codes.inc"
|
||||
|
||||
} napa_response_code;
|
||||
} napa_result_code;
|
||||
|
||||
#undef NAPA_RESPONSE_CODE_DEF
|
||||
#undef NAPA_RESULT_CODE_DEF
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
typedef napa_response_code ResponseCode;
|
||||
typedef napa_result_code ResultCode;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
@ -66,7 +66,7 @@ namespace napa {
|
|||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents options for an execution request. </summary>
|
||||
/// <summary> Represents options for calling a function. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> Timeout in milliseconds - Use 0 for inifinite. </summary>
|
||||
|
@ -74,17 +74,17 @@ typedef struct {
|
|||
|
||||
/// <summary> Arguments transport option. Default is AUTO. </summary>
|
||||
napa_transport_option transport;
|
||||
} napa_zone_execute_options;
|
||||
} napa_zone_call_options;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
typedef napa_zone_execute_options ExecuteOptions;
|
||||
typedef napa_zone_call_options CallOptions;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents an execution request for a zone. </summary>
|
||||
/// <summary> Represents a function to run within a zone, with binded aruments . </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> The module that exports the function to execute. </summary>
|
||||
|
@ -100,11 +100,11 @@ typedef struct {
|
|||
size_t arguments_count;
|
||||
|
||||
/// <summary> Options. </summary>
|
||||
napa_zone_execute_options options;
|
||||
napa_zone_call_options options;
|
||||
|
||||
/// <summary> A context used for transporting handles across zones/workers. </summary>
|
||||
void* transport_context;
|
||||
} napa_zone_execute_request;
|
||||
} napa_zone_function_spec;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
@ -114,8 +114,8 @@ typedef struct {
|
|||
#include <vector>
|
||||
|
||||
namespace napa {
|
||||
/// <summary> Represents an execution request. </summary>
|
||||
struct ExecuteRequest {
|
||||
/// <summary> Represents a function to call with its arguments. </summary>
|
||||
struct FunctionSpec {
|
||||
|
||||
/// <summary> The module that exports the function to execute. </summary>
|
||||
StringRef module = EMPTY_NAPA_STRING_REF;
|
||||
|
@ -127,7 +127,7 @@ namespace napa {
|
|||
std::vector<StringRef> arguments;
|
||||
|
||||
/// <summary> Execute options. </summary>
|
||||
ExecuteOptions options = { 0, AUTO };
|
||||
CallOptions options = { 0, AUTO };
|
||||
|
||||
/// <summary> Used for transporting shared_ptr and unique_ptr across zones/workers. </summary>
|
||||
mutable std::unique_ptr<napa::transport::TransportContext> transportContext;
|
||||
|
@ -136,11 +136,11 @@ namespace napa {
|
|||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents a response from executing in a zone. </summary>
|
||||
/// <summary> Represents a result from executing in a zone. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> A response code. </summary>
|
||||
napa_response_code code;
|
||||
/// <summary> A result code. </summary>
|
||||
napa_result_code code;
|
||||
|
||||
/// <summary> The error message in case of an error. </summary>
|
||||
napa_string_ref error_message;
|
||||
|
@ -150,16 +150,16 @@ typedef struct {
|
|||
|
||||
/// <summary> A context used for transporting handles across zones/workers. </summary>
|
||||
void* transport_context;
|
||||
} napa_zone_execute_response;
|
||||
} napa_zone_result;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
/// <summary> Represents an execution response. </summary>
|
||||
struct ExecuteResponse {
|
||||
/// <summary> Represents a function call result. </summary>
|
||||
struct Result {
|
||||
|
||||
/// <summary> A response code. </summary>
|
||||
ResponseCode code;
|
||||
/// <summary> A result code. </summary>
|
||||
ResultCode code;
|
||||
|
||||
/// <summary> The error message in case of an error. </summary>
|
||||
std::string errorMessage;
|
||||
|
@ -175,16 +175,16 @@ namespace napa {
|
|||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Callback signatures. </summary>
|
||||
typedef void(*napa_zone_broadcast_callback)(napa_response_code code, void* context);
|
||||
typedef void(*napa_zone_execute_callback)(napa_zone_execute_response response, void* context);
|
||||
typedef void(*napa_zone_broadcast_callback)(napa_result_code code, void* context);
|
||||
typedef void(*napa_zone_execute_callback)(napa_zone_result result, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace napa {
|
||||
typedef std::function<void(ResponseCode)> BroadcastCallback;
|
||||
typedef std::function<void(ExecuteResponse)> ExecuteCallback;
|
||||
typedef std::function<void(ResultCode)> BroadcastCallback;
|
||||
typedef std::function<void(Result)> ExecuteCallback;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
#include <napa/v8-helpers/json.h>
|
||||
#include <napa/v8-helpers/object.h>
|
||||
#include <napa/v8-helpers/ptr.h>
|
||||
#include <napa/v8-helpers/string.h>
|
||||
#include <napa/v8-helpers/string.h>
|
||||
#include <napa/v8-helpers/time.h>
|
|
@ -12,8 +12,8 @@ namespace v8_helpers {
|
|||
/// <param name="argv"> Actual arguments. </param>
|
||||
static void Log(int argc, v8::Local<v8::Value> argv[]) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
auto console = v8::Local<v8::Object>::Cast(context->Global()->Get(
|
||||
v8_helpers::MakeV8String(isolate, "console")));
|
||||
|
|
|
@ -19,9 +19,9 @@ namespace v8_helpers {
|
|||
v8::Local<v8::Value> argv[] = nullptr) {
|
||||
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
auto function = context->Global()->Get(v8_helpers::MakeV8String(isolate, functionName));
|
||||
|
||||
JS_ENSURE_WITH_RETURN(
|
||||
|
@ -49,9 +49,9 @@ namespace v8_helpers {
|
|||
v8::Local<v8::Value> argv[] = nullptr) {
|
||||
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
auto function = object->Get(v8_helpers::MakeV8String(isolate, functionName));
|
||||
|
||||
JS_ENSURE_WITH_RETURN(
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace v8_helpers {
|
|||
/// <summary> JSON.stringify </summary>
|
||||
/// TODO @asib: Use v8::JSON::Stringify when available
|
||||
inline v8::MaybeLocal<v8::String> Stringify(v8::Isolate* isolate, const v8::Local<v8::Value>& value) {
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
auto json = context->Global()
|
||||
->Get(context, v8::String::NewFromUtf8(isolate, "JSON"))
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <v8.h>
|
||||
#include <napa/stl/string.h>
|
||||
|
||||
namespace napa {
|
||||
namespace v8_helpers {
|
||||
|
||||
static const uint32_t NANOS_PER_SECOND = 1000000000;
|
||||
|
||||
/// <summary> Make a v8 array from high-resolution time. </summary>
|
||||
inline v8::Local<v8::Array> HrtimeToV8Uint32Array(v8::Isolate* isolate, uint64_t time) {
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
v8::Local<v8::Array> res = v8::Array::New(isolate, 2);
|
||||
(void)res->CreateDataProperty(
|
||||
context,
|
||||
0,
|
||||
v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(time / NANOS_PER_SECOND)));
|
||||
|
||||
(void)res->CreateDataProperty(
|
||||
context,
|
||||
1,
|
||||
v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(time % NANOS_PER_SECOND)));
|
||||
|
||||
return scope.Escape(res);
|
||||
}
|
||||
|
||||
/// <summary> Convert a 2-element v8 array to high-resolution time in nano-seconds. </summary>
|
||||
inline std::pair<uint64_t, bool> V8Uint32ArrayToHrtime(v8::Isolate* isolate, v8::Local<v8::Value> value) {
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
if (value.IsEmpty() || !value->IsArray()) {
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
|
||||
auto array = v8::Local<v8::Array>::Cast(value);
|
||||
if (array->Length() != 2) {
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
return std::make_pair(static_cast<uint64_t>(array->Get(0)->Uint32Value()) * NANOS_PER_SECOND + array->Get(1)->Uint32Value(), true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
#include <functional>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
namespace zone {
|
||||
|
||||
/// <summary> Function to run asynchronously in separate thread. </summary>
|
||||
/// <remarks> Return value will be the input to 'AsyncCompleteCallback'. </remarks>
|
|
@ -8,7 +8,7 @@
|
|||
#include <vector>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
namespace zone {
|
||||
|
||||
/// <summary> Function to run asynchronously in separate thread. </summary>
|
||||
/// <remarks> Return value will be the input to 'AsyncCompleteCallback'. </remarks>
|
|
@ -6,4 +6,8 @@ import * as store from './store';
|
|||
import * as transport from './transport';
|
||||
import * as zone from './zone';
|
||||
|
||||
export { log, memory, metric, runtime, store, transport, zone };
|
||||
export { log, memory, metric, runtime, store, transport, zone };
|
||||
|
||||
// Add execute proxy to global context.
|
||||
import { call } from './zone/function-call';
|
||||
(<any>(global))["__napa_zone_call__"] = call;
|
26
lib/zone.ts
26
lib/zone.ts
|
@ -1,6 +1,5 @@
|
|||
import * as napa from './zone/napa-zone';
|
||||
import * as node from './zone/node-zone';
|
||||
import * as zone from './zone/zone';
|
||||
import * as impl from './zone/zone-impl';
|
||||
|
||||
import * as platform from './runtime/platform';
|
||||
|
||||
|
@ -14,31 +13,32 @@ declare var __in_napa: boolean;
|
|||
/// <param name="settings"> The settings of the new zone. </param>
|
||||
export function create(id: string, settings: zone.ZoneSettings = zone.DEFAULT_SETTINGS) : zone.Zone {
|
||||
platform.initialize();
|
||||
return new napa.NapaZone(binding.createZone(id, settings));
|
||||
return new impl.ZoneImpl(binding.createZone(id, settings));
|
||||
}
|
||||
|
||||
/// <summary> Returns the zone associated with the provided id. </summary>
|
||||
export function get(id: string) : zone.Zone {
|
||||
platform.initialize();
|
||||
if (id === "node") {
|
||||
return new node.NodeZone();
|
||||
}
|
||||
|
||||
return new napa.NapaZone(binding.getZone(id));
|
||||
return new impl.ZoneImpl(binding.getZone(id));
|
||||
}
|
||||
|
||||
/// TODO: add function getOrCreate(id: string, settings: zone.ZoneSettings): Zone.
|
||||
|
||||
/// <summary> Define a getter property 'current' to retrieves the current zone. </summary>
|
||||
/// <summary> Define a getter property 'current' to retrieve the current zone. </summary>
|
||||
export declare let current: zone.Zone;
|
||||
Object.defineProperty(exports, "current", {
|
||||
get: function () : zone.Zone {
|
||||
platform.initialize();
|
||||
if (typeof __in_napa !== 'undefined') {
|
||||
return new napa.NapaZone(binding.getCurrentZone());
|
||||
}
|
||||
return new impl.ZoneImpl(binding.getCurrentZone());
|
||||
}
|
||||
});
|
||||
|
||||
return new node.NodeZone();
|
||||
/// <summary> Define a getter property 'node' to retrieve node zone. </summary>
|
||||
export declare let node: zone.Zone;
|
||||
Object.defineProperty(exports, "node", {
|
||||
get: function () : zone.Zone {
|
||||
platform.initialize();
|
||||
return new impl.ZoneImpl(binding.getZone('node'));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
import * as transport from '../transport';
|
||||
import { CallOptions } from './zone';
|
||||
|
||||
/// <summary> Rejection type </summary>
|
||||
/// TODO: we need a better mapping between error code and result code.
|
||||
export enum RejectionType {
|
||||
TIMEOUT = 3,
|
||||
APP_ERROR = 6
|
||||
}
|
||||
|
||||
/// <summary> Interface for Call context. </summary>
|
||||
export interface CallContext {
|
||||
|
||||
/// <summary> Resolve task with marshalled result. </summary>
|
||||
resolve(result: string): void;
|
||||
|
||||
/// <summary> Reject task with reason. </summary>
|
||||
reject(reason: any): void;
|
||||
|
||||
/// <summary> Reject task with a rejection type and reason. </summary>
|
||||
reject(type: RejectionType, reason: any): void;
|
||||
|
||||
/// <summary> Returns whether task has finished (either completed or cancelled). </summary>
|
||||
readonly finished: boolean;
|
||||
|
||||
/// <summary> Elapse in nano-seconds since task started. </summary>
|
||||
readonly elapse: [number, number];
|
||||
|
||||
/// <summary> Module name to select function. </summary>
|
||||
readonly module: string;
|
||||
|
||||
/// <summary> Function name to execute. </summary>
|
||||
readonly function: string;
|
||||
|
||||
/// <summary> Marshalled arguments. </summary>
|
||||
readonly args: string[];
|
||||
|
||||
/// <summary> Transport context. </summary>
|
||||
readonly transportContext: transport.TransportContext;
|
||||
|
||||
/// <summary> Execute options. </summary>
|
||||
readonly options: CallOptions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy function for __napa_zone_call__.
|
||||
/// 1) calling a global function:
|
||||
/// module name: undefined or empty string
|
||||
/// function name: global function name
|
||||
/// 2) calling an anonymous function at client side:
|
||||
/// module name: literal '__function'
|
||||
/// function name: hash returned from transport.saveFunction().
|
||||
/// 3) calling a function from a module:
|
||||
/// module name: target module path.
|
||||
/// function name: target function name from the module.
|
||||
///
|
||||
/// function name can have multiple levels like 'foo.bar'.
|
||||
/// </summary>
|
||||
export function call(context: CallContext): void {
|
||||
// Cache the context since every call to context.transportContext will create a new wrap upon inner TransportContext pointer.
|
||||
let transportContext = context.transportContext;
|
||||
let result: any = undefined;
|
||||
try {
|
||||
result = callFunction(
|
||||
context.module,
|
||||
context.function,
|
||||
context.args,
|
||||
transportContext,
|
||||
context.options);
|
||||
}
|
||||
catch(error) {
|
||||
context.reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result != null
|
||||
&& typeof result === 'object'
|
||||
&& typeof result['then'] === 'function') {
|
||||
// Delay completion if return value is a promise.
|
||||
result.then((value: any) => {
|
||||
finishCall(context, transportContext, value);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
context.reject(error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
finishCall(context, transportContext, result);
|
||||
}
|
||||
|
||||
/// <summary> Call a function. </summary>
|
||||
function callFunction(
|
||||
moduleName: string,
|
||||
functionName: string,
|
||||
marshalledArgs: string[],
|
||||
transportContext: transport.TransportContext,
|
||||
options: CallOptions): any {
|
||||
|
||||
let module: any = null;
|
||||
if (moduleName == null || moduleName.length === 0) {
|
||||
module = global;
|
||||
} else if (moduleName !== '__function') {
|
||||
module = require(moduleName);
|
||||
}
|
||||
|
||||
let func = null;
|
||||
if (module != null) {
|
||||
func = module;
|
||||
if (functionName != null && functionName.length != 0) {
|
||||
var path = functionName.split('.');
|
||||
for (let item of path) {
|
||||
func = func[item];
|
||||
if (func === undefined) {
|
||||
throw new Error("Cannot find function '" + functionName + "' in module '" + moduleName + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof func !== 'function') {
|
||||
throw new Error("'" + functionName + "' in module '" + moduleName + "' is not a function");
|
||||
}
|
||||
} else {
|
||||
// Anonymous function.
|
||||
func = transport.loadFunction(functionName);
|
||||
}
|
||||
|
||||
let args = marshalledArgs.map((arg) => { return transport.unmarshall(arg, transportContext); });
|
||||
return func.apply(this, args);
|
||||
}
|
||||
|
||||
/// <summary> Finish call with result. </summary>
|
||||
function finishCall(
|
||||
context: CallContext,
|
||||
transportContext: transport.TransportContext,
|
||||
result: any) {
|
||||
|
||||
let payload: string = undefined;
|
||||
try {
|
||||
payload = transport.marshall(result, transportContext);
|
||||
}
|
||||
catch (error) {
|
||||
context.reject(error);
|
||||
return;
|
||||
}
|
||||
context.resolve(payload);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
import * as zone from "./zone";
|
||||
|
||||
/// <summary> A virtual Zone consists only 1 worker, which is Node event loop. </summary>
|
||||
export class NodeZone implements zone.Zone {
|
||||
|
||||
public get id(): string {
|
||||
return "node";
|
||||
}
|
||||
|
||||
public toJSON(): any {
|
||||
return { id: this.id, type: "node" };
|
||||
}
|
||||
|
||||
public broadcast(arg1: any, arg2?: any) : Promise<void> {
|
||||
// TODO @asib: add implementation
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public broadcastSync(arg1: any, arg2?: any) : void {
|
||||
// TODO @asib: add implementation
|
||||
}
|
||||
|
||||
public execute(arg1: any, arg2: any, arg3?: any, arg4?: any) : Promise<zone.ExecuteResult> {
|
||||
// TODO @asib: add implementation
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public executeSync(arg1: any, arg2: any, arg3?: any, arg4?: any) : zone.ExecuteResult {
|
||||
// TODO @asib: add implementation
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -1,17 +1,15 @@
|
|||
import * as zone from './zone';
|
||||
import * as transport from '../transport';
|
||||
|
||||
declare var __in_napa: boolean;
|
||||
|
||||
interface ExecuteRequest {
|
||||
interface FunctionSpec {
|
||||
module: string;
|
||||
function: string;
|
||||
arguments: any[];
|
||||
options: zone.ExecuteOptions;
|
||||
options: zone.CallOptions;
|
||||
transportContext: transport.TransportContext;
|
||||
}
|
||||
|
||||
export class NapaExecuteResult implements zone.ExecuteResult{
|
||||
class ExecuteResult implements zone.Result{
|
||||
|
||||
constructor(payload: string, transportContext: transport.TransportContext) {
|
||||
this._payload = payload;
|
||||
|
@ -40,7 +38,7 @@ export class NapaExecuteResult implements zone.ExecuteResult{
|
|||
};
|
||||
|
||||
/// <summary> Zone consists of Napa isolates. </summary>
|
||||
export class NapaZone implements zone.Zone {
|
||||
export class ZoneImpl implements zone.Zone {
|
||||
private _nativeZone: any;
|
||||
|
||||
constructor(nativeZone: any) {
|
||||
|
@ -52,18 +50,18 @@ export class NapaZone implements zone.Zone {
|
|||
}
|
||||
|
||||
public toJSON(): any {
|
||||
return { id: this.id, type: "napa" };
|
||||
return { id: this.id, type: this.id === 'node'? 'node': 'napa' };
|
||||
}
|
||||
|
||||
public broadcast(arg1: any, arg2?: any) : Promise<void> {
|
||||
let source: string = this.createBroadcastSource(arg1, arg2);
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this._nativeZone.broadcast(source, (responseCode: number) => {
|
||||
if (responseCode === 0) {
|
||||
this._nativeZone.broadcast(source, (resultCode: number) => {
|
||||
if (resultCode === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject("broadcast failed with response code: " + responseCode);
|
||||
reject("broadcast failed with result code: " + resultCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -72,36 +70,36 @@ export class NapaZone implements zone.Zone {
|
|||
public broadcastSync(arg1: any, arg2?: any) : void {
|
||||
let source: string = this.createBroadcastSource(arg1, arg2);
|
||||
|
||||
let responseCode: number = this._nativeZone.broadcastSync(source);
|
||||
if (responseCode !== 0) {
|
||||
throw new Error("broadcast failed with response code: " + responseCode);
|
||||
let resultCode: number = this._nativeZone.broadcastSync(source);
|
||||
if (resultCode !== 0) {
|
||||
throw new Error("broadcast failed with result code: " + resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
public execute(arg1: any, arg2: any, arg3?: any, arg4?: any) : Promise<zone.ExecuteResult> {
|
||||
let request : ExecuteRequest = this.createExecuteRequest(arg1, arg2, arg3, arg4);
|
||||
public execute(arg1: any, arg2: any, arg3?: any, arg4?: any) : Promise<zone.Result> {
|
||||
let spec : FunctionSpec = this.createExecuteRequest(arg1, arg2, arg3, arg4);
|
||||
|
||||
return new Promise<zone.ExecuteResult>((resolve, reject) => {
|
||||
this._nativeZone.execute(request, (response: any) => {
|
||||
if (response.code === 0) {
|
||||
resolve(new NapaExecuteResult(
|
||||
response.returnValue,
|
||||
transport.createTransportContext(response.contextHandle)));
|
||||
return new Promise<zone.Result>((resolve, reject) => {
|
||||
this._nativeZone.execute(spec, (result: any) => {
|
||||
if (result.code === 0) {
|
||||
resolve(new ExecuteResult(
|
||||
result.returnValue,
|
||||
transport.createTransportContext(result.contextHandle)));
|
||||
} else {
|
||||
reject(response.errorMessage);
|
||||
reject(result.errorMessage);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public executeSync(arg1: any, arg2: any, arg3?: any, arg4?: any) : zone.ExecuteResult {
|
||||
let request : ExecuteRequest = this.createExecuteRequest(arg1, arg2, arg3, arg4);
|
||||
public executeSync(arg1: any, arg2: any, arg3?: any, arg4?: any) : zone.Result {
|
||||
let spec : FunctionSpec = this.createExecuteRequest(arg1, arg2, arg3, arg4);
|
||||
|
||||
let response = this._nativeZone.executeSync(request);
|
||||
if (response.code === 0) {
|
||||
return new NapaExecuteResult(response.returnValue, transport.createTransportContext(response.contextHandle));
|
||||
let result = this._nativeZone.executeSync(spec);
|
||||
if (result.code === 0) {
|
||||
return new ExecuteResult(result.returnValue, transport.createTransportContext(result.contextHandle));
|
||||
} else {
|
||||
throw new Error(response.errorMessage);
|
||||
throw new Error(result.errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,12 +133,12 @@ export class NapaZone implements zone.Zone {
|
|||
return source;
|
||||
}
|
||||
|
||||
private createExecuteRequest(arg1: any, arg2: any, arg3?: any, arg4?: any) : ExecuteRequest {
|
||||
private createExecuteRequest(arg1: any, arg2: any, arg3?: any, arg4?: any) : FunctionSpec {
|
||||
|
||||
let moduleName: string = null;
|
||||
let functionName: string = null;
|
||||
let args: any[] = null;
|
||||
let options: zone.ExecuteOptions = undefined;
|
||||
let options: zone.CallOptions = undefined;
|
||||
|
||||
if (typeof arg1 === 'function') {
|
||||
moduleName = "__function";
|
||||
|
@ -160,7 +158,7 @@ export class NapaZone implements zone.Zone {
|
|||
module: moduleName,
|
||||
function: functionName,
|
||||
arguments: (<Array<any>>args).map(arg => { return transport.marshall(arg, transportContext); }),
|
||||
options: options != null? options: zone.DEFAULT_EXECUTE_OPTIONS,
|
||||
options: options != null? options: zone.DEFAULT_CALL_OPTIONS,
|
||||
transportContext: transportContext
|
||||
};
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
var transport = require('../lib/transport');
|
||||
|
||||
function __zone_execute__(moduleName, functionName, args, transportContextHandle, options) {
|
||||
var module = null;
|
||||
if (moduleName == null || moduleName.length === 0) {
|
||||
module = this;
|
||||
} else if (moduleName !== '__function') {
|
||||
module = require(moduleName);
|
||||
}
|
||||
|
||||
var func = null;
|
||||
if (module != null) {
|
||||
func = module;
|
||||
if (functionName != null && functionName.length != 0) {
|
||||
var path = functionName.split('.');
|
||||
for (item of path) {
|
||||
func = func[item];
|
||||
if (func === undefined) {
|
||||
throw new Error("Cannot find function '" + functionName + "' in module '" + moduleName + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof func !== 'function') {
|
||||
throw new Error("'" + functionName + "' in module '" + moduleName + "' is not a function");
|
||||
}
|
||||
} else {
|
||||
// Anonymous function.
|
||||
func = transport.loadFunction(functionName);
|
||||
}
|
||||
|
||||
var transportContext = transport.createTransportContext(transportContextHandle);
|
||||
var args = args.map((arg) => { return transport.unmarshall(arg, transportContext); });
|
||||
return transport.marshall(func.apply(this, args), transportContext);
|
||||
}
|
|
@ -27,8 +27,8 @@ export enum TransportOption {
|
|||
MANUAL,
|
||||
}
|
||||
|
||||
/// <summary> Represent the options of an execute call. </summary>
|
||||
export interface ExecuteOptions {
|
||||
/// <summary> Represent the options of calling a function. </summary>
|
||||
export interface CallOptions {
|
||||
|
||||
/// <summary> Timeout in milliseconds. By default set to 0 if timeout is not needed. </summary>
|
||||
timeout?: number,
|
||||
|
@ -38,7 +38,7 @@ export interface ExecuteOptions {
|
|||
}
|
||||
|
||||
/// <summary> Default execution options. </summary>
|
||||
export let DEFAULT_EXECUTE_OPTIONS: ExecuteOptions = {
|
||||
export let DEFAULT_CALL_OPTIONS: CallOptions = {
|
||||
|
||||
/// <summary> No timeout. </summary>
|
||||
timeout: 0,
|
||||
|
@ -48,7 +48,7 @@ export let DEFAULT_EXECUTE_OPTIONS: ExecuteOptions = {
|
|||
}
|
||||
|
||||
/// <summary> Represent the result of an execute call. </summary>
|
||||
export interface ExecuteResult {
|
||||
export interface Result {
|
||||
|
||||
/// <summary> The unmarshalled result value. </summary>
|
||||
readonly value : any;
|
||||
|
@ -81,15 +81,15 @@ export interface Zone {
|
|||
/// <param name="module"> The module name that contains the function to execute. </param>
|
||||
/// <param name="func"> The function name to execute. </param>
|
||||
/// <param name="args"> The arguments that will pass to the function. </param>
|
||||
/// <param name="options"> Execute options, defaults to DEFAULT_EXECUTE_OPTIONS. </param>
|
||||
execute(module: string, func: string, args: any[], options?: ExecuteOptions) : Promise<ExecuteResult>;
|
||||
executeSync(module: string, func: string, args: any[], options?: ExecuteOptions) : ExecuteResult;
|
||||
/// <param name="options"> Call options, defaults to DEFAULT_CALL_OPTIONS. </param>
|
||||
execute(module: string, func: string, args: any[], options?: CallOptions) : Promise<Result>;
|
||||
executeSync(module: string, func: string, args: any[], options?: CallOptions) : Result;
|
||||
|
||||
/// <summary> Executes the function on one of the zone workers. </summary>
|
||||
/// <param name="func"> The JS function to execute. </param>
|
||||
/// <param name="args"> The arguments that will pass to the function. </param>
|
||||
/// <param name="options"> Execute options, defaults to DEFAULT_EXECUTE_OPTIONS. </param>
|
||||
execute(func: Function, args: any[], timeout?: number) : Promise<ExecuteResult>;
|
||||
executeSync(func: Function, args: any[], timeout?: number) : ExecuteResult;
|
||||
/// <param name="options"> Call options, defaults to DEFAULT_CALL_OPTIONS. </param>
|
||||
execute(func: Function, args: any[], timeout?: number) : Promise<Result>;
|
||||
executeSync(func: Function, args: any[], timeout?: number) : Result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# Files to compile
|
||||
file(GLOB SOURCE_FILES "addon.cpp" "../src/module/core-modules/napa/*.cpp")
|
||||
file(GLOB SOURCE_FILES
|
||||
"addon.cpp"
|
||||
"node-zone-delegates.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/zone/call-context.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/zone/call-task.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/zone/eval-task.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/zone/terminable-task.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/module/core-modules/napa/*.cpp")
|
||||
|
||||
# The addon name
|
||||
set(TARGET_NAME "${PROJECT_NAME}-binding")
|
||||
|
@ -13,10 +20,11 @@ set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
|
|||
target_include_directories(${TARGET_NAME} PRIVATE
|
||||
${CMAKE_JS_INC}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_SOURCE_DIR}/src/module/core-modules/napa)
|
||||
|
||||
# Compiler definitions
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE BUILDING_NODE_EXTENSION)
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE BUILDING_NODE_EXTENSION NAPA_BINDING_EXPORTS)
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include "napa-binding.h"
|
||||
#include "node-zone-delegates.h"
|
||||
|
||||
#include <napa.h>
|
||||
#include <napa-module.h>
|
||||
|
||||
#include <zone/node-zone.h>
|
||||
|
||||
void Initialize(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
@ -34,6 +37,8 @@ void Shutdown(const v8::FunctionCallbackInfo<v8::Value>&) {
|
|||
void InitAll(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) {
|
||||
napa::module::binding::Init(exports, module);
|
||||
|
||||
napa::zone::NodeZone::Init(napa::node_zone::Broadcast, napa::node_zone::Execute);
|
||||
|
||||
// Only node addon can initialize/shutdown napa.
|
||||
NAPA_SET_METHOD(exports, "initialize", Initialize);
|
||||
NAPA_SET_METHOD(exports, "shutdown", Shutdown);
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#include "node-zone-delegates.h"
|
||||
|
||||
#include <zone/call-task.h>
|
||||
#include <zone/eval-task.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
struct AsyncContext {
|
||||
/// <summary> libuv request. </summary>
|
||||
uv_async_t work;
|
||||
|
||||
/// <summary> Callback that will be running in Node event loop. </summary>
|
||||
std::function<void()> callback;
|
||||
};
|
||||
|
||||
/// <summary> Run an async work item in Node. </summary>
|
||||
void Run(uv_async_t* work) {
|
||||
auto context = static_cast<AsyncContext*>(work->data);
|
||||
|
||||
context->callback();
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(work), [](auto work) {
|
||||
auto context = static_cast<AsyncContext*>(work->data);
|
||||
delete context;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary> Schedule a function in Node event loop. </summary>
|
||||
void ScheduleInNode(std::function<void()> callback) {
|
||||
auto context = new AsyncContext();
|
||||
context->work.data = context;
|
||||
context->callback = std::move(callback);
|
||||
|
||||
uv_async_init(uv_default_loop(), &context->work, Run);
|
||||
uv_async_send(&context->work);
|
||||
}
|
||||
|
||||
void napa::node_zone::Broadcast(const std::string& source, napa::BroadcastCallback callback) {
|
||||
std::string sourceCopy = source;
|
||||
ScheduleInNode([sourceCopy = std::move(sourceCopy), callback = std::move(callback)]() {
|
||||
napa::zone::EvalTask task(std::move(sourceCopy), "", std::move(callback));
|
||||
task.Execute();
|
||||
});
|
||||
}
|
||||
|
||||
void napa::node_zone::Execute(const napa::FunctionSpec& spec, napa::ExecuteCallback callback) {
|
||||
auto requestContext = std::make_shared<napa::zone::CallContext>(spec, callback);
|
||||
ScheduleInNode([requestContext = std::move(requestContext)]() {
|
||||
napa::zone::CallTask task(std::move(requestContext));
|
||||
task.Execute();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/types.h>
|
||||
|
||||
namespace napa {
|
||||
namespace node_zone {
|
||||
|
||||
/// <summary> Broadcast to Node zone. </summary>
|
||||
void Broadcast(const std::string& source, napa::BroadcastCallback callback);
|
||||
|
||||
/// <summary> Execute in Node zone. </summary>
|
||||
void Execute(const napa::FunctionSpec& spec, napa::ExecuteCallback callback);
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ target_include_directories(${TARGET_NAME}
|
|||
${PROJECT_SOURCE_DIR}/inc)
|
||||
|
||||
# Compiler definitions
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE NAPA_EXPORTS BUILDING_NAPA_EXTENSION)
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE NAPA_EXPORTS BUILDING_NAPA_EXTENSION NAPA_BINDING_EXPORTS)
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE ${Boost_LIBRARIES})
|
||||
|
|
101
src/api/api.cpp
101
src/api/api.cpp
|
@ -3,7 +3,8 @@
|
|||
#include "providers/providers.h"
|
||||
#include "settings/settings-parser.h"
|
||||
#include "v8/v8-common.h"
|
||||
#include "zone/zone-impl.h"
|
||||
#include "zone/napa-zone.h"
|
||||
#include "zone/node-zone.h"
|
||||
|
||||
#include <napa-log.h>
|
||||
|
||||
|
@ -20,12 +21,12 @@
|
|||
using namespace napa;
|
||||
|
||||
static std::atomic<bool> _initialized(false);
|
||||
static PlatformSettings _platformSettings;
|
||||
static settings::PlatformSettings _platformSettings;
|
||||
|
||||
/// <summary> a simple wrapper around Zone for managing lifetime using shared_ptr. </summary>
|
||||
struct napa_zone {
|
||||
std::string id;
|
||||
std::shared_ptr<internal::Zone> zone;
|
||||
std::shared_ptr<zone::Zone> zone;
|
||||
};
|
||||
|
||||
napa_zone_handle napa_zone_create(napa_string_ref id) {
|
||||
|
@ -39,7 +40,13 @@ napa_zone_handle napa_zone_get(napa_string_ref id) {
|
|||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
|
||||
auto zoneId = NAPA_STRING_REF_TO_STD_STRING(id);
|
||||
auto zone = ZoneImpl::Get(zoneId);
|
||||
std::shared_ptr<zone::Zone> zone;
|
||||
if (zoneId == "node") {
|
||||
zone = zone::NodeZone::Get();
|
||||
} else {
|
||||
zone = zone::NapaZone::Get(zoneId);
|
||||
}
|
||||
|
||||
if (!zone) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -50,7 +57,7 @@ napa_zone_handle napa_zone_get(napa_string_ref id) {
|
|||
napa_zone_handle napa_zone_get_current() {
|
||||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
|
||||
auto zone = reinterpret_cast<ZoneImpl*>(napa::module::WorkerContext::Get(napa::module::WorkerContextItem::ZONE));
|
||||
auto zone = reinterpret_cast<zone::Zone*>(zone::WorkerContext::Get(zone::WorkerContextItem::ZONE));
|
||||
if (zone == nullptr) {
|
||||
LOG_WARNING("Api", "Trying to get current zone from a thread that is not associated with a zone");
|
||||
return nullptr;
|
||||
|
@ -59,39 +66,39 @@ napa_zone_handle napa_zone_get_current() {
|
|||
return napa_zone_get(STD_STRING_TO_NAPA_STRING_REF(zone->GetId()));
|
||||
}
|
||||
|
||||
napa_response_code napa_zone_init(napa_zone_handle handle, napa_string_ref settings) {
|
||||
napa_result_code napa_zone_init(napa_zone_handle handle, napa_string_ref settings) {
|
||||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
NAPA_ASSERT(handle, "Zone handle is null");
|
||||
|
||||
// Zone settings are based on platform settings.
|
||||
ZoneSettings zoneSettings = _platformSettings;
|
||||
if (!napa::settings_parser::ParseFromString(NAPA_STRING_REF_TO_STD_STRING(settings), zoneSettings)) {
|
||||
settings::ZoneSettings zoneSettings = _platformSettings;
|
||||
if (!napa::settings::ParseFromString(NAPA_STRING_REF_TO_STD_STRING(settings), zoneSettings)) {
|
||||
LOG_ERROR("Api", "Failed to parse zone settings: %s", settings.data);
|
||||
return NAPA_RESPONSE_SETTINGS_PARSER_ERROR;
|
||||
return NAPA_RESULT_SETTINGS_PARSER_ERROR;
|
||||
}
|
||||
|
||||
zoneSettings.id = handle->id;
|
||||
|
||||
// Create the actual zone.
|
||||
handle->zone = ZoneImpl::Create(zoneSettings);
|
||||
handle->zone = zone::NapaZone::Create(zoneSettings);
|
||||
if (handle->zone == nullptr) {
|
||||
LOG_ERROR("Api", "Failed to initialize zone: %s", handle->id.c_str());
|
||||
return NAPA_RESPONSE_ZONE_INIT_ERROR;
|
||||
return NAPA_RESULT_ZONE_INIT_ERROR;
|
||||
}
|
||||
|
||||
LOG_INFO("Api", "Napa zone '%s' initialized successfully", handle->id.c_str());
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
return NAPA_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
napa_response_code napa_zone_release(napa_zone_handle handle) {
|
||||
napa_result_code napa_zone_release(napa_zone_handle handle) {
|
||||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
NAPA_ASSERT(handle, "Zone handle is null");
|
||||
|
||||
handle->zone = nullptr;
|
||||
delete handle;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
return NAPA_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
napa_string_ref napa_zone_get_id(napa_zone_handle handle) {
|
||||
|
@ -109,54 +116,54 @@ void napa_zone_broadcast(napa_zone_handle handle,
|
|||
NAPA_ASSERT(handle, "Zone handle is null");
|
||||
NAPA_ASSERT(handle->zone, "Zone handle wasn't initialized");
|
||||
|
||||
handle->zone->Broadcast(NAPA_STRING_REF_TO_STD_STRING(source), [callback, context](napa_response_code code) {
|
||||
handle->zone->Broadcast(NAPA_STRING_REF_TO_STD_STRING(source), [callback, context](napa_result_code code) {
|
||||
callback(code, context);
|
||||
});
|
||||
}
|
||||
|
||||
void napa_zone_execute(napa_zone_handle handle,
|
||||
napa_zone_execute_request request,
|
||||
napa_zone_function_spec spec,
|
||||
napa_zone_execute_callback callback,
|
||||
void* context) {
|
||||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
NAPA_ASSERT(handle, "Zone handle is null");
|
||||
NAPA_ASSERT(handle->zone, "Zone handle wasn't initialized");
|
||||
|
||||
ExecuteRequest req;
|
||||
req.module = request.module;
|
||||
req.function = request.function;
|
||||
FunctionSpec req;
|
||||
req.module = spec.module;
|
||||
req.function = spec.function;
|
||||
|
||||
req.arguments.reserve(request.arguments_count);
|
||||
for (size_t i = 0; i < request.arguments_count; i++) {
|
||||
req.arguments.emplace_back(request.arguments[i]);
|
||||
req.arguments.reserve(spec.arguments_count);
|
||||
for (size_t i = 0; i < spec.arguments_count; i++) {
|
||||
req.arguments.emplace_back(spec.arguments[i]);
|
||||
}
|
||||
|
||||
req.options = request.options;
|
||||
req.options = spec.options;
|
||||
|
||||
// Assume ownership of transport context
|
||||
req.transportContext.reset(reinterpret_cast<napa::transport::TransportContext*>(request.transport_context));
|
||||
req.transportContext.reset(reinterpret_cast<napa::transport::TransportContext*>(spec.transport_context));
|
||||
|
||||
handle->zone->Execute(req, [callback, context](ExecuteResponse response) {
|
||||
napa_zone_execute_response res;
|
||||
res.code = response.code;
|
||||
res.error_message = STD_STRING_TO_NAPA_STRING_REF(response.errorMessage);
|
||||
res.return_value = STD_STRING_TO_NAPA_STRING_REF(response.returnValue);
|
||||
handle->zone->Execute(req, [callback, context](Result result) {
|
||||
napa_zone_result res;
|
||||
res.code = result.code;
|
||||
res.error_message = STD_STRING_TO_NAPA_STRING_REF(result.errorMessage);
|
||||
res.return_value = STD_STRING_TO_NAPA_STRING_REF(result.returnValue);
|
||||
|
||||
// Release ownership of transport context
|
||||
res.transport_context = reinterpret_cast<void*>(response.transportContext.release());
|
||||
res.transport_context = reinterpret_cast<void*>(result.transportContext.release());
|
||||
|
||||
callback(res, context);
|
||||
});
|
||||
}
|
||||
|
||||
static napa_response_code napa_initialize_common() {
|
||||
static napa_result_code napa_initialize_common() {
|
||||
if (!napa::providers::Initialize(_platformSettings)) {
|
||||
return NAPA_RESPONSE_PROVIDERS_INIT_ERROR;
|
||||
return NAPA_RESULT_PROVIDERS_INIT_ERROR;
|
||||
}
|
||||
|
||||
if (_platformSettings.initV8) {
|
||||
if (!napa::v8_common::Initialize()) {
|
||||
return NAPA_RESPONSE_V8_INIT_ERROR;
|
||||
return NAPA_RESULT_V8_INIT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,30 +171,30 @@ static napa_response_code napa_initialize_common() {
|
|||
|
||||
LOG_INFO("Api", "Napa initialized successfully");
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
return NAPA_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
napa_response_code napa_initialize(napa_string_ref settings) {
|
||||
napa_result_code napa_initialize(napa_string_ref settings) {
|
||||
NAPA_ASSERT(!_initialized, "Napa was already initialized");
|
||||
|
||||
if (!napa::settings_parser::ParseFromString(NAPA_STRING_REF_TO_STD_STRING(settings), _platformSettings)) {
|
||||
return NAPA_RESPONSE_SETTINGS_PARSER_ERROR;
|
||||
if (!napa::settings::ParseFromString(NAPA_STRING_REF_TO_STD_STRING(settings), _platformSettings)) {
|
||||
return NAPA_RESULT_SETTINGS_PARSER_ERROR;
|
||||
}
|
||||
|
||||
return napa_initialize_common();
|
||||
}
|
||||
|
||||
napa_response_code napa_initialize_from_console(int argc, char* argv[]) {
|
||||
napa_result_code napa_initialize_from_console(int argc, char* argv[]) {
|
||||
NAPA_ASSERT(!_initialized, "Napa was already initialized");
|
||||
|
||||
if (!napa::settings_parser::ParseFromConsole(argc, argv, _platformSettings)) {
|
||||
return NAPA_RESPONSE_SETTINGS_PARSER_ERROR;
|
||||
if (!napa::settings::ParseFromConsole(argc, argv, _platformSettings)) {
|
||||
return NAPA_RESULT_SETTINGS_PARSER_ERROR;
|
||||
}
|
||||
|
||||
return napa_initialize_common();
|
||||
}
|
||||
|
||||
napa_response_code napa_shutdown() {
|
||||
napa_result_code napa_shutdown() {
|
||||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
|
||||
napa::providers::Shutdown();
|
||||
|
@ -198,23 +205,23 @@ napa_response_code napa_shutdown() {
|
|||
|
||||
LOG_INFO("Api", "Napa shutdown successfully");
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
return NAPA_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#define NAPA_RESPONSE_CODE_DEF(symbol, string_rep) string_rep
|
||||
#define NAPA_RESULT_CODE_DEF(symbol, string_rep) string_rep
|
||||
|
||||
static const char* NAPA_REPONSE_CODE_STRINGS[] = {
|
||||
#include "napa/response-codes.inc"
|
||||
#include "napa/result-codes.inc"
|
||||
};
|
||||
|
||||
#undef NAPA_RESPONSE_CODE_DEF
|
||||
#undef NAPA_RESULT_CODE_DEF
|
||||
|
||||
template<class T, size_t N>
|
||||
constexpr size_t size(T(&)[N]) { return N; }
|
||||
|
||||
const char* napa_response_code_to_string(napa_response_code code) {
|
||||
NAPA_ASSERT(code < size(NAPA_REPONSE_CODE_STRINGS), "response code out of range");
|
||||
const char* napa_result_code_to_string(napa_result_code code) {
|
||||
NAPA_ASSERT(code < size(NAPA_REPONSE_CODE_STRINGS), "result code out of range");
|
||||
|
||||
return NAPA_REPONSE_CODE_STRINGS[code];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
#include "call-context-wrap.h"
|
||||
#include "transport-context-wrap-impl.h"
|
||||
|
||||
#include <napa/module/common.h>
|
||||
#include <napa-transport.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
|
||||
NAPA_DEFINE_PERSISTENT_CONSTRUCTOR(CallContextWrap)
|
||||
|
||||
void CallContextWrap::Init() {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto constructorTemplate = v8::FunctionTemplate::New(isolate, DefaultConstructorCallback<CallContextWrap>);
|
||||
constructorTemplate->SetClassName(v8_helpers::MakeV8String(isolate, exportName));
|
||||
constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
InitConstructorTemplate<CallContextWrap>(constructorTemplate);
|
||||
|
||||
NAPA_SET_PROTOTYPE_METHOD(constructorTemplate, "resolve", ResolveCallback);
|
||||
NAPA_SET_PROTOTYPE_METHOD(constructorTemplate, "reject", RejectCallback);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "finished", IsFinishedCallback, nullptr);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "elapse", GetElapseCallback, nullptr);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "module", GetModuleCallback, nullptr);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "function", GetFunctionCallback, nullptr);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "args", GetArgumentsCallback, nullptr);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "transportContext", GetTransportContextCallback, nullptr);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "options", GetOptionsCallback, nullptr);
|
||||
|
||||
auto constructor = constructorTemplate->GetFunction();
|
||||
InitConstructor("<CallContextWrap>", constructor);
|
||||
NAPA_SET_PERSISTENT_CONSTRUCTOR(exportName, constructor);
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> CallContextWrap::NewInstance(std::shared_ptr<zone::CallContext> call) {
|
||||
return ShareableWrap::NewInstance<CallContextWrap>(call);
|
||||
}
|
||||
|
||||
zone::CallContext& CallContextWrap::GetRef() {
|
||||
return ShareableWrap::GetRef<zone::CallContext>();
|
||||
}
|
||||
|
||||
void CallContextWrap::ResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 1, "1 argument of 'result' is required for \"resolve\".");
|
||||
|
||||
v8::String::Utf8Value result(args[0]);
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
auto success = thisObject->GetRef().Resolve(std::string(*result, result.length()));
|
||||
|
||||
JS_ENSURE(isolate, success, "Resolve call failed: Already finished.");
|
||||
}
|
||||
|
||||
void CallContextWrap::RejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 1 || args.Length() == 2, "at least 1 argument of 'reason' is required for \"reject\".");
|
||||
|
||||
napa::ResultCode code = NAPA_RESULT_EXECUTE_FUNC_ERROR;
|
||||
v8::Local<v8::Value> reason;
|
||||
|
||||
if (args.Length() == 1) {
|
||||
reason = args[0];
|
||||
} else {
|
||||
CHECK_ARG(isolate, args[0]->IsUint32(), "arg 'resultCode' should be a number type.");
|
||||
code = static_cast<napa::ResultCode>(args[0]->Uint32Value());
|
||||
|
||||
reason = args[1];
|
||||
}
|
||||
|
||||
v8::String::Utf8Value reasonStr(reason);
|
||||
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
auto success = thisObject->GetRef().Reject(code, std::string(*reasonStr, reasonStr.length()));
|
||||
JS_ENSURE(isolate, success, "Reject call failed: Already finished.");
|
||||
}
|
||||
|
||||
void CallContextWrap::IsFinishedCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args){
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
args.GetReturnValue().Set(thisObject->GetRef().IsFinished());
|
||||
}
|
||||
|
||||
void CallContextWrap::GetElapseCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args){
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
args.GetReturnValue().Set(v8_helpers::HrtimeToV8Uint32Array(isolate, thisObject->GetRef().GetElapse().count()));
|
||||
}
|
||||
|
||||
void CallContextWrap::GetModuleCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
args.GetReturnValue().Set(v8_helpers::MakeV8String(isolate, thisObject->GetRef().GetModule()));
|
||||
}
|
||||
|
||||
void CallContextWrap::GetFunctionCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
args.GetReturnValue().Set(v8_helpers::MakeV8String(isolate, thisObject->GetRef().GetFunction()));
|
||||
}
|
||||
|
||||
void CallContextWrap::GetArgumentsCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
|
||||
auto& cppArgs = thisObject->GetRef().GetArguments();
|
||||
auto jsArgs = v8::Array::New(isolate, static_cast<int>(cppArgs.size()));
|
||||
for (size_t i = 0; i < cppArgs.size(); ++i) {
|
||||
(void)jsArgs->CreateDataProperty(context, static_cast<uint32_t>(i), v8_helpers::MakeExternalV8String(isolate, cppArgs[i]));
|
||||
}
|
||||
args.GetReturnValue().Set(jsArgs);
|
||||
}
|
||||
|
||||
void CallContextWrap::GetTransportContextCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
auto thisObject = NAPA_OBJECTWRAP::Unwrap<CallContextWrap>(args.Holder());
|
||||
|
||||
auto& transportContext = thisObject->GetRef().GetTransportContext();
|
||||
auto wrap = TransportContextWrapImpl::NewInstance(&transportContext);
|
||||
args.GetReturnValue().Set(wrap);
|
||||
}
|
||||
|
||||
void CallContextWrap::GetOptionsCallback(v8::Local<v8::String> /*propertyName*/, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
// Prepare execute options.
|
||||
// NOTE: export necessary fields from CallContext.GetOptions to jsOptions object here. Now it's empty.
|
||||
auto jsOptions = v8::ObjectTemplate::New(isolate)->NewInstance();
|
||||
|
||||
args.GetReturnValue().Set(jsOptions);
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa-module.h>
|
||||
#include <napa/module/common.h>
|
||||
#include <napa/module/shareable-wrap.h>
|
||||
|
||||
#include <zone/call-context.h>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
|
||||
/// <summary>
|
||||
/// Class that wraps zone::CallContext, which enables JavaScript world to
|
||||
/// resolve or reject a function call.
|
||||
/// </summary>
|
||||
class CallContextWrap: public ShareableWrap {
|
||||
public:
|
||||
/// <summary> It creates a persistent constructor for CallContextWrap instance. </summary>
|
||||
static void Init();
|
||||
|
||||
/// <summary> Create a new instance of wrap associating with specific call context. </summary>
|
||||
static v8::Local<v8::Object> NewInstance(std::shared_ptr<zone::CallContext> call);
|
||||
|
||||
/// <summary> Get call context. </summary>
|
||||
zone::CallContext& GetRef();
|
||||
|
||||
/// <summary> Exported class name. </summary>
|
||||
static constexpr const char* exportName = "CallContextWrap";
|
||||
|
||||
/// <summary> Declare constructor in public, so we can export class constructor in JavaScript world. </summary>
|
||||
NAPA_DECLARE_PERSISTENT_CONSTRUCTOR
|
||||
|
||||
protected:
|
||||
/// <summary> It implements CallContext.resolve(result: any): void </summary>
|
||||
static void ResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.reject(reason: string): void </summary>
|
||||
static void RejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.finished: boolean </summary>
|
||||
static void IsFinishedCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.module: string </summary>
|
||||
static void GetModuleCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.function: string </summary>
|
||||
static void GetFunctionCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.args: string[] </summary>
|
||||
static void GetArgumentsCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.transportContext: TransportContext </summary>
|
||||
static void GetTransportContextCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.options: CallOptions </summary>
|
||||
static void GetOptionsCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> It implements CallContext.elapse: [number, number] (precision in nano-second) </summary>
|
||||
static void GetElapseCallback(v8::Local<v8::String> propertyName, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,18 @@
|
|||
#include "metric-wrap.h"
|
||||
#include "allocator-debugger-wrap.h"
|
||||
#include "allocator-wrap.h"
|
||||
#include "call-context-wrap.h"
|
||||
#include "shared-ptr-wrap.h"
|
||||
#include "store-wrap.h"
|
||||
#include "transport-context-wrap-impl.h"
|
||||
#include "zone-wrap.h"
|
||||
|
||||
#include <zone/worker-context.h>
|
||||
|
||||
#include <napa.h>
|
||||
#include <napa-memory.h>
|
||||
#include <napa/module/binding.h>
|
||||
#include <napa/module/binding/wraps.h>
|
||||
#include <napa/module/worker-context.h>
|
||||
#include <napa/providers/logging.h>
|
||||
#include <napa/providers/metric.h>
|
||||
|
||||
|
@ -23,7 +26,16 @@ static void RegisterBinding(v8::Local<v8::Object> module) {
|
|||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto persistentModule = new v8::Persistent<v8::Object>(isolate, module);
|
||||
WorkerContext::Set(WorkerContextItem::NAPA_BINDING, persistentModule);
|
||||
zone::WorkerContext::Set(zone::WorkerContextItem::NAPA_BINDING, persistentModule);
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> napa::module::binding::GetModule() {
|
||||
auto persistentModule =
|
||||
reinterpret_cast<v8::Persistent<v8::Object>*>(
|
||||
zone::WorkerContext::Get(zone::WorkerContextItem::NAPA_BINDING));
|
||||
|
||||
NAPA_ASSERT(persistentModule != nullptr, "\"napajs\" must be required before napa::module::binding::GetModule() can be called from C++.");
|
||||
return v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), *persistentModule);
|
||||
}
|
||||
|
||||
static void CreateZone(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
|
@ -194,6 +206,7 @@ void binding::Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module)
|
|||
AllocatorDebuggerWrap::Init();
|
||||
AllocatorWrap::Init();
|
||||
MetricWrap::Init();
|
||||
CallContextWrap::Init();
|
||||
SharedPtrWrap::Init();
|
||||
StoreWrap::Init();
|
||||
TransportContextWrapImpl::Init();
|
||||
|
@ -202,6 +215,7 @@ void binding::Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module)
|
|||
NAPA_EXPORT_OBJECTWRAP(exports, "AllocatorDebuggerWrap", AllocatorDebuggerWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "AllocatorWrap", AllocatorWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "MetricWrap", MetricWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "CallContextWrap", CallContextWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "SharedPtrWrap", SharedPtrWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "TransportContextWrap", TransportContextWrapImpl);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\allocator-debugger-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\allocator-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\call-context-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\metric-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\napa-binding.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\shared-ptr-wrap.cpp" />
|
||||
|
|
|
@ -12,6 +12,14 @@ TransportContextWrapImpl::TransportContextWrapImpl(TransportContext* context) {
|
|||
_context = context;
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> TransportContextWrapImpl::NewInstance(napa::transport::TransportContext* context) {
|
||||
auto object = napa::module::NewInstance<TransportContextWrapImpl>().ToLocalChecked();
|
||||
auto wrap = NAPA_OBJECTWRAP::Unwrap<TransportContextWrapImpl>(object);
|
||||
wrap->_context = context;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
TransportContext* TransportContextWrapImpl::Get() {
|
||||
return _context;
|
||||
}
|
||||
|
@ -19,14 +27,14 @@ TransportContext* TransportContextWrapImpl::Get() {
|
|||
void TransportContextWrapImpl::Init() {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto constructorTemplate = v8::FunctionTemplate::New(isolate, TransportContextWrapImpl::ConstructorCallback);
|
||||
constructorTemplate->SetClassName(MakeV8String(isolate, _exportName));
|
||||
constructorTemplate->SetClassName(MakeV8String(isolate, exportName));
|
||||
constructorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
NAPA_SET_PROTOTYPE_METHOD(constructorTemplate, "saveShared", SaveSharedCallback);
|
||||
NAPA_SET_PROTOTYPE_METHOD(constructorTemplate, "loadShared", LoadSharedCallback);
|
||||
NAPA_SET_ACCESSOR(constructorTemplate, "sharedCount", GetSharedCountCallback, nullptr);
|
||||
|
||||
NAPA_SET_PERSISTENT_CONSTRUCTOR(_exportName, constructorTemplate->GetFunction());
|
||||
NAPA_SET_PERSISTENT_CONSTRUCTOR(exportName, constructorTemplate->GetFunction());
|
||||
}
|
||||
|
||||
void TransportContextWrapImpl::GetSharedCountCallback(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& args){
|
||||
|
|
|
@ -13,12 +13,18 @@ namespace module {
|
|||
/// <summary> Init this wrap. </summary>
|
||||
static void Init();
|
||||
|
||||
/// <summary> Create a non-owning transport context wrap. </summary>
|
||||
static v8::Local<v8::Object> NewInstance(napa::transport::TransportContext* context);
|
||||
|
||||
/// <summary> Get transport context. </summary>
|
||||
napa::transport::TransportContext* Get() override;
|
||||
|
||||
/// <summary> Declare constructor in public, so we can export class constructor to JavaScript world. </summary>
|
||||
NAPA_DECLARE_PERSISTENT_CONSTRUCTOR
|
||||
|
||||
/// <summary> Exported class name. </summary>
|
||||
static constexpr const char* exportName = "TransportContextWrap";
|
||||
|
||||
private:
|
||||
/// <summary> Constructor. </summary>
|
||||
TransportContextWrapImpl(napa::transport::TransportContext* context);
|
||||
|
@ -39,9 +45,6 @@ namespace module {
|
|||
/// <summary> It implements TransportContext.loadShared(handle: Handle): napajs.memory.ShareableWrap) </summary>
|
||||
static void LoadSharedCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary> Exported class name. </summary>
|
||||
static constexpr const char* _exportName = "TransportContextWrap";
|
||||
|
||||
/// <summary> Non-owning transport context. </summary>
|
||||
napa::transport::TransportContext* _context;
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <napa.h>
|
||||
#include <napa-assert.h>
|
||||
#include <napa-async.h>
|
||||
#include <napa/v8-helpers.h>
|
||||
|
||||
#include <sstream>
|
||||
|
@ -15,7 +16,7 @@ using namespace napa::v8_helpers;
|
|||
NAPA_DEFINE_PERSISTENT_CONSTRUCTOR(ZoneWrap);
|
||||
|
||||
// Forward declaration.
|
||||
static v8::Local<v8::Object> CreateResponseObject(const napa::ExecuteResponse& response);
|
||||
static v8::Local<v8::Object> CreateResponseObject(const napa::Result& result);
|
||||
template <typename Func>
|
||||
static void CreateRequestAndExecute(v8::Local<v8::Object> obj, Func&& func);
|
||||
|
||||
|
@ -66,23 +67,22 @@ void ZoneWrap::Broadcast(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
|
||||
v8::String::Utf8Value source(args[0]->ToString());
|
||||
|
||||
napa::module::DoAsyncWork(v8::Local<v8::Function>::Cast(args[1]),
|
||||
napa::zone::DoAsyncWork(v8::Local<v8::Function>::Cast(args[1]),
|
||||
[&args, &source](std::function<void(void*)> complete) {
|
||||
auto wrap = ObjectWrap::Unwrap<ZoneWrap>(args.Holder());
|
||||
|
||||
wrap->_zoneProxy->Broadcast(*source, [complete = std::move(complete)](ResponseCode responseCode) {
|
||||
complete(reinterpret_cast<void*>(static_cast<uintptr_t>(responseCode)));
|
||||
wrap->_zoneProxy->Broadcast(*source, [complete = std::move(complete)](ResultCode resultCode) {
|
||||
complete(reinterpret_cast<void*>(static_cast<uintptr_t>(resultCode)));
|
||||
});
|
||||
},
|
||||
[](auto jsCallback, void* result) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
std::vector<v8::Local<v8::Value>> argv;
|
||||
auto responseCode = static_cast<ResponseCode>(reinterpret_cast<uintptr_t>(result));
|
||||
argv.emplace_back(v8::Uint32::NewFromUnsigned(isolate, responseCode));
|
||||
auto resultCode = static_cast<ResultCode>(reinterpret_cast<uintptr_t>(result));
|
||||
argv.emplace_back(v8::Uint32::NewFromUnsigned(isolate, resultCode));
|
||||
|
||||
(void)jsCallback->Call(context, context->Global(), static_cast<int>(argv.size()), argv.data());
|
||||
}
|
||||
|
@ -97,41 +97,41 @@ void ZoneWrap::BroadcastSync(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
v8::String::Utf8Value source(args[0]->ToString());
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ZoneWrap>(args.Holder());
|
||||
auto responseCode = wrap->_zoneProxy->BroadcastSync(*source);
|
||||
auto resultCode = wrap->_zoneProxy->BroadcastSync(*source);
|
||||
|
||||
args.GetReturnValue().Set(v8::Uint32::NewFromUnsigned(isolate, responseCode));
|
||||
args.GetReturnValue().Set(v8::Uint32::NewFromUnsigned(isolate, resultCode));
|
||||
}
|
||||
|
||||
void ZoneWrap::Execute(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "first argument to zone.execute must be the execution request object");
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "first argument to zone.execute must be the function spec object");
|
||||
CHECK_ARG(isolate, args[1]->IsFunction(), "second argument to zone.execute must be the callback");
|
||||
|
||||
napa::module::DoAsyncWork(v8::Local<v8::Function>::Cast(args[1]),
|
||||
napa::zone::DoAsyncWork(v8::Local<v8::Function>::Cast(args[1]),
|
||||
[&args](std::function<void(void*)> complete) {
|
||||
CreateRequestAndExecute(args[0]->ToObject(), [&args, &complete](const napa::ExecuteRequest& request) {
|
||||
CreateRequestAndExecute(args[0]->ToObject(), [&args, &complete](const napa::FunctionSpec& spec) {
|
||||
auto wrap = ObjectWrap::Unwrap<ZoneWrap>(args.Holder());
|
||||
|
||||
wrap->_zoneProxy->Execute(request, [complete = std::move(complete)](napa::ExecuteResponse response) {
|
||||
complete(new napa::ExecuteResponse(std::move(response)));
|
||||
wrap->_zoneProxy->Execute(spec, [complete = std::move(complete)](napa::Result result) {
|
||||
complete(new napa::Result(std::move(result)));
|
||||
});
|
||||
});
|
||||
},
|
||||
[](auto jsCallback, void* result) {
|
||||
[](auto jsCallback, void* res) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
auto response = static_cast<napa::ExecuteResponse*>(result);
|
||||
auto result = static_cast<napa::Result*>(res);
|
||||
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
std::vector<v8::Local<v8::Value>> argv;
|
||||
argv.emplace_back(CreateResponseObject(*response));
|
||||
argv.emplace_back(CreateResponseObject(*result));
|
||||
|
||||
(void)jsCallback->Call(context, context->Global(), static_cast<int>(argv.size()), argv.data());
|
||||
|
||||
delete response;
|
||||
delete result;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -139,17 +139,17 @@ void ZoneWrap::Execute(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
void ZoneWrap::ExecuteSync(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "first argument to zone.execute must be the execution request object");
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "first argument to zone.execute must be the function spec object");
|
||||
|
||||
CreateRequestAndExecute(args[0]->ToObject(), [&args](const napa::ExecuteRequest& request) {
|
||||
CreateRequestAndExecute(args[0]->ToObject(), [&args](const napa::FunctionSpec& spec) {
|
||||
auto wrap = ObjectWrap::Unwrap<ZoneWrap>(args.Holder());
|
||||
|
||||
napa::ExecuteResponse response = wrap->_zoneProxy->ExecuteSync(request);
|
||||
args.GetReturnValue().Set(CreateResponseObject(response));
|
||||
napa::Result result = wrap->_zoneProxy->ExecuteSync(spec);
|
||||
args.GetReturnValue().Set(CreateResponseObject(result));
|
||||
});
|
||||
}
|
||||
|
||||
static v8::Local<v8::Object> CreateResponseObject(const napa::ExecuteResponse& response) {
|
||||
static v8::Local<v8::Object> CreateResponseObject(const napa::Result& result) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
|
@ -158,23 +158,23 @@ static v8::Local<v8::Object> CreateResponseObject(const napa::ExecuteResponse& r
|
|||
(void)responseObject->CreateDataProperty(
|
||||
context,
|
||||
MakeV8String(isolate, "code"),
|
||||
v8::Uint32::NewFromUnsigned(isolate, response.code));
|
||||
v8::Uint32::NewFromUnsigned(isolate, result.code));
|
||||
|
||||
(void)responseObject->CreateDataProperty(
|
||||
context,
|
||||
MakeV8String(isolate, "errorMessage"),
|
||||
MakeV8String(isolate, response.errorMessage));
|
||||
MakeV8String(isolate, result.errorMessage));
|
||||
|
||||
(void)responseObject->CreateDataProperty(
|
||||
context,
|
||||
MakeV8String(isolate, "returnValue"),
|
||||
MakeV8String(isolate, response.returnValue));
|
||||
MakeV8String(isolate, result.returnValue));
|
||||
|
||||
// Transport context handle
|
||||
(void)responseObject->CreateDataProperty(
|
||||
context,
|
||||
MakeV8String(isolate, "contextHandle"),
|
||||
PtrToV8Uint32Array(isolate, response.transportContext.release()));
|
||||
PtrToV8Uint32Array(isolate, result.transportContext.release()));
|
||||
|
||||
return responseObject;
|
||||
}
|
||||
|
@ -184,35 +184,35 @@ static void CreateRequestAndExecute(v8::Local<v8::Object> obj, Func&& func) {
|
|||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
napa::ExecuteRequest request;
|
||||
napa::FunctionSpec spec;
|
||||
|
||||
// module property is optional in a request
|
||||
// module property is optional in a spec
|
||||
Utf8String module;
|
||||
auto maybe = obj->Get(context, MakeV8String(isolate, "module"));
|
||||
if (!maybe.IsEmpty()) {
|
||||
module = Utf8String(maybe.ToLocalChecked());
|
||||
request.module = NAPA_STRING_REF_WITH_SIZE(module.Data(), module.Length());
|
||||
spec.module = NAPA_STRING_REF_WITH_SIZE(module.Data(), module.Length());
|
||||
}
|
||||
|
||||
// function property is mandatory in a request
|
||||
// function property is mandatory in a spec
|
||||
maybe = obj->Get(context, MakeV8String(isolate, "function"));
|
||||
CHECK_ARG(isolate, !maybe.IsEmpty(), "function property is missing in execution request object");
|
||||
CHECK_ARG(isolate, !maybe.IsEmpty(), "function property is missing in function spec object");
|
||||
|
||||
auto functionValue = maybe.ToLocalChecked();
|
||||
CHECK_ARG(isolate, functionValue->IsString(), "function property in execution request object must be a string");
|
||||
CHECK_ARG(isolate, functionValue->IsString(), "function property in function spec object must be a string");
|
||||
|
||||
v8::String::Utf8Value function(functionValue->ToString());
|
||||
request.function = NAPA_STRING_REF_WITH_SIZE(*function, static_cast<size_t>(function.length()));
|
||||
spec.function = NAPA_STRING_REF_WITH_SIZE(*function, static_cast<size_t>(function.length()));
|
||||
|
||||
// arguments are optional in a request
|
||||
// arguments are optional in a spec
|
||||
maybe = obj->Get(context, MakeV8String(isolate, "arguments"));
|
||||
std::vector<Utf8String> arguments;
|
||||
if (!maybe.IsEmpty()) {
|
||||
arguments = V8ArrayToVector<Utf8String>(isolate, v8::Local<v8::Array>::Cast(maybe.ToLocalChecked()));
|
||||
|
||||
request.arguments.reserve(arguments.size());
|
||||
spec.arguments.reserve(arguments.size());
|
||||
for (const auto& arg : arguments) {
|
||||
request.arguments.emplace_back(NAPA_STRING_REF_WITH_SIZE(arg.Data(), arg.Length()));
|
||||
spec.arguments.emplace_back(NAPA_STRING_REF_WITH_SIZE(arg.Data(), arg.Length()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,23 +226,23 @@ static void CreateRequestAndExecute(v8::Local<v8::Object> obj, Func&& func) {
|
|||
// timeout is optional.
|
||||
maybe = options->Get(context, MakeV8String(isolate, "timeout"));
|
||||
if (!maybe.IsEmpty()) {
|
||||
request.options.timeout = maybe.ToLocalChecked()->Uint32Value(context).FromJust();
|
||||
spec.options.timeout = maybe.ToLocalChecked()->Uint32Value(context).FromJust();
|
||||
}
|
||||
|
||||
// transport option is optional.
|
||||
maybe = options->Get(context, MakeV8String(isolate, "transport"));
|
||||
if (!maybe.IsEmpty()) {
|
||||
request.options.transport = static_cast<napa::TransportOption>(maybe.ToLocalChecked()->Uint32Value(context).FromJust());
|
||||
spec.options.transport = static_cast<napa::TransportOption>(maybe.ToLocalChecked()->Uint32Value(context).FromJust());
|
||||
}
|
||||
}
|
||||
|
||||
// transportContext property is mandatory in a request
|
||||
// transportContext property is mandatory in a spec
|
||||
maybe = obj->Get(context, MakeV8String(isolate, "transportContext"));
|
||||
CHECK_ARG(isolate, !maybe.IsEmpty(), "transportContext property is missing in execution request object");
|
||||
CHECK_ARG(isolate, !maybe.IsEmpty(), "transportContext property is missing in function spec object");
|
||||
|
||||
auto transportContextWrap = NAPA_OBJECTWRAP::Unwrap<TransportContextWrapImpl>(maybe.ToLocalChecked()->ToObject());
|
||||
request.transportContext.reset(transportContextWrap->Get());
|
||||
spec.transportContext.reset(transportContextWrap->Get());
|
||||
|
||||
// Execute
|
||||
func(request);
|
||||
func(spec);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "os.h"
|
||||
|
||||
#include <napa-module.h>
|
||||
#include <napa/module/platform.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "path.h"
|
||||
|
||||
#include <napa-module.h>
|
||||
#include <napa/module/platform.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <string>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "process.h"
|
||||
|
||||
#include <napa-module.h>
|
||||
#include <napa/module/platform.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
@ -122,8 +122,6 @@ namespace {
|
|||
}
|
||||
|
||||
void HrtimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
const static uint32_t NANOS_PER_SECOND = 1000000000;
|
||||
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
@ -132,30 +130,13 @@ namespace {
|
|||
uint64_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
|
||||
if (args.Length() == 1) {
|
||||
CHECK_ARG(isolate, args[0]->IsArray(), "process.hrtime only accepts an Array tuple");
|
||||
|
||||
auto arr = v8::Local<v8::Array>::Cast(args[0]);
|
||||
CHECK_ARG(isolate, arr->Length() == 2, "process.hrtime only accepts an Array tuple of size 2");
|
||||
|
||||
uint64_t prev = (static_cast<uint64_t>(arr->Get(0)->Uint32Value()) * NANOS_PER_SECOND)
|
||||
+ arr->Get(1)->Uint32Value();
|
||||
auto result = v8_helpers::V8Uint32ArrayToHrtime(isolate, args[0]);
|
||||
JS_ENSURE(isolate, result.second, "The 1st argument of hrtime must be a two-element uint32 array.");
|
||||
|
||||
// Calculate the delta
|
||||
time -= prev;
|
||||
time -= result.first;
|
||||
}
|
||||
|
||||
v8::Local<v8::Array> res = v8::Array::New(isolate, 2);
|
||||
(void)res->CreateDataProperty(
|
||||
context,
|
||||
0,
|
||||
v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(time / NANOS_PER_SECOND)));
|
||||
|
||||
(void)res->CreateDataProperty(
|
||||
context,
|
||||
1,
|
||||
v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(time % NANOS_PER_SECOND)));
|
||||
|
||||
args.GetReturnValue().Set(res);
|
||||
args.GetReturnValue().Set(v8_helpers::HrtimeToV8Uint32Array(isolate, time));
|
||||
}
|
||||
|
||||
void UmaskCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "tty-wrap.h"
|
||||
|
||||
#include <napa-module.h>
|
||||
#include <napa/module/platform.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "module-loader-helpers.h"
|
||||
#include "core-modules/node/file-system-helpers.h"
|
||||
#include <module/core-modules/node/file-system-helpers.h>
|
||||
|
||||
#include <napa-log.h>
|
||||
#include <napa/v8-helpers.h>
|
|
@ -8,7 +8,10 @@
|
|||
#include "module-loader-helpers.h"
|
||||
#include "module-resolver.h"
|
||||
|
||||
#include "core-modules/core-modules.h"
|
||||
#include <module/core-modules/core-modules.h>
|
||||
|
||||
// TODO: decouple dependencies between moduler-loader and zone.
|
||||
#include <zone/worker-context.h>
|
||||
|
||||
#include <napa-log.h>
|
||||
#include <napa-module.h>
|
||||
|
@ -104,10 +107,10 @@ private:
|
|||
};
|
||||
|
||||
void ModuleLoader::CreateModuleLoader() {
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(WorkerContext::Get(WorkerContextItem::MODULE_LOADER));
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(zone::WorkerContext::Get(zone::WorkerContextItem::MODULE_LOADER));
|
||||
if (moduleLoader == nullptr) {
|
||||
moduleLoader = new ModuleLoader();
|
||||
WorkerContext::Set(WorkerContextItem::MODULE_LOADER, moduleLoader);
|
||||
zone::WorkerContext::Set(zone::WorkerContextItem::MODULE_LOADER, moduleLoader);
|
||||
|
||||
// Now, Javascript core module's 'require' can find module loader instance correctly.
|
||||
moduleLoader->_impl->Bootstrap();
|
||||
|
@ -184,7 +187,7 @@ void ModuleLoader::ModuleLoaderImpl::RequireCallback(const v8::FunctionCallbackI
|
|||
args.Length() == 1 || args.Length() == 2 || args[0]->IsString(),
|
||||
"Invalid arguments");
|
||||
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(WorkerContext::Get(WorkerContextItem::MODULE_LOADER));
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(zone::WorkerContext::Get(zone::WorkerContextItem::MODULE_LOADER));
|
||||
JS_ENSURE(isolate, moduleLoader != nullptr, "Module loader is not initialized");
|
||||
|
||||
v8::String::Utf8Value path(args[0]);
|
||||
|
@ -197,7 +200,7 @@ void ModuleLoader::ModuleLoaderImpl::ResolveCallback(const v8::FunctionCallbackI
|
|||
|
||||
CHECK_ARG(isolate, args.Length() == 1 && args[0]->IsString(), "Invalid arguments");
|
||||
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(WorkerContext::Get(WorkerContextItem::MODULE_LOADER));
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(zone::WorkerContext::Get(zone::WorkerContextItem::MODULE_LOADER));
|
||||
JS_ENSURE(isolate, moduleLoader != nullptr, "Module loader is not initialized");
|
||||
|
||||
v8::String::Utf8Value path(args[0]);
|
||||
|
@ -213,7 +216,7 @@ void ModuleLoader::ModuleLoaderImpl::BindingCallback(const v8::FunctionCallbackI
|
|||
|
||||
CHECK_ARG(isolate, args.Length() == 1 && args[0]->IsString(), "Invalid arguments");
|
||||
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(WorkerContext::Get(WorkerContextItem::MODULE_LOADER));
|
||||
auto moduleLoader = reinterpret_cast<ModuleLoader*>(zone::WorkerContext::Get(zone::WorkerContextItem::MODULE_LOADER));
|
||||
JS_ENSURE(isolate, moduleLoader != nullptr, "Module loader is not initialized");
|
||||
|
||||
v8::String::Utf8Value name(args[0]);
|
|
@ -1,6 +1,6 @@
|
|||
#include "module-resolver.h"
|
||||
|
||||
#include <napa/module/platform.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
|
@ -0,0 +1,47 @@
|
|||
#include <napa/module/module-internal.h>
|
||||
|
||||
#include <zone/worker-context.h>
|
||||
|
||||
using namespace napa;
|
||||
|
||||
/// <summary> It sets the persistent constructor at the current V8 isolate. </summary>
|
||||
/// <param name="name"> Unique constructor name. It's recommended to use the same name as module. </param>
|
||||
/// <param name="constructor"> V8 persistent function to constructor V8 object. </param>
|
||||
void napa::module::SetPersistentConstructor(const char* name,
|
||||
v8::Local<v8::Function> constructor) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto constructorInfo =
|
||||
static_cast<ConstructorInfo*>(zone::WorkerContext::Get(zone::WorkerContextItem::CONSTRUCTOR));
|
||||
if (constructorInfo == nullptr) {
|
||||
constructorInfo = new ConstructorInfo();
|
||||
zone::WorkerContext::Set(zone::WorkerContextItem::CONSTRUCTOR, constructorInfo);
|
||||
}
|
||||
|
||||
constructorInfo->constructorMap.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(name),
|
||||
std::forward_as_tuple(isolate, constructor));
|
||||
}
|
||||
|
||||
/// <summary> It gets the given persistent constructor from the current V8 isolate. </summary>
|
||||
/// <param name="name"> Unique constructor name given at SetPersistentConstructor() call. </param>
|
||||
/// <returns> V8 local function object. </returns>
|
||||
v8::Local<v8::Function> napa::module::GetPersistentConstructor(const char* name) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
|
||||
auto constructorInfo =
|
||||
static_cast<ConstructorInfo*>(zone::WorkerContext::Get(zone::WorkerContextItem::CONSTRUCTOR));
|
||||
if (constructorInfo == nullptr) {
|
||||
return scope.Escape(v8::Local<v8::Function>());
|
||||
}
|
||||
|
||||
auto iter = constructorInfo->constructorMap.find(name);
|
||||
if (iter != constructorInfo->constructorMap.end()) {
|
||||
auto constructor = v8::Local<v8::Function>::New(isolate, iter->second);
|
||||
return scope.Escape(constructor);
|
||||
} else {
|
||||
return scope.Escape(v8::Local<v8::Function>());
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
#include <string>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
namespace platform {
|
||||
|
||||
/// <summary> Global variable to indicate the number of process arguments. </summary>
|
||||
|
@ -44,5 +43,4 @@ namespace platform {
|
|||
int32_t Isatty(int32_t fd);
|
||||
|
||||
} // End of namespce platform.
|
||||
} // End of namespce module
|
||||
} // End of namespce napa.
|
|
@ -3,7 +3,7 @@
|
|||
#include <cstdint>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
namespace platform {
|
||||
namespace tls {
|
||||
|
||||
/// <summary> Allocate a thread local storage index. </summary>
|
|
@ -1,4 +1,4 @@
|
|||
#include <napa/module/platform.h>
|
||||
#include <platform/platform.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <windows.h>
|
||||
|
||||
using namespace napa::module;
|
||||
using namespace napa;
|
||||
|
||||
int platform::argc = __argc;
|
||||
char** platform::argv = __argv;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <napa/module/thread-local-storage.h>
|
||||
#include <platform/thread-local-storage.h>
|
||||
#include <windows.h>
|
||||
|
||||
using namespace napa::module;
|
||||
using namespace napa::platform;
|
||||
|
||||
uint32_t tls::Alloc() {
|
||||
return TlsAlloc();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "nop-logging-provider.h"
|
||||
#include "nop-metric-provider.h"
|
||||
|
||||
#include "module/module-resolver.h"
|
||||
#include <module/loader/module-resolver.h>
|
||||
|
||||
#include <napa-log.h>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::providers;
|
||||
|
||||
// Forward declarations.
|
||||
|
@ -25,7 +25,7 @@ static LoggingProvider* _loggingProvider = LoadLoggingProvider("");
|
|||
static MetricProvider* _metricProvider = LoadMetricProvider("");
|
||||
|
||||
|
||||
bool napa::providers::Initialize(const napa::PlatformSettings& settings) {
|
||||
bool napa::providers::Initialize(const settings::PlatformSettings& settings) {
|
||||
_loggingProvider = LoadLoggingProvider(settings.loggingProvider);
|
||||
_metricProvider = LoadMetricProvider(settings.metricProvider);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace napa {
|
|||
namespace providers {
|
||||
|
||||
/// <summary> Initializes and loads all providers based on the provided settings. </summary>
|
||||
bool Initialize(const napa::PlatformSettings& settings);
|
||||
bool Initialize(const settings::PlatformSettings& settings);
|
||||
|
||||
/// <summary> Clean up and destroy all loaded providers. </summary>
|
||||
void Shutdown();
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
#include "execute-task.h"
|
||||
|
||||
#include <napa-log.h>
|
||||
#include <napa/v8-helpers.h>
|
||||
|
||||
#include <v8.h>
|
||||
|
||||
using namespace napa::scheduler;
|
||||
using namespace napa::v8_helpers;
|
||||
|
||||
napa::scheduler::ExecuteTask::ExecuteTask(const ExecuteRequest& request, ExecuteCallback callback) :
|
||||
_module(NAPA_STRING_REF_TO_STD_STRING(request.module)),
|
||||
_func(NAPA_STRING_REF_TO_STD_STRING(request.function)),
|
||||
_callback(std::move(callback)) {
|
||||
|
||||
_args.reserve(request.arguments.size());
|
||||
for (auto& arg : request.arguments) {
|
||||
_args.emplace_back(NAPA_STRING_REF_TO_STD_STRING(arg));
|
||||
}
|
||||
_options = request.options;
|
||||
|
||||
// Pass ownership of the transport context to the execute task.
|
||||
_transportContext = std::move(request.transportContext);
|
||||
}
|
||||
|
||||
void ExecuteTask::Execute() {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
// Get the module based main function from global scope.
|
||||
auto executeFunction = context->Global()->Get(MakeExternalV8String(isolate, "__zone_execute__"));
|
||||
NAPA_ASSERT(executeFunction->IsFunction(), "__zone_execute__ function must exist in global scope");
|
||||
|
||||
// Prepare function args
|
||||
auto args = v8::Array::New(isolate, static_cast<int>(_args.size()));
|
||||
for (size_t i = 0; i < _args.size(); ++i) {
|
||||
(void)args->CreateDataProperty(context, static_cast<uint32_t>(i), MakeExternalV8String(isolate, _args[i]));
|
||||
}
|
||||
|
||||
// Prepare execute options.
|
||||
// NOTE: export necessary fields from _options to options object here. Now it's empty.
|
||||
auto options = v8::ObjectTemplate::New(isolate)->NewInstance();
|
||||
|
||||
v8::Local<v8::Value> argv[] = {
|
||||
MakeExternalV8String(isolate, _module),
|
||||
MakeExternalV8String(isolate, _func),
|
||||
args,
|
||||
PtrToV8Uint32Array(isolate, _transportContext.get()),
|
||||
options
|
||||
};
|
||||
|
||||
// Execute the function.
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
auto res = v8::Local<v8::Function>::Cast(executeFunction)->Call(context->Global(), 5, argv);
|
||||
|
||||
// Terminating an isolate may occur from a different thread, i.e. from timeout service.
|
||||
// If the function call already finished successfully when the isolate is terminated it may lead
|
||||
// to one the following:
|
||||
// 1. Terminate was called before tryCatch.HasTerminated(), the user gets an error code.
|
||||
// 2. Terminate was called after tryCatch.HasTerminated(), the user gets a success code.
|
||||
//
|
||||
// In both cases the isolate is being restored since this happens before each task executes.
|
||||
if (tryCatch.HasTerminated()) {
|
||||
if (_terminationReason == TerminationReason::TIMEOUT) {
|
||||
LOG_ERROR("Execute", "Task was terminated due to timeout");
|
||||
_callback({ NAPA_RESPONSE_TIMEOUT, "Execute exceeded timeout", "", std::move(_transportContext) });
|
||||
} else {
|
||||
LOG_ERROR("Execute", "Task was terminated for unknown reason");
|
||||
_callback({ NAPA_RESPONSE_INTERNAL_ERROR, "Execute task terminated", "", std::move(_transportContext) });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (tryCatch.HasCaught()) {
|
||||
auto exception = tryCatch.Exception();
|
||||
v8::String::Utf8Value exceptionStr(exception);
|
||||
auto stackTrace = tryCatch.StackTrace();
|
||||
v8::String::Utf8Value stackTraceStr(stackTrace);
|
||||
|
||||
LOG_ERROR("Execute", "JS exception thrown: %s - %s", *exceptionStr, *stackTraceStr);
|
||||
|
||||
_callback({ NAPA_RESPONSE_EXECUTE_FUNC_ERROR, *exceptionStr, "", std::move(_transportContext) });
|
||||
return;
|
||||
}
|
||||
|
||||
v8::String::Utf8Value val(res);
|
||||
_callback({ NAPA_RESPONSE_SUCCESS, "", std::string(*val, val.length()), std::move(_transportContext) });
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "terminable-task.h"
|
||||
|
||||
#include <napa/types.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace napa {
|
||||
namespace scheduler {
|
||||
|
||||
/// <summary> A task for executing pre-loaded javascript functions. </summary>
|
||||
class ExecuteTask : public TerminableTask {
|
||||
public:
|
||||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
/// <param name="callback"> A callback that is triggered when the execute task is completed. </param>
|
||||
ExecuteTask(const ExecuteRequest& request, ExecuteCallback callback);
|
||||
|
||||
/// <summary> Overrides Task.Execute to define execution logic. </summary>
|
||||
virtual void Execute() override;
|
||||
|
||||
private:
|
||||
std::string _module;
|
||||
std::string _func;
|
||||
std::vector<std::string> _args;
|
||||
ExecuteOptions _options;
|
||||
ExecuteCallback _callback;
|
||||
std::unique_ptr<napa::transport::TransportContext> _transportContext;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
using namespace boost::program_options;
|
||||
using namespace napa;
|
||||
using namespace napa::settings;
|
||||
|
||||
static void AddZoneOptions(options_description& desc, ZoneSettings& settings) {
|
||||
// Zone parsing options should be added here.
|
||||
|
@ -26,7 +27,7 @@ static void AddPlatformOptions(options_description& desc, PlatformSettings& sett
|
|||
("initV8", value(&settings.initV8), "specify whether v8 should be initialized");
|
||||
}
|
||||
|
||||
bool settings_parser::Parse(const std::vector<std::string>& args, ZoneSettings& settings) {
|
||||
bool settings::Parse(const std::vector<std::string>& args, ZoneSettings& settings) {
|
||||
options_description desc;
|
||||
AddZoneOptions(desc, settings);
|
||||
|
||||
|
@ -45,7 +46,7 @@ bool settings_parser::Parse(const std::vector<std::string>& args, ZoneSettings&
|
|||
return true;
|
||||
}
|
||||
|
||||
bool settings_parser::Parse(const std::vector<std::string>& args, PlatformSettings& settings) {
|
||||
bool settings::Parse(const std::vector<std::string>& args, PlatformSettings& settings) {
|
||||
options_description desc;
|
||||
AddZoneOptions(desc, settings);
|
||||
AddPlatformOptions(desc, settings);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <vector>
|
||||
|
||||
namespace napa {
|
||||
namespace settings_parser {
|
||||
namespace settings {
|
||||
|
||||
/// <summary> Parses napa settings from a vector of arguments. </summary>
|
||||
/// <param name="str"> The arguments holding the settings. </param>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
|
||||
namespace napa {
|
||||
namespace settings {
|
||||
|
||||
/// <summary> Zone specific settings. </summary>
|
||||
struct ZoneSettings {
|
||||
|
@ -45,4 +46,5 @@ namespace napa {
|
|||
/// <summary> A flag to specify whether v8 should be initialized. </summary>
|
||||
bool initV8 = true;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
#include <v8.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
using namespace napa::zone;
|
||||
|
||||
AsyncCompleteTask::AsyncCompleteTask(std::shared_ptr<AsyncContext> context) : _context(std::move(context)) {}
|
||||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
#include "async-context.h"
|
||||
|
||||
#include <scheduler/task.h>
|
||||
#include <zone/task.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
namespace zone {
|
||||
|
||||
/// <summary> A task to run Javascript callback after asynchronous callback completes. </summary>
|
||||
class AsyncCompleteTask : public scheduler::Task {
|
||||
class AsyncCompleteTask : public Task {
|
||||
public:
|
||||
|
||||
/// <summary> Constructor. </summary>
|
|
@ -1,26 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/module/napa-async-runner.h>
|
||||
#include <scheduler/worker.h>
|
||||
#include <zone/zone-impl.h>
|
||||
#include <napa/zone/napa-async-runner.h>
|
||||
|
||||
#include <zone/worker.h>
|
||||
#include <zone/napa-zone.h>
|
||||
|
||||
#include <v8.h>
|
||||
|
||||
#include <future>
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
namespace zone {
|
||||
|
||||
/// <summary> Class holding asynchonous callbacks. </summary>
|
||||
struct AsyncContext {
|
||||
/// <summary> Zone instance issueing asynchronous work. </summary>
|
||||
ZoneImpl* zone = nullptr;
|
||||
NapaZone* zone = nullptr;
|
||||
|
||||
/// <summary> Keep scheduler instance referenced until async work completes. </summary>
|
||||
std::shared_ptr<scheduler::Scheduler> scheduler;
|
||||
std::shared_ptr<zone::Scheduler> scheduler;
|
||||
|
||||
/// <summary> Worker Id issueing asynchronous work. </summary>
|
||||
scheduler::WorkerId workerId;
|
||||
zone::WorkerId workerId;
|
||||
|
||||
/// <summary> Future to wait async callback. </summary>
|
||||
std::future<void> future;
|
||||
|
@ -38,5 +39,5 @@ namespace module {
|
|||
AsyncCompleteCallback asyncCompleteCallback;
|
||||
};
|
||||
|
||||
} // End of namespace scheduler.
|
||||
} // End of namespace zone.
|
||||
} // End of namespace napa.
|
|
@ -1,10 +1,11 @@
|
|||
#include <napa/module/worker-context.h>
|
||||
#include <napa/module/napa-async-runner.h>
|
||||
#include <scheduler/async-complete-task.h>
|
||||
#include <zone/zone-impl.h>
|
||||
#include <napa/zone/napa-async-runner.h>
|
||||
|
||||
#include <zone/async-complete-task.h>
|
||||
#include <zone/worker-context.h>
|
||||
#include <zone/napa-zone.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
using namespace napa::zone;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -23,9 +24,9 @@ namespace {
|
|||
/// <param name="jsCallback"> Javascript callback. </summary>
|
||||
/// <param name="asyncWork"> Function to run asynchronously in separate thread. </param>
|
||||
/// <param name="asyncCompleteCallback"> Callback running in V8 isolate after asynchronous callback completes. </param>
|
||||
void napa::module::PostAsyncWork(v8::Local<v8::Function> jsCallback,
|
||||
AsyncWork asyncWork,
|
||||
AsyncCompleteCallback asyncCompleteCallback) {
|
||||
void napa::zone::PostAsyncWork(v8::Local<v8::Function> jsCallback,
|
||||
AsyncWork asyncWork,
|
||||
AsyncCompleteCallback asyncCompleteCallback) {
|
||||
auto context = PrepareAsyncWork(jsCallback, std::move(asyncWork), std::move(asyncCompleteCallback));
|
||||
if (context == nullptr) {
|
||||
return;
|
||||
|
@ -43,9 +44,9 @@ void napa::module::PostAsyncWork(v8::Local<v8::Function> jsCallback,
|
|||
/// <param name="jsCallback"> Javascript callback. </summary>
|
||||
/// <param name="asyncWork"> Function to wrap async-supporting function. </param>
|
||||
/// <param name="asyncCompleteCallback"> Callback running in V8 isolate after asynchronous function completes. </param>
|
||||
void napa::module::DoAsyncWork(v8::Local<v8::Function> jsCallback,
|
||||
const CompletionWork& asyncWork,
|
||||
AsyncCompleteCallback asyncCompleteCallback) {
|
||||
void napa::zone::DoAsyncWork(v8::Local<v8::Function> jsCallback,
|
||||
const CompletionWork& asyncWork,
|
||||
AsyncCompleteCallback asyncCompleteCallback) {
|
||||
auto context = PrepareAsyncWork(jsCallback, nullptr, std::move(asyncCompleteCallback));
|
||||
if (context == nullptr) {
|
||||
return;
|
||||
|
@ -67,16 +68,16 @@ namespace {
|
|||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto context = std::make_shared<AsyncContext>();
|
||||
auto context = std::make_shared<zone::AsyncContext>();
|
||||
|
||||
context->zone = reinterpret_cast<ZoneImpl*>(WorkerContext::Get(WorkerContextItem::ZONE));
|
||||
context->zone = reinterpret_cast<NapaZone*>(WorkerContext::Get(WorkerContextItem::ZONE));
|
||||
if (context->zone == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
context->scheduler = context->zone->GetScheduler();
|
||||
context->workerId = static_cast<scheduler::WorkerId>(
|
||||
reinterpret_cast<uintptr_t>(module::WorkerContext::Get(WorkerContextItem::WORKER_ID)));
|
||||
context->workerId = static_cast<WorkerId>(
|
||||
reinterpret_cast<uintptr_t>(WorkerContext::Get(WorkerContextItem::WORKER_ID)));
|
||||
|
||||
context->jsCallback.Reset(isolate, jsCallback);
|
||||
context->asyncWork = std::move(asyncWork);
|
|
@ -0,0 +1,87 @@
|
|||
// See: https://groups.google.com/forum/#!topic/nodejs/onA0S01INtw
|
||||
#ifdef BUILDING_NODE_EXTENSION
|
||||
#include <node.h>
|
||||
#endif
|
||||
|
||||
#include "call-context.h"
|
||||
|
||||
//#include <napa-transport.h>
|
||||
#include <napa-log.h>
|
||||
#include <napa/v8-helpers.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace napa::zone;
|
||||
|
||||
CallContext::CallContext(const napa::FunctionSpec& spec, napa::ExecuteCallback callback) :
|
||||
_module(NAPA_STRING_REF_TO_STD_STRING(spec.module)),
|
||||
_function(NAPA_STRING_REF_TO_STD_STRING(spec.function)),
|
||||
_callback(callback),
|
||||
_finished(false) {
|
||||
|
||||
// Audit start time.
|
||||
_startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
_arguments.reserve(spec.arguments.size());
|
||||
for (auto& arg : spec.arguments) {
|
||||
_arguments.emplace_back(NAPA_STRING_REF_TO_STD_STRING(arg));
|
||||
}
|
||||
_options = spec.options;
|
||||
|
||||
// Pass ownership of the transport context.
|
||||
_transportContext = std::move(spec.transportContext);
|
||||
}
|
||||
|
||||
bool CallContext::Resolve(std::string marshalledResult) {
|
||||
auto expected = false;
|
||||
if (!_finished.compare_exchange_strong(expected, true)) {
|
||||
return false;
|
||||
}
|
||||
_callback({
|
||||
NAPA_RESULT_SUCCESS,
|
||||
"",
|
||||
std::move(marshalledResult),
|
||||
std::move(_transportContext)
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallContext::Reject(napa::ResultCode code, std::string reason) {
|
||||
auto expected = false;
|
||||
if (!_finished.compare_exchange_strong(expected, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_ERROR("Execute", "Call was rejected: %s", reason.c_str());
|
||||
|
||||
_callback({ code, reason, "", std::move(_transportContext) });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallContext::IsFinished() const {
|
||||
return _finished;
|
||||
}
|
||||
|
||||
const std::string& CallContext::GetModule() const {
|
||||
return _module;
|
||||
}
|
||||
|
||||
const std::string& CallContext::GetFunction() const {
|
||||
return _function;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& CallContext::GetArguments() const {
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
napa::transport::TransportContext& CallContext::GetTransportContext() {
|
||||
return *_transportContext.get();
|
||||
}
|
||||
|
||||
const napa::CallOptions& CallContext::GetOptions() const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds CallContext::GetElapse() const {
|
||||
return std::chrono::high_resolution_clock::now() - _startTime;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/types.h>
|
||||
#include <v8.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace napa {
|
||||
namespace zone {
|
||||
|
||||
/// <summary> Context of calling a JavaScript function. </summary>
|
||||
class CallContext {
|
||||
|
||||
public:
|
||||
/// <summary> Construct spec from external FunctionSpec. </summary>
|
||||
explicit CallContext(const napa::FunctionSpec& spec, napa::ExecuteCallback callback);
|
||||
|
||||
/// <summary> Resolve current spec. </summary>
|
||||
/// <param name="result"> marshalled return value. </param>
|
||||
/// <returns> True if operation is successful, otherwise if task is already finished before. </returns>
|
||||
//bool Resolve(v8::Local<v8::Value> result);
|
||||
bool Resolve(std::string result);
|
||||
|
||||
/// <summary> Reject current spec. </summary>
|
||||
/// <param name="resultCode"> Response code to return to user. </summary>
|
||||
/// <param name="reason"> Reason of cancellation. </summary>
|
||||
/// <returns> True if operation is successful, otherwise if task is already finished before. </returns>
|
||||
bool Reject(napa::ResultCode code, std::string reason);
|
||||
|
||||
/// <summary> Returns whether current job is completed or cancelled. </summary>
|
||||
bool IsFinished() const;
|
||||
|
||||
/// <summary> Get module name to load function. </summary>
|
||||
const std::string& GetModule() const;
|
||||
|
||||
/// <summary> Get function name to execute. </summary>
|
||||
const std::string& GetFunction() const;
|
||||
|
||||
/// <summary> Get marshalled arguments. </summary>
|
||||
const std::vector<std::string>& GetArguments() const;
|
||||
|
||||
/// <summary> Get transport context. </summary>
|
||||
napa::transport::TransportContext& GetTransportContext();
|
||||
|
||||
/// <summary> Get options. </summary>
|
||||
const napa::CallOptions& GetOptions() const;
|
||||
|
||||
/// <summary> Get elapse since task start in nano-second. </summary>
|
||||
std::chrono::nanoseconds GetElapse() const;
|
||||
|
||||
private:
|
||||
/// <summary> Module name. </summary>
|
||||
std::string _module;
|
||||
|
||||
/// <summary> Function name. </summary>
|
||||
std::string _function;
|
||||
|
||||
/// <summary> Arguments. </summary>
|
||||
std::vector<std::string> _arguments;
|
||||
|
||||
/// <summary> Execute options. </summary>
|
||||
napa::CallOptions _options;
|
||||
|
||||
/// <summary> Transport context. </summary>
|
||||
std::unique_ptr<napa::transport::TransportContext> _transportContext;
|
||||
|
||||
/// <summary> Callback when task completes. </summary>
|
||||
napa::ExecuteCallback _callback;
|
||||
|
||||
/// <summary> Whether this task is finished. </summary>
|
||||
std::atomic<bool> _finished;
|
||||
|
||||
/// <summary> Call start time. </summary>
|
||||
std::chrono::high_resolution_clock::time_point _startTime;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// See: https://groups.google.com/forum/#!topic/nodejs/onA0S01INtw
|
||||
#ifdef BUILDING_NODE_EXTENSION
|
||||
#include <node.h>
|
||||
#endif
|
||||
|
||||
#include "call-task.h"
|
||||
|
||||
#include <module/core-modules/napa/call-context-wrap.h>
|
||||
|
||||
using namespace napa::zone;
|
||||
using namespace napa::v8_helpers;
|
||||
|
||||
napa::zone::CallTask::CallTask(std::shared_ptr<CallContext> context) :
|
||||
_context(std::move(context)) {
|
||||
}
|
||||
|
||||
void CallTask::Execute() {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
// Get the module based main function from global scope.
|
||||
auto executeFunction = context->Global()->Get(MakeExternalV8String(isolate, "__napa_zone_call__"));
|
||||
NAPA_ASSERT(executeFunction->IsFunction(), "__napa_zone_call__ function must exist in global scope");
|
||||
|
||||
// Create task wrap.
|
||||
auto contextWrap = napa::module::CallContextWrap::NewInstance(_context);
|
||||
v8::Local<v8::Value> argv[] = { contextWrap };
|
||||
|
||||
// Execute the function.
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
auto res = v8::Local<v8::Function>::Cast(executeFunction)->Call(context->Global(), 1, argv);
|
||||
|
||||
// Terminating an isolate may occur from a different thread, i.e. from timeout service.
|
||||
// If the function call already finished successfully when the isolate is terminated it may lead
|
||||
// to one the following:
|
||||
// 1. Terminate was called before tryCatch.HasTerminated(), the user gets an error code.
|
||||
// 2. Terminate was called after tryCatch.HasTerminated(), the user gets a success code.
|
||||
//
|
||||
// In both cases the isolate is being restored since this happens before each task executes.
|
||||
if (tryCatch.HasTerminated()) {
|
||||
if (_terminationReason == TerminationReason::TIMEOUT) {
|
||||
(void)_context->Reject(NAPA_RESULT_TIMEOUT, "Terminated due to timeout");
|
||||
} else {
|
||||
(void)_context->Reject(NAPA_RESULT_INTERNAL_ERROR, "Terminated with unknown reason");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NAPA_ASSERT(!tryCatch.HasCaught(), "__napa_zone_call__ should catch all user exceptions and reject task.");
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "call-context.h"
|
||||
#include "terminable-task.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace napa {
|
||||
namespace zone {
|
||||
|
||||
/// <summary> A task for executing pre-loaded javascript functions. </summary>
|
||||
class CallTask : public TerminableTask {
|
||||
public:
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="context"> Call context. </param>
|
||||
CallTask(std::shared_ptr<CallContext> context);
|
||||
|
||||
/// <summary> Overrides Task.Execute to define execution logic. </summary>
|
||||
virtual void Execute() override;
|
||||
|
||||
private:
|
||||
/// <summary> Call context. </summary>
|
||||
std::shared_ptr<CallContext> _context;
|
||||
};
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче