зеркало из https://github.com/microsoft/napajs.git
Merged PR 148659: node binding for runtime apis
- node binding for runtime apis
This commit is contained in:
Родитель
60af9d8341
Коммит
9ae68a15e6
|
@ -0,0 +1,76 @@
|
|||
// Node uses deprecated V8 APIs
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
#include <node.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include "napa/v8-helpers.h"
|
||||
#include "napa-runtime.h"
|
||||
#include "container-wrap.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void Initialize(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
if (args.Length() <= 0)
|
||||
{
|
||||
// No settings provided
|
||||
napa::runtime::InitializeFromConsole(0, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_ARG(
|
||||
isolate,
|
||||
args[0]->IsString() || args[0]->IsObject(),
|
||||
"first argument to initialize must be a string or an object");
|
||||
|
||||
if (args[0]->IsString())
|
||||
{
|
||||
// Settings provided as string
|
||||
|
||||
v8::String::Utf8Value settings(args[0]->ToString());
|
||||
napa::runtime::Initialize(*settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Settings provided as object
|
||||
|
||||
auto settingsObj = args[0]->ToObject(context).ToLocalChecked();
|
||||
|
||||
auto settingsMap = napa::v8_helpers::V8ObjectToMap<std::string>(isolate, settingsObj);
|
||||
|
||||
std::stringstream ss;
|
||||
for (const auto& kv : settingsMap)
|
||||
{
|
||||
ss << " --" << kv.first << " " << kv.second;
|
||||
}
|
||||
|
||||
napa::runtime::Initialize(ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
napa::runtime::Shutdown();
|
||||
}
|
||||
|
||||
void CreateContainer(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
napa::binding::ContainerWrap::NewInstance(args);
|
||||
}
|
||||
|
||||
void InitAll(v8::Local<v8::Object> exports)
|
||||
{
|
||||
napa::binding::ContainerWrap::Init(v8::Isolate::GetCurrent());
|
||||
|
||||
NODE_SET_METHOD(exports, "initialize", Initialize);
|
||||
NODE_SET_METHOD(exports, "shutdown", Shutdown);
|
||||
NODE_SET_METHOD(exports, "createContainer", CreateContainer);
|
||||
|
||||
}
|
||||
|
||||
NODE_MODULE(napa_wrap, InitAll)
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(EnvironmentConfig)" />
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<TargetName>napa_wrap</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{AAB1C309-643B-45EC-A93A-902AD402E31D}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings>4100</DisableSpecificWarnings>
|
||||
<PreprocessorDefinitions>V8_IMMINENT_DEPRECATION_WARNINGS;BUILDING_NODE_EXTENSION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(NapaRoot)\vanilla\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(NapaRoot)\vanilla\src\napa\napa.vcxproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="addon.cpp" />
|
||||
<ClCompile Include="container-wrap.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Binplace Include="$(OutputPath)\$(TargetFileName)">
|
||||
<DestinationFolder>$(NapaVanillaBinplacePath)</DestinationFolder>
|
||||
<DestinationFileName>$(TargetName).node</DestinationFileName>
|
||||
</Binplace>
|
||||
</ItemGroup>
|
||||
<Import Project="$(PACKAGESROOT)\NodeJs.Library\exports.props" />
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,276 @@
|
|||
// Node uses deprecated V8 APIs
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
#include <node.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include "container-wrap.h"
|
||||
#include "napa-runtime.h"
|
||||
#include "napa/v8-helpers.h"
|
||||
#include "node-async-handler.h"
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace napa::binding;
|
||||
|
||||
|
||||
v8::Persistent<v8::Function> ContainerWrap::_constructor;
|
||||
|
||||
|
||||
ContainerWrap::ContainerWrap(std::unique_ptr<napa::runtime::Container> container) :
|
||||
_container(std::move(container))
|
||||
{
|
||||
}
|
||||
|
||||
void ContainerWrap::Init(v8::Isolate* isolate)
|
||||
{
|
||||
// Prepare constructor template
|
||||
v8::Local<v8::FunctionTemplate> functionTemplate = v8::FunctionTemplate::New(isolate, NewCallback);
|
||||
functionTemplate->SetClassName(
|
||||
v8::String::NewFromUtf8(isolate, "ContainerWrap", v8::NewStringType::kNormal).ToLocalChecked());
|
||||
functionTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
// Prototype
|
||||
NODE_SET_PROTOTYPE_METHOD(functionTemplate, "load", Load);
|
||||
NODE_SET_PROTOTYPE_METHOD(functionTemplate, "loadSync", LoadSync);
|
||||
NODE_SET_PROTOTYPE_METHOD(functionTemplate, "loadFile", LoadFile);
|
||||
NODE_SET_PROTOTYPE_METHOD(functionTemplate, "loadFileSync", LoadFileSync);
|
||||
NODE_SET_PROTOTYPE_METHOD(functionTemplate, "run", Run);
|
||||
NODE_SET_PROTOTYPE_METHOD(functionTemplate, "runSync", RunSync);
|
||||
|
||||
// Set constructor method
|
||||
_constructor.Reset(isolate, functionTemplate->GetFunction(isolate->GetCurrentContext()).ToLocalChecked());
|
||||
}
|
||||
|
||||
void ContainerWrap::NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
|
||||
int argc = args.Length();
|
||||
std::vector<v8::Local<v8::Value>> argv;
|
||||
argv.reserve(argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
argv.emplace_back(args[i]);
|
||||
}
|
||||
|
||||
v8::Local<v8::Function> cons = v8::Local<v8::Function>::New(isolate, _constructor);
|
||||
v8::MaybeLocal<v8::Object> instance = cons->NewInstance(
|
||||
isolate->GetCurrentContext(),
|
||||
argc,
|
||||
argv.data());
|
||||
|
||||
if (!instance.IsEmpty())
|
||||
{
|
||||
args.GetReturnValue().Set(instance.ToLocalChecked());
|
||||
}
|
||||
}
|
||||
|
||||
void ContainerWrap::NewCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
std::stringstream ss;
|
||||
if (args.Length() > 0)
|
||||
{
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "first argument to createContainer must be an object");
|
||||
|
||||
v8::Local<v8::Object> settingsObj = args[0]->ToObject(context).ToLocalChecked();
|
||||
|
||||
auto settingsMap = napa::v8_helpers::V8ObjectToMap<std::string>(isolate, settingsObj);
|
||||
|
||||
for (const auto& kv : settingsMap)
|
||||
{
|
||||
ss << " --" << kv.first << " " << kv.second;
|
||||
}
|
||||
}
|
||||
|
||||
auto obj = new ContainerWrap(std::make_unique<napa::runtime::Container>(ss.str()));
|
||||
|
||||
obj->Wrap(args.This());
|
||||
args.GetReturnValue().Set(args.This());
|
||||
}
|
||||
|
||||
void ContainerWrap::Load(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "first parameter to container.load must be the javascript source");
|
||||
CHECK_ARG(isolate, args[1]->IsFunction(), "second parameter to container.load must be the callback");
|
||||
|
||||
v8::String::Utf8Value source(args[0]->ToString());
|
||||
auto callback = v8::Local<v8::Function>::Cast(args[1]);
|
||||
|
||||
auto handler = NodeAsyncHandler<NapaResponseCode>::New(
|
||||
isolate,
|
||||
callback,
|
||||
[isolate](const NapaResponseCode& responseCode) {
|
||||
std::vector<v8::Local<v8::Value>> res;
|
||||
res.push_back(v8::Uint32::NewFromUnsigned(isolate, responseCode));
|
||||
return res;
|
||||
}
|
||||
);
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ContainerWrap>(args.Holder());
|
||||
wrap->_container->Load(*source, [handler](NapaResponseCode responseCode) {
|
||||
handler->DispatchCallback(std::move(responseCode));
|
||||
});
|
||||
}
|
||||
|
||||
void ContainerWrap::LoadSync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "first parameter to container.loadSync must be the javascript source");
|
||||
|
||||
v8::String::Utf8Value source(args[0]->ToString());
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ContainerWrap>(args.Holder());
|
||||
wrap->_container->LoadSync(*source);
|
||||
}
|
||||
|
||||
void ContainerWrap::LoadFile(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "first parameter to container.loadFile must be the javascript file");
|
||||
CHECK_ARG(isolate, args[1]->IsFunction(), "second parameter to container.loadFile must be the callback");
|
||||
|
||||
v8::String::Utf8Value file(args[0]->ToString());
|
||||
auto callback = v8::Local<v8::Function>::Cast(args[1]);
|
||||
|
||||
auto handler = NodeAsyncHandler<NapaResponseCode>::New(
|
||||
isolate,
|
||||
callback,
|
||||
[isolate](const NapaResponseCode& responseCode) {
|
||||
std::vector<v8::Local<v8::Value>> res;
|
||||
res.push_back(v8::Uint32::NewFromUnsigned(isolate, responseCode));
|
||||
return res;
|
||||
}
|
||||
);
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ContainerWrap>(args.Holder());
|
||||
wrap->_container->LoadFile(*file, [handler](NapaResponseCode responseCode) {
|
||||
handler->DispatchCallback(std::move(responseCode));
|
||||
});
|
||||
}
|
||||
|
||||
void ContainerWrap::LoadFileSync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "first parameter to container.loadFileSync must be the javascript file");
|
||||
|
||||
v8::String::Utf8Value file(args[0]->ToString());
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ContainerWrap>(args.Holder());
|
||||
wrap->_container->LoadFileSync(*file);
|
||||
}
|
||||
|
||||
void ContainerWrap::Run(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "first parameter to container.run must be the function name");
|
||||
CHECK_ARG(isolate, args[1]->IsArray(), "second parameter to container.run must be the arguments array");
|
||||
CHECK_ARG(isolate, args[2]->IsFunction(), "third parameter to container.run must be the callback");
|
||||
|
||||
if (args.Length() > 3)
|
||||
{
|
||||
CHECK_ARG(isolate, args[3]->IsUint32(), "forth parameter to container.run must be the timeout");
|
||||
}
|
||||
|
||||
v8::String::Utf8Value func(args[0]->ToString());
|
||||
auto runArgs = napa::v8_helpers::V8ArrayToVector<std::string>(isolate, v8::Local<v8::Array>::Cast(args[1]));
|
||||
auto callback = v8::Local<v8::Function>::Cast(args[2]);
|
||||
|
||||
auto handler = NodeAsyncHandler<napa::runtime::Response>::New(
|
||||
isolate,
|
||||
callback,
|
||||
[isolate](const napa::runtime::Response& response) {
|
||||
return std::vector<v8::Local<v8::Value>>({
|
||||
v8::Uint32::NewFromUnsigned(isolate, response.code),
|
||||
v8::String::NewFromUtf8(
|
||||
isolate,
|
||||
response.error.c_str(),
|
||||
v8::NewStringType::kNormal).ToLocalChecked(),
|
||||
v8::String::NewFromUtf8(
|
||||
isolate,
|
||||
response.returnValue.c_str(),
|
||||
v8::NewStringType::kNormal).ToLocalChecked()
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ContainerWrap>(args.Holder());
|
||||
|
||||
if (args.Length() > 3)
|
||||
{
|
||||
wrap->_container->Run(
|
||||
*func,
|
||||
runArgs,
|
||||
[handler](napa::runtime::Response response) { handler->DispatchCallback(std::move(response)); },
|
||||
args[3]->Uint32Value(context).FromJust()); // timeout
|
||||
}
|
||||
else
|
||||
{
|
||||
wrap->_container->Run(
|
||||
*func,
|
||||
runArgs,
|
||||
[handler](napa::runtime::Response response) { handler->DispatchCallback(std::move(response)); });
|
||||
}
|
||||
}
|
||||
|
||||
void ContainerWrap::RunSync(const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||
{
|
||||
auto isolate = args.GetIsolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "first parameter to container.runSync must be the function name");
|
||||
CHECK_ARG(isolate, args[1]->IsArray(), "second parameter to container.runSync must be the arguments array");
|
||||
|
||||
if (args.Length() > 2)
|
||||
{
|
||||
CHECK_ARG(isolate, args[2]->IsUint32(), "third parameter to container.runSync must be the timeout");
|
||||
}
|
||||
|
||||
v8::String::Utf8Value func(args[0]->ToString());
|
||||
|
||||
auto runArgs = napa::v8_helpers::V8ArrayToVector<std::string>(isolate, v8::Local<v8::Array>::Cast(args[1]));
|
||||
|
||||
auto wrap = ObjectWrap::Unwrap<ContainerWrap>(args.Holder());
|
||||
|
||||
napa::runtime::Response response;
|
||||
if (args.Length() > 2)
|
||||
{
|
||||
// Call with provided timeout
|
||||
response = wrap->_container->RunSync(*func, runArgs, args[2]->Uint32Value(context).FromJust());
|
||||
}
|
||||
else
|
||||
{
|
||||
response = wrap->_container->RunSync(*func, runArgs);
|
||||
}
|
||||
|
||||
auto returnObj = v8::Object::New(isolate);
|
||||
|
||||
returnObj->CreateDataProperty(
|
||||
context,
|
||||
v8::String::NewFromUtf8(isolate, "code", v8::NewStringType::kNormal).ToLocalChecked(),
|
||||
v8::Uint32::NewFromUnsigned(isolate, response.code));
|
||||
|
||||
returnObj->CreateDataProperty(
|
||||
context,
|
||||
v8::String::NewFromUtf8(isolate, "error", v8::NewStringType::kNormal).ToLocalChecked(),
|
||||
v8::String::NewFromUtf8(isolate, response.error.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
|
||||
|
||||
returnObj->CreateDataProperty(
|
||||
context,
|
||||
v8::String::NewFromUtf8(isolate, "returnValue", v8::NewStringType::kNormal).ToLocalChecked(),
|
||||
v8::String::NewFromUtf8(isolate, response.returnValue.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
|
||||
|
||||
args.GetReturnValue().Set(returnObj);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef NAPA_BINDING_CONTAINER_WRAP_H
|
||||
#define NAPA_BINDING_CONTAINER_WRAP_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <node_object_wrap.h>
|
||||
|
||||
// Forward declare container.
|
||||
namespace napa
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
class Container;
|
||||
}
|
||||
}
|
||||
|
||||
namespace napa
|
||||
{
|
||||
namespace binding
|
||||
{
|
||||
/// <summary>A node object wrap to expose container APIs to node. </summary>
|
||||
class ContainerWrap : public node::ObjectWrap
|
||||
{
|
||||
public:
|
||||
static void Init(v8::Isolate* isolate);
|
||||
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
private:
|
||||
static v8::Persistent<v8::Function> _constructor;
|
||||
|
||||
std::unique_ptr<napa::runtime::Container> _container;
|
||||
|
||||
explicit ContainerWrap(std::unique_ptr<napa::runtime::Container> container);
|
||||
|
||||
static void NewCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void LoadSync(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void LoadFile(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void LoadFileSync(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Run(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void RunSync(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
#ifndef NAPA_BINDING_NODE_ASYNC_HANDLER_H
|
||||
#define NAPA_BINDING_NODE_ASYNC_HANDLER_H
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace napa
|
||||
{
|
||||
namespace binding
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to facilitate dispatcing async calls fron node addons.
|
||||
/// The handler stores the provided V8 callback function persistently which enables calling
|
||||
/// it when the underlying execution callback is called.
|
||||
/// The dispatcing of the V8 callback happend on the node main thread.
|
||||
/// </summary>
|
||||
template <typename ResponseType>
|
||||
class NodeAsyncHandler
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::function<std::vector<v8::Local<v8::Value>>(const ResponseType&)> CallbackArgsGeneratorFunction;
|
||||
|
||||
/// <summary>Non copyable and non movable. </summary>
|
||||
NodeAsyncHandler(const NodeAsyncHandler&) = delete;
|
||||
NodeAsyncHandler& operator=(const NodeAsyncHandler&) = delete;
|
||||
NodeAsyncHandler(NodeAsyncHandler&&) = delete;
|
||||
NodeAsyncHandler& operator=(NodeAsyncHandler&&) = delete;
|
||||
|
||||
/// <summary>
|
||||
/// Factory method to create the handler.
|
||||
/// Releasing the handler resources happens automatically when dispatcing is done.
|
||||
/// In cases when an error occurs before a call to DispatchCallback was made, the user
|
||||
/// should invoke the Release method.
|
||||
/// </summary>
|
||||
static NodeAsyncHandler<ResponseType>* New(
|
||||
v8::Isolate* isolate,
|
||||
const v8::Local<v8::Function>& callback,
|
||||
CallbackArgsGeneratorFunction argsGeneratorFunc);
|
||||
|
||||
/// <summary>Releasing handler resources </summary>
|
||||
static void Release(NodeAsyncHandler<ResponseType>* handler);
|
||||
|
||||
/// <summary>Invoking the stored V8 callback on node main thread. </summary>
|
||||
void DispatchCallback(ResponseType&& response);
|
||||
|
||||
private:
|
||||
|
||||
NodeAsyncHandler() {}
|
||||
|
||||
// Prevent users from deleting the handler.
|
||||
~NodeAsyncHandler() {}
|
||||
|
||||
static void AsyncCompletionCallback(uv_async_t* asyncHandle);
|
||||
|
||||
v8::Isolate* _isolate;
|
||||
v8::Persistent<v8::Function> _callback;
|
||||
CallbackArgsGeneratorFunction _argsGeneratorFunc;
|
||||
|
||||
uv_async_t _asyncHandle;
|
||||
ResponseType _response;
|
||||
};
|
||||
|
||||
template <typename ResponseType>
|
||||
NodeAsyncHandler<ResponseType>* NodeAsyncHandler<ResponseType>::New(
|
||||
v8::Isolate* isolate,
|
||||
const v8::Local<v8::Function>& callback,
|
||||
CallbackArgsGeneratorFunction argsGeneratorFunc)
|
||||
{
|
||||
auto handler = new NodeAsyncHandler<ResponseType>();
|
||||
|
||||
handler->_isolate = isolate;
|
||||
|
||||
// Store the callback in a persistent function.
|
||||
handler->_callback.Reset(isolate, callback);
|
||||
|
||||
// Store the argument generator function.
|
||||
handler->_argsGeneratorFunc = std::move(argsGeneratorFunc);
|
||||
|
||||
// Store the handler to enable retrieving it in the uv callbacks.
|
||||
handler->_asyncHandle.data = handler;
|
||||
|
||||
// Initialize the uv async handle and set the callback function
|
||||
// that will be executed on the node main thread.
|
||||
uv_async_init(uv_default_loop(), &(handler->_asyncHandle), AsyncCompletionCallback);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
template <typename ResponseType>
|
||||
void NodeAsyncHandler<ResponseType>::Release(NodeAsyncHandler<ResponseType>* handler)
|
||||
{
|
||||
// Free the persistent function callback.
|
||||
handler->_callback.Reset();
|
||||
|
||||
// De-allocate the memory.
|
||||
delete handler;
|
||||
}
|
||||
|
||||
template <typename ResponseType>
|
||||
void NodeAsyncHandler<ResponseType>::DispatchCallback(ResponseType&& response)
|
||||
{
|
||||
_response = std::forward<ResponseType>(response);
|
||||
|
||||
// Defer JS callback to the node main thread.
|
||||
uv_async_send(&_asyncHandle);
|
||||
}
|
||||
|
||||
template <typename ResponseType>
|
||||
void NodeAsyncHandler<ResponseType>::AsyncCompletionCallback(uv_async_t* asyncHandle)
|
||||
{
|
||||
auto handler = reinterpret_cast<NodeAsyncHandler<ResponseType>*>(asyncHandle->data);
|
||||
|
||||
auto isolate = handler->_isolate;
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
auto callback = v8::Local<v8::Function>::New(isolate, handler->_callback);
|
||||
|
||||
auto args = handler->_argsGeneratorFunc(handler->_response);
|
||||
|
||||
// Call the user provided Javascript callback.
|
||||
callback->Call(context, context->Global(), static_cast<int>(args.size()), args.data());
|
||||
|
||||
// Cleanup
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(asyncHandle), [](uv_handle_t* asyncHandle) {
|
||||
auto handler = reinterpret_cast<NodeAsyncHandler<ResponseType>*>(asyncHandle->data);
|
||||
|
||||
Release(handler);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NAPA_BINDING_NODE_ASYNC_HANDLER_H
|
|
@ -1,2 +1,8 @@
|
|||
// This is the C style header file for Napa app engine.
|
||||
// We are going to build binding on top of it. (Asi)
|
||||
#ifndef NAPA_APP_C_H
|
||||
#define NAPA_APP_C_H
|
||||
|
||||
#include "napa-runtime-c.h"
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -6,18 +6,16 @@
|
|||
|
||||
typedef NapaResponseCode napa_response_code;
|
||||
|
||||
/// <summary>
|
||||
/// Represents napa response.
|
||||
/// If response code is success then the output has a JSON format, otherwise the
|
||||
/// output is the error message
|
||||
/// </summary>
|
||||
/// <summary>Represents napa response. </summary>
|
||||
typedef struct {
|
||||
napa_response_code code;
|
||||
napa_string_ref output;
|
||||
napa_string_ref error;
|
||||
napa_string_ref return_value;
|
||||
} napa_container_response;
|
||||
|
||||
/// <summary>Callback signature</summary>
|
||||
typedef void(*napa_container_callback)(napa_container_response response, void* state);
|
||||
/// <summary>Callback signatures</summary>
|
||||
typedef void(*napa_container_run_callback)(napa_container_response response, void* context);
|
||||
typedef void(*napa_container_load_callback)(napa_response_code code, void* context);
|
||||
|
||||
/// <summary>
|
||||
/// Container handle type.
|
||||
|
@ -54,17 +52,39 @@ EXTERN_C NAPA_API napa_response_code napa_container_set_global_value(
|
|||
napa_string_ref key,
|
||||
void* value);
|
||||
|
||||
/// <summary>Loads the content of the provided file into the container</summary>
|
||||
/// <summary>Loads the content of the provided file into the container asynchronously</summary>
|
||||
/// <param name="handle">The container handle</param>
|
||||
/// <param name="file">The path to the JavaScript file</param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_container_load_file(
|
||||
/// <param name="callback">A callback that is triggered when loading is done</param>
|
||||
/// <param name="context">An opaque pointer that is passed back in the callback</param>
|
||||
EXTERN_C NAPA_API void napa_container_load_file(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref file,
|
||||
napa_container_load_callback callback,
|
||||
void* context);
|
||||
|
||||
/// <summary>Loads the content of the provided file into the container synchronously</summary>
|
||||
/// <param name="handle">The container handle</param>
|
||||
/// <param name="file">The path to the JavaScript file</param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_container_load_file_sync(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref file);
|
||||
|
||||
/// <summary>Loads the provided source code into the container</summary>
|
||||
/// <summary>Loads the provided source code into the container asynchronously</summary>
|
||||
/// <param name="handle">The container handle</param>
|
||||
/// <param name="source">The JavaScript source code</param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_container_load(
|
||||
/// <param name="callback">A callback that is triggered when loading is done</param>
|
||||
/// <param name="context">An opaque pointer that is passed back in the callback</param>
|
||||
EXTERN_C NAPA_API void napa_container_load(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref source,
|
||||
napa_container_load_callback callback,
|
||||
void* context);
|
||||
|
||||
/// <summary>Loads the provided source code into the container synchronously</summary>
|
||||
/// <param name="handle">The container handle</param>
|
||||
/// <param name="source">The JavaScript source code</param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_container_load_sync(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref source);
|
||||
|
||||
|
@ -74,14 +94,14 @@ EXTERN_C NAPA_API napa_response_code napa_container_load(
|
|||
/// <param name="argc">The number of arguments that are to be passed to the function</param>
|
||||
/// <param name="argv">The arguments</param>
|
||||
/// <param name="callback">A callback that is triggered when execution is done</param>
|
||||
/// <param name="context">An opaque pointer that is returned with the callback</param>
|
||||
/// <param name="context">An opaque pointer that is passed back in the callback</param>
|
||||
/// <param name="timeout">Timeout in milliseconds - Use 0 for inifinite</param>
|
||||
EXTERN_C NAPA_API napa_response_code napa_container_run(
|
||||
EXTERN_C NAPA_API void napa_container_run(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref func,
|
||||
size_t argc,
|
||||
napa_string_ref argv[],
|
||||
napa_container_callback callback,
|
||||
napa_container_run_callback callback,
|
||||
void* context,
|
||||
uint32_t timeout);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef NapaRuntime_H
|
||||
#define NapaRuntime_H
|
||||
#ifndef NAPA_RUNTIME_H
|
||||
#define NAPA_RUNTIME_H
|
||||
|
||||
#include "napa-runtime-c.h"
|
||||
|
||||
|
@ -8,86 +8,38 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace napa
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
/// <summary> Initialize napa runtime with global scope settings </summary>
|
||||
/// <see cref="napa_initialize" />
|
||||
inline NapaResponseCode Initialize(const std::string& settings)
|
||||
{
|
||||
return napa_initialize(STD_STRING_TO_NAPA_STRING_REF(settings));
|
||||
}
|
||||
|
||||
/// <summary> Initialize napa runtime using console provided arguments </summary>
|
||||
/// <see cref="napa_initialize_from_console" />
|
||||
inline NapaResponseCode InitializeFromConsole(int argc, char* argv[])
|
||||
{
|
||||
return napa_initialize_from_console(argc, argv);
|
||||
}
|
||||
|
||||
/// <summary> Shut down napa runtime </summary>
|
||||
/// <see cref="napa_shutdown" />
|
||||
inline NapaResponseCode Shutdown()
|
||||
{
|
||||
return napa_shutdown();
|
||||
}
|
||||
|
||||
/// <summary>Response</summary>
|
||||
struct Response
|
||||
{
|
||||
/// <summary>Response code.</summary>
|
||||
Response() : code(NAPA_RESPONSE_UNDEFINED)
|
||||
{
|
||||
}
|
||||
|
||||
Response(napa_container_response response) :
|
||||
code(response.code),
|
||||
error(NAPA_STRING_REF_TO_STD_STRING(response.error)),
|
||||
returnValue(NAPA_STRING_REF_TO_STD_STRING(response.return_value))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Response code </summary>
|
||||
NapaResponseCode code;
|
||||
|
||||
/// <summary>Napa output. Json format in case of success, error message otherwise</summary>
|
||||
std::string output;
|
||||
/// <summary>Error message. Empty when response code is success. </summary>
|
||||
std::string error;
|
||||
|
||||
/// <summary>Napa return value </summary>
|
||||
std::string returnValue;
|
||||
};
|
||||
|
||||
/// <summary>Response callback signature</summary>
|
||||
typedef std::function<void(Response)> ResponseCallback;
|
||||
|
||||
/// <summary>helper classes and functions in internal namespace</summary>
|
||||
namespace internal
|
||||
{
|
||||
struct RunCompletionContext
|
||||
{
|
||||
RunCompletionContext(ResponseCallback callback)
|
||||
: callback(std::move(callback))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Non copyable and non movable.</summary>
|
||||
RunCompletionContext(const RunCompletionContext&) = delete;
|
||||
RunCompletionContext& operator=(const RunCompletionContext&) = delete;
|
||||
RunCompletionContext(RunCompletionContext&&) = delete;
|
||||
RunCompletionContext& operator=(RunCompletionContext&&) = delete;
|
||||
|
||||
/// <summary>User callback.</summary>
|
||||
ResponseCallback callback;
|
||||
};
|
||||
|
||||
inline void RunCompletionHandler(napa_container_response response, void* context)
|
||||
{
|
||||
std::unique_ptr<RunCompletionContext> completionContext(
|
||||
reinterpret_cast<RunCompletionContext*>(context));
|
||||
|
||||
completionContext->callback(
|
||||
Response{ response.code, NAPA_STRING_REF_TO_STD_STRING(response.output) });
|
||||
}
|
||||
|
||||
inline std::vector<napa_string_ref> ConvertToNapaRuntimeArgs(const std::vector<std::string>& args)
|
||||
{
|
||||
std::vector<napa_string_ref> res;
|
||||
res.reserve(args.size());
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
res.emplace_back(STD_STRING_TO_NAPA_STRING_REF(arg));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::function<void(Response)> RunCallback;
|
||||
typedef std::function<void(NapaResponseCode)> LoadCallback;
|
||||
|
||||
/// <summary> C++ class wrapper around napa runtime C APIs </summary>
|
||||
class Container
|
||||
|
@ -104,29 +56,35 @@ namespace runtime
|
|||
/// <summary> Sets a value in container scope </summary>
|
||||
/// <param name="key"> A unique identifier for the value </param>
|
||||
/// <param name="value"> The value </param>
|
||||
/// <see cref="NapaRuntime_SetGlobalValue" />
|
||||
NapaResponseCode SetGlobalValue(const std::string& key, void* value);
|
||||
|
||||
/// <summary> Loads a JS file into the container </summary>
|
||||
/// <summary> Loads a JS file into the container asynchronously </summary>
|
||||
/// <param name="file"> The JS file </param>
|
||||
/// <see cref="NapaRuntime_LoadFile" />
|
||||
NapaResponseCode LoadFile(const std::string& file);
|
||||
/// <param name="callback">A callback that is triggered when loading is done</param>
|
||||
void LoadFile(const std::string& file, LoadCallback callback);
|
||||
|
||||
/// <summary> Loads a JS source into the container </summary>
|
||||
/// <summary> Loads a JS file into the container synchronously </summary>
|
||||
/// <param name="file"> The JS file </param>
|
||||
NapaResponseCode LoadFileSync(const std::string& file);
|
||||
|
||||
/// <summary> Loads a JS source into the container asynchronously </summary>
|
||||
/// <param name="source"> The JS source </param>
|
||||
/// <see cref="NapaRuntime_Load" />
|
||||
NapaResponseCode Load(const std::string& source);
|
||||
/// <param name="callback">A callback that is triggered when loading is done</param>
|
||||
void Load(const std::string& source, LoadCallback callback);
|
||||
|
||||
/// <summary> Loads a JS source into the container synchronously </summary>
|
||||
/// <param name="source"> The JS source </param>
|
||||
NapaResponseCode LoadSync(const std::string& source);
|
||||
|
||||
/// <summary> Runs a pre-loaded JS function asynchronously </summary>
|
||||
/// <param name="func">The name of the function to run</param>
|
||||
/// <param name="args">The arguments to the function</param>
|
||||
/// <param name="callback">A callback that is triggered when execution is done</param>
|
||||
/// <param name="timeout">Timeout in milliseconds - default is inifinite</param>
|
||||
/// <see cref="NapaRuntime_Run" />
|
||||
void Run(
|
||||
const std::string& func,
|
||||
const std::vector<std::string>& args,
|
||||
ResponseCallback callback,
|
||||
RunCallback callback,
|
||||
uint32_t timeout = 0);
|
||||
|
||||
/// <summary> Runs a pre-loaded JS function synchronously </summary>
|
||||
|
@ -142,6 +100,70 @@ namespace runtime
|
|||
napa_container_handle _handle;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Implementation starts here
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// <summary> Initialize napa runtime with global scope settings </summary>
|
||||
inline NapaResponseCode Initialize(const std::string& settings)
|
||||
{
|
||||
return napa_initialize(STD_STRING_TO_NAPA_STRING_REF(settings));
|
||||
}
|
||||
|
||||
/// <summary> Initialize napa runtime using console provided arguments </summary>
|
||||
inline NapaResponseCode InitializeFromConsole(int argc, char* argv[])
|
||||
{
|
||||
return napa_initialize_from_console(argc, argv);
|
||||
}
|
||||
|
||||
/// <summary> Shut down napa runtime </summary>
|
||||
inline NapaResponseCode Shutdown()
|
||||
{
|
||||
return napa_shutdown();
|
||||
}
|
||||
|
||||
/// <summary>Helper classes and functions in internal namespace</summary>
|
||||
namespace internal
|
||||
{
|
||||
template <typename CallbackType>
|
||||
struct AsyncCompletionContext
|
||||
{
|
||||
AsyncCompletionContext(CallbackType&& callback)
|
||||
: callback(std::forward<CallbackType>(callback))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Non copyable and non movable.</summary>
|
||||
AsyncCompletionContext(const AsyncCompletionContext&) = delete;
|
||||
AsyncCompletionContext& operator=(const AsyncCompletionContext&) = delete;
|
||||
AsyncCompletionContext(AsyncCompletionContext&&) = delete;
|
||||
AsyncCompletionContext& operator=(AsyncCompletionContext&&) = delete;
|
||||
|
||||
/// <summary>User callback.</summary>
|
||||
CallbackType callback;
|
||||
};
|
||||
|
||||
template <typename CallbackType, typename ResponseType>
|
||||
inline void CompletionHandler(ResponseType response, void* context)
|
||||
{
|
||||
std::unique_ptr<AsyncCompletionContext<CallbackType>> completionContext(
|
||||
reinterpret_cast<AsyncCompletionContext<CallbackType>*>(context));
|
||||
|
||||
completionContext->callback(response);
|
||||
}
|
||||
|
||||
inline std::vector<napa_string_ref> ConvertToNapaRuntimeArgs(const std::vector<std::string>& args)
|
||||
{
|
||||
std::vector<napa_string_ref> res;
|
||||
res.reserve(args.size());
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
res.emplace_back(STD_STRING_TO_NAPA_STRING_REF(arg));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
inline Container::Container(const std::string& settings)
|
||||
{
|
||||
|
@ -160,32 +182,54 @@ namespace runtime
|
|||
return napa_container_set_global_value(_handle, STD_STRING_TO_NAPA_STRING_REF(key), value);
|
||||
}
|
||||
|
||||
inline NapaResponseCode Container::LoadFile(const std::string& file)
|
||||
inline void Container::LoadFile(const std::string& file, LoadCallback callback)
|
||||
{
|
||||
return napa_container_load_file(_handle, STD_STRING_TO_NAPA_STRING_REF(file));
|
||||
auto context = new internal::AsyncCompletionContext<LoadCallback>(std::move(callback));
|
||||
|
||||
napa_container_load_file(
|
||||
_handle,
|
||||
STD_STRING_TO_NAPA_STRING_REF(file),
|
||||
internal::CompletionHandler<LoadCallback, NapaResponseCode>,
|
||||
context);
|
||||
}
|
||||
|
||||
inline NapaResponseCode Container::Load(const std::string& source)
|
||||
inline NapaResponseCode Container::LoadFileSync(const std::string& file)
|
||||
{
|
||||
return napa_container_load(_handle, STD_STRING_TO_NAPA_STRING_REF(source));
|
||||
return napa_container_load_file_sync(_handle, STD_STRING_TO_NAPA_STRING_REF(file));
|
||||
}
|
||||
|
||||
inline void Container::Load(const std::string& source, LoadCallback callback)
|
||||
{
|
||||
auto context = new internal::AsyncCompletionContext<LoadCallback>(std::move(callback));
|
||||
|
||||
napa_container_load(
|
||||
_handle,
|
||||
STD_STRING_TO_NAPA_STRING_REF(source),
|
||||
internal::CompletionHandler<LoadCallback, napa_response_code>,
|
||||
context);
|
||||
}
|
||||
|
||||
inline NapaResponseCode Container::LoadSync(const std::string& source)
|
||||
{
|
||||
return napa_container_load_sync(_handle, STD_STRING_TO_NAPA_STRING_REF(source));
|
||||
}
|
||||
|
||||
inline void Container::Run(
|
||||
const std::string& func,
|
||||
const std::vector<std::string>& args,
|
||||
ResponseCallback callback,
|
||||
RunCallback callback,
|
||||
uint32_t timeout)
|
||||
{
|
||||
auto argv = internal::ConvertToNapaRuntimeArgs(args);
|
||||
|
||||
auto context = new internal::RunCompletionContext(std::move(callback));
|
||||
auto context = new internal::AsyncCompletionContext<RunCallback>(std::move(callback));
|
||||
|
||||
napa_container_run(
|
||||
_handle,
|
||||
STD_STRING_TO_NAPA_STRING_REF(func),
|
||||
argv.size(),
|
||||
argv.data(),
|
||||
internal::RunCompletionHandler,
|
||||
internal::CompletionHandler<RunCallback, napa_container_response>,
|
||||
context,
|
||||
timeout);
|
||||
}
|
||||
|
@ -204,10 +248,10 @@ namespace runtime
|
|||
argv.data(),
|
||||
timeout);
|
||||
|
||||
return Response { response.code, NAPA_STRING_REF_TO_STD_STRING(response.output) };
|
||||
return Response(response);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NapaRuntime_H
|
||||
#endif // NAPA_RUNTIME_H
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
/// <summary>Simple non ownning string. Should only be used for binding.</summary>
|
||||
typedef struct {
|
||||
|
@ -10,9 +11,11 @@ typedef struct {
|
|||
size_t size;
|
||||
} napa_string_ref;
|
||||
|
||||
#define CREATE_NAPA_STRING_REF2(data, size) (napa_string_ref { (data), (size) })
|
||||
#define CREATE_NAPA_STRING_REF(data) CREATE_NAPA_STRING_REF2(data, strlen(data))
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#define CREATE_NAPA_STRING_REF(data, size) (napa_string_ref { (data), (size) })
|
||||
#define STD_STRING_TO_NAPA_STRING_REF(str) (napa_string_ref { (str).data(), (str).size() })
|
||||
#define NAPA_STRING_REF_TO_STD_STRING(str) (std::string((str).data, (str).size))
|
||||
|
||||
|
|
|
@ -16,4 +16,5 @@
|
|||
#error NAPA_RESPONSE_CODE_DEF must be defined before including response_code.inc
|
||||
#endif
|
||||
|
||||
NAPA_RESPONSE_CODE_DEF( SUCCESS, "Success")
|
||||
NAPA_RESPONSE_CODE_DEF( SUCCESS, "Success"),
|
||||
NAPA_RESPONSE_CODE_DEF( UNDEFINED, "Undefined")
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef NAPA_V8_HELPERS_H
|
||||
#define NAPA_V8_HELPERS_H
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
|
||||
#define CHECK_ARG_COMMON(isolate, expression, message, result, function, line) \
|
||||
if (!(expression)) \
|
||||
{ \
|
||||
std::stringstream temp; \
|
||||
temp << function << ":" << line << " -- " << message; \
|
||||
isolate->ThrowException(v8::Exception::TypeError( \
|
||||
v8::String::NewFromUtf8(isolate, temp.str().c_str(), v8::NewStringType::kNormal).ToLocalChecked())); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define CHECK_ARG(isolate, expression, message) \
|
||||
CHECK_ARG_COMMON(isolate, expression, message, /* empty */, __FUNCTION__, __LINE__)
|
||||
|
||||
#define CHECK_ARG_WITH_RETURN(isolate, expression, message, result) \
|
||||
CHECK_ARG_COMMON(isolate, expression, message, result, __FUNCTION__, __LINE__)
|
||||
|
||||
namespace napa
|
||||
{
|
||||
namespace v8_helpers
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
inline T To(const v8::Local<v8::Value>& value)
|
||||
{
|
||||
static_assert(sizeof(T) == -1, "No specilization exists for this type");
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string To(const v8::Local<v8::Value>& value)
|
||||
{
|
||||
v8::String::Utf8Value utf8Value(value);
|
||||
return *utf8Value;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline std::unordered_map<std::string, ValueType> V8ObjectToMap(
|
||||
v8::Isolate* isolate,
|
||||
const v8::Local<v8::Object>& obj)
|
||||
{
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
std::unordered_map<std::string, ValueType> res;
|
||||
|
||||
auto maybeProps = obj->GetOwnPropertyNames(context);
|
||||
if (!maybeProps.IsEmpty())
|
||||
{
|
||||
auto props = maybeProps.ToLocalChecked();
|
||||
res.reserve(props->Length());
|
||||
|
||||
for (uint32_t i = 0; i < props->Length(); i++)
|
||||
{
|
||||
auto key = props->Get(context, i).ToLocalChecked();
|
||||
auto value = obj->Get(context, key).ToLocalChecked();
|
||||
|
||||
v8::String::Utf8Value keyString(key->ToString());
|
||||
|
||||
res.emplace(*keyString, To<ValueType>(value));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline std::vector<ValueType> V8ArrayToVector(
|
||||
v8::Isolate* isolate,
|
||||
const v8::Local<v8::Array>& array)
|
||||
{
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
std::vector<ValueType> res;
|
||||
res.reserve(array->Length());
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); i++)
|
||||
{
|
||||
res.emplace_back(To<ValueType>(array->Get(context, i).ToLocalChecked()));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -39,5 +39,11 @@
|
|||
<ClCompile Include="runtime.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Binplace Include="$(OutputPath)\$(TargetFileName)">
|
||||
<DestinationFolder>$(NapaVanillaBinplacePath)</DestinationFolder>
|
||||
</Binplace>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
|
||||
#include "container.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
napa_container_handle napa_container_create()
|
||||
{
|
||||
std::cout << "napa_container_create()" << std::endl;
|
||||
|
||||
return reinterpret_cast<napa_container_handle>(new napa::runtime::internal::Container());
|
||||
}
|
||||
|
||||
|
@ -12,6 +17,9 @@ napa_response_code napa_container_init(
|
|||
napa_container_handle handle,
|
||||
napa_string_ref settings)
|
||||
{
|
||||
std::cout << "napa_container_init()" << std::endl;
|
||||
std::cout << "\tsettings: " << settings.data << std::endl;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -20,43 +28,122 @@ napa_response_code napa_container_set_global_value(
|
|||
napa_string_ref key,
|
||||
void* value)
|
||||
{
|
||||
std::cout << "napa_container_set_global_value()" << std::endl;
|
||||
std::cout << "\tkey: " << key.data << std::endl;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
napa_response_code napa_container_load_file(
|
||||
void napa_container_load_file(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref file,
|
||||
napa_container_load_callback callback,
|
||||
void* context)
|
||||
{
|
||||
std::cout << "napa_container_load_file()" << std::endl;
|
||||
std::cout << "\tfile: " << file.data << std::endl;
|
||||
|
||||
// Mock async response
|
||||
std::thread([callback, context]() {
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
callback(NAPA_RESPONSE_SUCCESS, context);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
napa_response_code napa_container_load_file_sync(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref file)
|
||||
{
|
||||
std::cout << "napa_container_load_file_sync()" << std::endl;
|
||||
std::cout << "\tfile: " << file.data << std::endl;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
napa_response_code napa_container_load(
|
||||
void napa_container_load(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref source,
|
||||
napa_container_load_callback callback,
|
||||
void* context)
|
||||
{
|
||||
std::cout << "napa_container_load()" << std::endl;
|
||||
std::cout << "\tsource: " << source.data << std::endl;
|
||||
|
||||
// Mock async response
|
||||
std::thread([callback, context]() {
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
callback(NAPA_RESPONSE_SUCCESS, context);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
napa_response_code napa_container_load_sync(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref source)
|
||||
{
|
||||
std::cout << "napa_container_load_sync()" << std::endl;
|
||||
std::cout << "\tsource: " << source.data << std::endl;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
napa_response_code napa_container_run(
|
||||
void napa_container_run(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref func,
|
||||
uint32_t argc,
|
||||
size_t argc,
|
||||
napa_string_ref argv[],
|
||||
napa_container_callback callback,
|
||||
napa_container_run_callback callback,
|
||||
void* context,
|
||||
uint32_t timeout)
|
||||
{
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
std::cout << "napa_container_run()" << std::endl;
|
||||
std::cout << "\tfunc: " << func.data << std::endl;
|
||||
std::cout << "\targc: " << argc << std::endl;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
std::cout << "\t\t[" << i << "] " << argv[i].data << std::endl;
|
||||
}
|
||||
std::cout << "\ttimeout: " << timeout << std::endl;
|
||||
|
||||
// Mock async response
|
||||
std::thread([callback, context]() {
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
napa_container_response response;
|
||||
|
||||
response.code = NAPA_RESPONSE_SUCCESS;
|
||||
response.error = CREATE_NAPA_STRING_REF("");
|
||||
response.return_value = CREATE_NAPA_STRING_REF("{\"score\":2412}");
|
||||
|
||||
callback(response, context);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
napa_container_response napa_container_run_sync(
|
||||
napa_container_handle handle,
|
||||
napa_string_ref func,
|
||||
uint32_t argc,
|
||||
size_t argc,
|
||||
napa_string_ref argv[],
|
||||
uint32_t timeout)
|
||||
{
|
||||
return napa_container_response{ NAPA_RESPONSE_SUCCESS, CREATE_NAPA_STRING_REF("", 0) };
|
||||
std::cout << "napa_container_run_sync()" << std::endl;
|
||||
std::cout << "\tfunc: " << func.data << std::endl;
|
||||
std::cout << "\targc: " << argc << std::endl;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
std::cout << "\t\t[" << i << "] " << argv[i].data << std::endl;
|
||||
}
|
||||
std::cout << "\ttimeout: " << timeout << std::endl;
|
||||
|
||||
return napa_container_response {
|
||||
NAPA_RESPONSE_SUCCESS,
|
||||
CREATE_NAPA_STRING_REF("test"),
|
||||
CREATE_NAPA_STRING_REF("{\"score\":2412}")
|
||||
};
|
||||
}
|
||||
|
||||
napa_response_code napa_container_release(napa_container_handle handle)
|
||||
|
@ -66,6 +153,9 @@ napa_response_code napa_container_release(napa_container_handle handle)
|
|||
|
||||
napa_response_code napa_initialize(napa_string_ref settings)
|
||||
{
|
||||
std::cout << "napa_initialize()" << std::endl;
|
||||
std::cout << "\tsettings: " << settings.data << std::endl;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -73,11 +163,20 @@ napa_response_code napa_initialize_from_console(
|
|||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
std::cout << "napa_initialize_from_console()" << std::endl;
|
||||
std::cout << "\targc: " << argc << std::endl;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
std::cout << "\t\t[" << i << "] " << argv[i] << std::endl;
|
||||
}
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
napa_response_code napa_shutdown()
|
||||
{
|
||||
std::cout << "napa_shutdown()" << std::endl;
|
||||
|
||||
return NAPA_RESPONSE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -94,6 +193,8 @@ const char* NAPA_RESPONSE_CODE_STRINGS[] = {
|
|||
|
||||
const char* napa_response_code_to_string(napa_response_code code)
|
||||
{
|
||||
std::cout << "napa_shutdownnapa_response_code_to_string()" << std::endl;
|
||||
|
||||
// TODO: assert code is in array boundaries
|
||||
|
||||
return NAPA_RESPONSE_CODE_STRINGS[code];
|
||||
|
|
Загрузка…
Ссылка в новой задаче