зеркало из https://github.com/microsoft/napajs.git
Merged PR 297335: Replace timeout with ExecuteOptions in zone.execute.
Replace timeout with ExecuteOptions in zone.execute.
This commit is contained in:
Родитель
a48e46dc51
Коммит
c7373d8342
|
@ -1,85 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "napa.h"
|
||||
|
||||
namespace napa {
|
||||
namespace app {
|
||||
|
||||
/// <summary> Interface for request object. </summary>
|
||||
class Request {
|
||||
public:
|
||||
|
||||
/// <summary> Serialize a request to JSON string. </summary>
|
||||
/// <returns> JSON string on successful serialization. Nullptr on failure. </returns>
|
||||
virtual NapaStringRef ToJson() const = 0;
|
||||
|
||||
/// <summary> Virtual destuctor. </summary>
|
||||
virtual ~Request() {}
|
||||
};
|
||||
|
||||
/// <summary> A string based request. </summary>
|
||||
class StringRequest : public Request {
|
||||
public:
|
||||
|
||||
StringRequest(const char* content) : _content(content) {}
|
||||
StringRequest(const std::string& content) : _content(content) {}
|
||||
|
||||
virtual NapaStringRef ToJson() const override {
|
||||
return STD_STRING_TO_NAPA_STRING_REF(_content);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _content;
|
||||
};
|
||||
|
||||
/// <summary> A string ref based request. </summary>
|
||||
class StringRefRequest : public Request {
|
||||
public:
|
||||
StringRefRequest(const char* data) : _content(CREATE_NAPA_STRING_REF(data)) {}
|
||||
StringRefRequest(const char* data, size_t size) : _content(CREATE_NAPA_STRING_REF_WITH_SIZE(data, size)) {}
|
||||
StringRefRequest(NapaStringRef content) : _content(content) {}
|
||||
|
||||
virtual NapaStringRef ToJson() const override {
|
||||
return _content;
|
||||
}
|
||||
|
||||
private:
|
||||
NapaStringRef _content;
|
||||
};
|
||||
|
||||
typedef napa::Response Response;
|
||||
|
||||
/// <summary> Facade class to facilitate napa app users in C++ </summary>
|
||||
class Engine {
|
||||
public:
|
||||
typedef napa::RunCallback ResponseCallback;
|
||||
|
||||
Engine();
|
||||
Engine(const napa::Container& container);
|
||||
|
||||
void Execute(const Request& request, ResponseCallback callback);
|
||||
Response ExecuteSync(const Request& request);
|
||||
|
||||
private:
|
||||
static constexpr const char* ENTRY_FILE = "napa-app-main.js";
|
||||
static constexpr const char* ENTRY_FUNCTION = "handleRequest";
|
||||
|
||||
napa::Container _container;
|
||||
};
|
||||
|
||||
inline Engine::Engine() : Engine(napa::Container()) {
|
||||
}
|
||||
|
||||
inline Engine::Engine(const napa::Container& container) : _container(container) {
|
||||
_container.LoadFileSync(ENTRY_FILE);
|
||||
}
|
||||
|
||||
inline void Engine::Execute(const Request& request, ResponseCallback callback) {
|
||||
return _container.Run(ENTRY_FUNCTION, { request.ToJson() }, std::move(callback));
|
||||
}
|
||||
|
||||
inline Response Engine::ExecuteSync(const Request& request) {
|
||||
return _container.RunSync(ENTRY_FUNCTION, { request.ToJson() });
|
||||
}
|
||||
}
|
||||
}
|
56
inc/napa-c.h
56
inc/napa-c.h
|
@ -1,55 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "napa/exports.h"
|
||||
#include "napa/common.h"
|
||||
|
||||
|
||||
/// <summary> Represents an execution request for a zone. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> The module that exports the function to execute. </summary>
|
||||
napa_string_ref module;
|
||||
|
||||
/// <summary> The function to execute. </summary>
|
||||
napa_string_ref function;
|
||||
|
||||
/// <summary> The function arguments. </summary>
|
||||
const napa_string_ref* arguments;
|
||||
|
||||
/// <summary> The number of arguments. </summary>
|
||||
size_t arguments_count;
|
||||
|
||||
/// <summary> Timeout in milliseconds - Use 0 for inifinite. </summary>
|
||||
uint32_t timeout;
|
||||
|
||||
/// <summary> A context used for transporting handles across zones/workers. </summary>
|
||||
void* transport_context;
|
||||
} napa_zone_request;
|
||||
|
||||
/// <summary> Represents a response from executing in a zone. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> A response code. </summary>
|
||||
napa_response_code code;
|
||||
|
||||
/// <summary> The error message in case of an error. </summary>
|
||||
napa_string_ref error_message;
|
||||
|
||||
/// <summary> The return value in case of success. </summary>
|
||||
napa_string_ref return_value;
|
||||
|
||||
/// <summary> A context used for transporting handles across zones/workers. </summary>
|
||||
void* transport_context;
|
||||
} napa_zone_response;
|
||||
|
||||
/// <summary> Callback signatures. </summary>
|
||||
typedef void(*napa_zone_broadcast_callback)(napa_response_code code, void* context);
|
||||
typedef void(*napa_zone_execute_callback)(napa_zone_response response, void* context);
|
||||
|
||||
/// <summary>
|
||||
/// Zone handle type.
|
||||
/// </summary>
|
||||
typedef struct napa_zone *napa_zone_handle;
|
||||
#include "napa/types.h"
|
||||
|
||||
/// <summary> Creates a napa zone. </summary>
|
||||
/// <param name="id"> A unique id for the zone. </param>
|
||||
|
@ -113,7 +65,7 @@ EXTERN_C NAPA_API void napa_zone_broadcast(
|
|||
/// <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_request request,
|
||||
napa_zone_execute_request request,
|
||||
napa_zone_execute_callback callback,
|
||||
void* context);
|
||||
|
||||
|
@ -142,10 +94,6 @@ EXTERN_C NAPA_API napa_response_code napa_shutdown();
|
|||
/// <param name="code"> The response code. </param>
|
||||
EXTERN_C NAPA_API const char* napa_response_code_to_string(napa_response_code code);
|
||||
|
||||
/// <summary> Callback for customized memory allocator. </summary>
|
||||
typedef void* (*napa_allocate_callback)(size_t);
|
||||
typedef void (*napa_deallocate_callback)(void*, size_t);
|
||||
|
||||
/// <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>
|
||||
/// <param name="allocate_callback"> Function pointer for allocating memory, which should be valid during the entire process. </param>
|
||||
|
|
73
inc/napa.h
73
inc/napa.h
|
@ -1,40 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "napa-c.h"
|
||||
#include <napa/zone.h>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace napa {
|
||||
|
||||
/// <summary> Initializes napa with global scope settings. </summary>
|
||||
inline NapaResponseCode Initialize(const std::string& settings = "") {
|
||||
inline ResponseCode Initialize(const std::string& settings = "") {
|
||||
return napa_initialize(STD_STRING_TO_NAPA_STRING_REF(settings));
|
||||
}
|
||||
|
||||
/// <summary> Initialize napa using console provided arguments. </summary>
|
||||
inline NapaResponseCode InitializeFromConsole(int argc, char* argv[]) {
|
||||
inline ResponseCode InitializeFromConsole(int argc, char* argv[]) {
|
||||
return napa_initialize_from_console(argc, argv);
|
||||
}
|
||||
|
||||
/// <summary> Shut down napa. </summary>
|
||||
inline NapaResponseCode Shutdown() {
|
||||
inline ResponseCode Shutdown() {
|
||||
return napa_shutdown();
|
||||
}
|
||||
|
||||
/// <summary> C++ proxy around napa Zone C APIs. </summary>
|
||||
class ZoneProxy : public Zone {
|
||||
class Zone {
|
||||
public:
|
||||
|
||||
/// <summary> Creates a new zone and wraps it with a zone proxy instance. </summary>
|
||||
/// <param name="id"> A unique id for the zone. </param>
|
||||
/// <param name="settings"> A settings string to set zone specific settings. </param>
|
||||
explicit ZoneProxy(const std::string& id, const std::string& settings = "") : _zoneId(id) {
|
||||
explicit Zone(const std::string& id, const std::string& settings = "") : _zoneId(id) {
|
||||
_handle = napa_zone_create(STD_STRING_TO_NAPA_STRING_REF(id));
|
||||
|
||||
auto res = napa_zone_init(_handle, STD_STRING_TO_NAPA_STRING_REF(settings));
|
||||
|
@ -45,17 +40,19 @@ namespace napa {
|
|||
}
|
||||
|
||||
/// <summary> Releases the underlying zone handle. </summary>
|
||||
virtual ~ZoneProxy() {
|
||||
~Zone() {
|
||||
napa_zone_release(_handle);
|
||||
}
|
||||
|
||||
/// <see cref="Zone::GetId" />
|
||||
virtual const std::string& GetId() const override {
|
||||
/// <summary> Compiles and run the provided source code on all zone workers asynchronously. </summary>
|
||||
/// <param name="source"> The source code. </param>
|
||||
/// <param name="callback"> A callback that is triggered when broadcasting is done. </param>
|
||||
const std::string& GetId() const {
|
||||
return _zoneId;
|
||||
}
|
||||
|
||||
/// <see cref="Zone::Broadcast" />
|
||||
virtual void Broadcast(const std::string& source, BroadcastCallback callback) override {
|
||||
void Broadcast(const std::string& source, BroadcastCallback callback) {
|
||||
// Will be deleted on when the callback scope ends.
|
||||
auto context = new BroadcastCallback(std::move(callback));
|
||||
|
||||
|
@ -70,22 +67,37 @@ namespace napa {
|
|||
}, context);
|
||||
}
|
||||
|
||||
/// <see cref="Zone::Execute" />
|
||||
virtual void Execute(const ExecuteRequest& request, ExecuteCallback callback) override {
|
||||
/// <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;
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Broadcast(source, [&prom](ResponseCode code) {
|
||||
prom.set_value(code);
|
||||
});
|
||||
|
||||
return fut.get();
|
||||
}
|
||||
|
||||
/// <summary> Executes a pre-loaded JS function asynchronously. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
/// <param name="callback"> A callback that is triggered when execution is done. </param>
|
||||
void Execute(const ExecuteRequest& request, ExecuteCallback callback) {
|
||||
// Will be deleted on when the callback scope ends.
|
||||
auto context = new ExecuteCallback(std::move(callback));
|
||||
|
||||
napa_zone_request req;
|
||||
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.timeout = request.timeout;
|
||||
req.options = request.options;
|
||||
|
||||
// Release ownership of transport context
|
||||
req.transport_context = reinterpret_cast<void*>(request.transportContext.release());
|
||||
|
||||
napa_zone_execute(_handle, req, [](napa_zone_response response, void* context) {
|
||||
napa_zone_execute(_handle, req, [](napa_zone_execute_response response, void* context) {
|
||||
// Ensures the context is deleted when this scope ends.
|
||||
std::unique_ptr<ExecuteCallback> callback(reinterpret_cast<ExecuteCallback*>(context));
|
||||
|
||||
|
@ -102,31 +114,44 @@ namespace napa {
|
|||
}, 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;
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Execute(request, [&prom](ExecuteResponse response) {
|
||||
prom.set_value(std::move(response));
|
||||
});
|
||||
|
||||
return fut.get();
|
||||
}
|
||||
|
||||
/// <summary> Retrieves a new zone proxy for the zone id, throws if zone is not found. </summary>
|
||||
static std::unique_ptr<ZoneProxy> Get(const std::string& id) {
|
||||
static std::unique_ptr<Zone> Get(const std::string& id) {
|
||||
auto handle = napa_zone_get(STD_STRING_TO_NAPA_STRING_REF(id));
|
||||
if (!handle) {
|
||||
throw std::runtime_error("No zone exists for id '" + id + "'");
|
||||
}
|
||||
|
||||
return std::unique_ptr<ZoneProxy>(new ZoneProxy(id, handle));
|
||||
return std::unique_ptr<Zone>(new Zone(id, handle));
|
||||
}
|
||||
|
||||
/// <summary> Creates a proxy to the current zone, throws if non is associated with this thread. </summary>
|
||||
static std::unique_ptr<ZoneProxy> GetCurrent() {
|
||||
static std::unique_ptr<Zone> GetCurrent() {
|
||||
auto handle = napa_zone_get_current();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("The calling thread is not associated with a zone");
|
||||
}
|
||||
|
||||
auto zoneId = NAPA_STRING_REF_TO_STD_STRING(napa_zone_get_id(handle));
|
||||
return std::unique_ptr<ZoneProxy>(new ZoneProxy(std::move(zoneId), handle));
|
||||
return std::unique_ptr<Zone>(new Zone(std::move(zoneId), handle));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// <summary> Private constructor to create a C++ zone proxy from a C handle. </summary>
|
||||
explicit ZoneProxy(const std::string& id, napa_zone_handle handle) : _zoneId(id), _handle(handle) {}
|
||||
explicit Zone(const std::string& id, napa_zone_handle handle) : _zoneId(id), _handle(handle) {}
|
||||
|
||||
/// <summary> The zone id. </summary>
|
||||
std::string _zoneId;
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
/// <summary> Simple non ownning string. Should only be used for binding. </summary>
|
||||
typedef struct {
|
||||
const char* data;
|
||||
size_t size;
|
||||
} napa_string_ref;
|
||||
|
||||
typedef napa_string_ref NapaStringRef;
|
||||
|
||||
#define NAPA_STRING_REF_WITH_SIZE(data, size) (napa_string_ref { (data), (size) })
|
||||
#define NAPA_STRING_REF(data) NAPA_STRING_REF_WITH_SIZE(data, strlen(data))
|
||||
|
||||
const napa_string_ref EMPTY_NAPA_STRING_REF = NAPA_STRING_REF_WITH_SIZE(0, 0);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#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))
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#define NAPA_RESPONSE_CODE_DEF(symbol, ...) NAPA_RESPONSE_##symbol
|
||||
|
||||
typedef enum {
|
||||
|
||||
#include "napa/response-codes.inc"
|
||||
|
||||
} napa_response_code;
|
||||
|
||||
#undef NAPA_RESPONSE_CODE_DEF
|
||||
|
||||
typedef napa_response_code NapaResponseCode;
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa-c.h>
|
||||
#include <string>
|
||||
#include <napa/exports.h>
|
||||
|
||||
namespace napa {
|
||||
namespace memory {
|
||||
|
@ -30,68 +29,9 @@ namespace memory {
|
|||
virtual ~Allocator() = default;
|
||||
};
|
||||
|
||||
/// <summary> C runtime allocator from napa.dll. </summary>
|
||||
class CrtAllocator: public Allocator {
|
||||
public:
|
||||
/// <summary> Allocate memory of given size. </summary>
|
||||
/// <param name="size"> Requested size. </summary>
|
||||
/// <returns> Allocated memory. May throw if error happens. </returns>
|
||||
void* Allocate(size_t size) override {
|
||||
return ::napa_malloc(size);
|
||||
}
|
||||
|
||||
/// <summary> Deallocate memory allocated from this allocator. </summary>
|
||||
/// <param name="memory"> Pointer to the memory. </summary>
|
||||
/// <param name="sizeHint"> Hint of size to delete. 0 if not available from caller. </summary>
|
||||
/// <returns> None. May throw if error happens. </returns>
|
||||
void CrtAllocator::Deallocate(void* memory, size_t sizeHint) override {
|
||||
::napa_free(memory, sizeHint);
|
||||
}
|
||||
|
||||
/// <summary> Get allocator type for better debuggability. </summary>
|
||||
const char* CrtAllocator::GetType() const override {
|
||||
return "CrtAllocator";
|
||||
}
|
||||
|
||||
/// <summary> Tell if another allocator equals to this allocator. </summary>
|
||||
bool operator==(const Allocator& other) const override {
|
||||
return strcmp(other.GetType(), GetType()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary> Get a long living CRT allocator for convenience. User can create their own as well.</summary>
|
||||
NAPA_API Allocator& GetCrtAllocator();
|
||||
|
||||
/// <summary> Allocator that uses napa_allocate and napa_deallocate. </summary>
|
||||
class DefaultAllocator: public Allocator {
|
||||
public:
|
||||
public:
|
||||
/// <summary> Allocate memory of given size. </summary>
|
||||
/// <param name="size"> Requested size. </summary>
|
||||
/// <returns> Allocated memory. May throw if error happens. </returns>
|
||||
void* Allocate(size_t size) override {
|
||||
return ::napa_allocate(size);
|
||||
}
|
||||
|
||||
/// <summary> Deallocate memory allocated from this allocator. </summary>
|
||||
/// <param name="memory"> Pointer to the memory. </summary>
|
||||
/// <param name="sizeHint"> Hint of size to delete. 0 if not available from caller. </summary>
|
||||
/// <returns> None. May throw if error happens. </returns>
|
||||
void Deallocate(void* memory, size_t sizeHint) override {
|
||||
return ::napa_deallocate(memory, sizeHint);
|
||||
}
|
||||
|
||||
/// <summary> Get allocator type for better debuggability. </summary>
|
||||
const char* GetType() const override {
|
||||
return "DefaultAllocator";
|
||||
}
|
||||
|
||||
/// <summary> Tell if another allocator equals to this allocator. </summary>
|
||||
bool operator==(const Allocator& other) const override {
|
||||
return strcmp(other.GetType(), GetType()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary> Get a long living default allocator for convenience. User can create their own as well.</summary>
|
||||
NAPA_API Allocator& GetDefaultAllocator();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
#pragma once
|
||||
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
|
||||
/// <summary> Simple non ownning string. Should only be used for binding. </summary>
|
||||
typedef struct {
|
||||
const char* data;
|
||||
size_t size;
|
||||
} napa_string_ref;
|
||||
|
||||
#define NAPA_STRING_REF_WITH_SIZE(data, size) (napa_string_ref { (data), (size) })
|
||||
#define NAPA_STRING_REF(data) NAPA_STRING_REF_WITH_SIZE(data, strlen(data))
|
||||
|
||||
const napa_string_ref EMPTY_NAPA_STRING_REF = NAPA_STRING_REF_WITH_SIZE(0, 0);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
typedef napa_string_ref StringRef;
|
||||
}
|
||||
|
||||
#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))
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents response code in napa zone apis. </summary>
|
||||
#define NAPA_RESPONSE_CODE_DEF(symbol, ...) NAPA_RESPONSE_##symbol
|
||||
|
||||
typedef enum {
|
||||
|
||||
#include "napa/response-codes.inc"
|
||||
|
||||
} napa_response_code;
|
||||
|
||||
#undef NAPA_RESPONSE_CODE_DEF
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
typedef napa_response_code ResponseCode;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents option for transporting objects in zone.execute. </summary>
|
||||
typedef enum {
|
||||
|
||||
/// <summary>
|
||||
/// transport.marshall/unmarshall will be done by `napajs` automatically.
|
||||
/// This is the most common way, but may not be performance optimal with objects
|
||||
/// that will be shared in multiple zone.execute.
|
||||
/// </summary>
|
||||
AUTO,
|
||||
|
||||
/// <summary> transport.marshall/unmarshall will be done by user manually. </summary>
|
||||
MANUAL,
|
||||
} napa_transport_option;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
typedef napa_transport_option TransportOption;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents options for an execution request. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> Timeout in milliseconds - Use 0 for inifinite. </summary>
|
||||
uint32_t timeout;
|
||||
|
||||
/// <summary> Arguments transport option. Default is AUTO. </summary>
|
||||
napa_transport_option transport;
|
||||
} napa_zone_execute_options;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
typedef napa_zone_execute_options ExecuteOptions;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents an execution request for a zone. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> The module that exports the function to execute. </summary>
|
||||
napa_string_ref module;
|
||||
|
||||
/// <summary> The function to execute. </summary>
|
||||
napa_string_ref function;
|
||||
|
||||
/// <summary> The function arguments. </summary>
|
||||
const napa_string_ref* arguments;
|
||||
|
||||
/// <summary> The number of arguments. </summary>
|
||||
size_t arguments_count;
|
||||
|
||||
/// <summary> Options. </summary>
|
||||
napa_zone_execute_options options;
|
||||
|
||||
/// <summary> A context used for transporting handles across zones/workers. </summary>
|
||||
void* transport_context;
|
||||
} napa_zone_execute_request;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <napa/transport/transport-context.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace napa {
|
||||
/// <summary> Represents an execution request. </summary>
|
||||
struct ExecuteRequest {
|
||||
|
||||
/// <summary> The module that exports the function to execute. </summary>
|
||||
StringRef module = EMPTY_NAPA_STRING_REF;
|
||||
|
||||
/// <summary> The function to execute. </summary>
|
||||
StringRef function = EMPTY_NAPA_STRING_REF;
|
||||
|
||||
/// <summary> The function arguments. </summary>
|
||||
std::vector<StringRef> arguments;
|
||||
|
||||
/// <summary> Execute options. </summary>
|
||||
ExecuteOptions options = { 0, AUTO };
|
||||
|
||||
/// <summary> Used for transporting shared_ptr and unique_ptr across zones/workers. </summary>
|
||||
mutable std::unique_ptr<napa::transport::TransportContext> transportContext;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Represents a response from executing in a zone. </summary>
|
||||
typedef struct {
|
||||
|
||||
/// <summary> A response code. </summary>
|
||||
napa_response_code code;
|
||||
|
||||
/// <summary> The error message in case of an error. </summary>
|
||||
napa_string_ref error_message;
|
||||
|
||||
/// <summary> The return value in case of success. </summary>
|
||||
napa_string_ref return_value;
|
||||
|
||||
/// <summary> A context used for transporting handles across zones/workers. </summary>
|
||||
void* transport_context;
|
||||
} napa_zone_execute_response;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace napa {
|
||||
/// <summary> Represents an execution response. </summary>
|
||||
struct ExecuteResponse {
|
||||
|
||||
/// <summary> A response code. </summary>
|
||||
ResponseCode code;
|
||||
|
||||
/// <summary> The error message in case of an error. </summary>
|
||||
std::string errorMessage;
|
||||
|
||||
/// <summary> The return value in case of success. </summary>
|
||||
std::string returnValue;
|
||||
|
||||
/// <summary> Used for transporting shared_ptr and unique_ptr across zones/workers. </summary>
|
||||
mutable std::unique_ptr<napa::transport::TransportContext> transportContext;
|
||||
};
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace napa {
|
||||
typedef std::function<void(ResponseCode)> BroadcastCallback;
|
||||
typedef std::function<void(ExecuteResponse)> ExecuteCallback;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
/// <summary> Zone handle type. </summary>
|
||||
typedef struct napa_zone *napa_zone_handle;
|
||||
|
||||
/// <summary> Callback for customized memory allocator. </summary>
|
||||
typedef void* (*napa_allocate_callback)(size_t);
|
||||
typedef void (*napa_deallocate_callback)(void*, size_t);
|
|
@ -1,99 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/common.h>
|
||||
#include <napa/transport/transport-context.h>
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace napa {
|
||||
|
||||
/// <summary> Represents an execution request. </summary>
|
||||
struct ExecuteRequest {
|
||||
|
||||
/// <summary> The module that exports the function to execute. </summary>
|
||||
NapaStringRef module = EMPTY_NAPA_STRING_REF;
|
||||
|
||||
/// <summary> The function to execute. </summary>
|
||||
NapaStringRef function = EMPTY_NAPA_STRING_REF;
|
||||
|
||||
/// <summary> The function arguments. </summary>
|
||||
std::vector<NapaStringRef> arguments;
|
||||
|
||||
/// <summary> Timeout in milliseconds - Use 0 for inifinite. </summary>
|
||||
uint32_t timeout = 0;
|
||||
|
||||
/// <summary> Used for transporting shared_ptr and unique_ptr across zones/workers. </summary>
|
||||
mutable std::unique_ptr<napa::transport::TransportContext> transportContext;
|
||||
};
|
||||
|
||||
/// <summary> Represents an execution response. </summary>
|
||||
struct ExecuteResponse {
|
||||
|
||||
/// <summary> A response code. </summary>
|
||||
NapaResponseCode code;
|
||||
|
||||
/// <summary> The error message in case of an error. </summary>
|
||||
std::string errorMessage;
|
||||
|
||||
/// <summary> The return value in case of success. </summary>
|
||||
std::string returnValue;
|
||||
|
||||
/// <summary> Used for transporting shared_ptr and unique_ptr across zones/workers. </summary>
|
||||
mutable std::unique_ptr<napa::transport::TransportContext> transportContext;
|
||||
};
|
||||
|
||||
/// <summary> Callback signature. </summary>
|
||||
typedef std::function<void(NapaResponseCode)> BroadcastCallback;
|
||||
typedef std::function<void(ExecuteResponse)> ExecuteCallback;
|
||||
|
||||
/// <summary> Base class for napa zone. </summary>
|
||||
struct Zone {
|
||||
|
||||
/// <summary> Get the zone id. </summary>
|
||||
virtual const std::string& GetId() const = 0;
|
||||
|
||||
/// <summary> Compiles and run the provided source code on all zone workers asynchronously. </summary>
|
||||
/// <param name="source"> The source code. </param>
|
||||
/// <param name="callback"> A callback that is triggered when broadcasting is done. </param>
|
||||
virtual void Broadcast(const std::string& source, BroadcastCallback callback) = 0;
|
||||
|
||||
/// <summary> Executes a pre-loaded JS function asynchronously. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
/// <param name="callback"> A callback that is triggered when execution is done. </param>
|
||||
virtual void Execute(const ExecuteRequest& request, ExecuteCallback callback) = 0;
|
||||
|
||||
/// <summary> Compiles and run the provided source code on all zone workers synchronously. </summary>
|
||||
/// <param name="source"> The source code. </param>
|
||||
virtual NapaResponseCode BroadcastSync(const std::string& source) {
|
||||
std::promise<NapaResponseCode> prom;
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Broadcast(source, [&prom](NapaResponseCode code) {
|
||||
prom.set_value(code);
|
||||
});
|
||||
|
||||
return fut.get();
|
||||
}
|
||||
|
||||
/// <summary> Executes a pre-loaded JS function synchronously. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
virtual ExecuteResponse ExecuteSync(const ExecuteRequest& request) {
|
||||
std::promise<ExecuteResponse> prom;
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Execute(request, [&prom](ExecuteResponse response) {
|
||||
prom.set_value(std::move(response));
|
||||
});
|
||||
|
||||
return fut.get();
|
||||
}
|
||||
|
||||
/// <summary> Virtual destructor. </summary>
|
||||
virtual ~Zone() {}
|
||||
};
|
||||
}
|
|
@ -7,12 +7,12 @@ interface ExecuteRequest {
|
|||
module: string;
|
||||
function: string;
|
||||
arguments: any[];
|
||||
timeout: number;
|
||||
options: zone.ExecuteOptions;
|
||||
transportContext: transport.TransportContext;
|
||||
}
|
||||
|
||||
export class NapaExecuteResult implements zone.ExecuteResult{
|
||||
|
||||
|
||||
constructor(payload: string, transportContext: transport.TransportContext) {
|
||||
this._payload = payload;
|
||||
this._transportContext = transportContext;
|
||||
|
@ -140,19 +140,19 @@ export class NapaZone implements zone.Zone {
|
|||
let moduleName: string = null;
|
||||
let functionName: string = null;
|
||||
let args: any[] = null;
|
||||
let timeout: number = 0;
|
||||
let options: zone.ExecuteOptions = undefined;
|
||||
|
||||
if (typeof arg1 === 'function') {
|
||||
moduleName = "__function";
|
||||
functionName = transport.saveFunction(arg1);
|
||||
args = arg2;
|
||||
timeout = arg3;
|
||||
options = arg3;
|
||||
}
|
||||
else {
|
||||
moduleName = arg1;
|
||||
functionName = arg2;
|
||||
args = arg3;
|
||||
timeout = arg4;
|
||||
options = arg4;
|
||||
}
|
||||
|
||||
let transportContext: transport.TransportContext = transport.createTransportContext();
|
||||
|
@ -160,7 +160,7 @@ export class NapaZone implements zone.Zone {
|
|||
module: moduleName,
|
||||
function: functionName,
|
||||
arguments: (<Array<any>>args).map(arg => { return transport.marshall(arg, transportContext); }),
|
||||
timeout: timeout,
|
||||
options: options != null? options: zone.DEFAULT_EXECUTE_OPTIONS,
|
||||
transportContext: transportContext
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var transport = require('napajs/lib/transport');
|
||||
|
||||
function __zone_execute__(moduleName, functionName, args, contextHandle) {
|
||||
function __zone_execute__(moduleName, functionName, args, transportContextHandle, options) {
|
||||
var module = null;
|
||||
if (moduleName == null || moduleName.length === 0) {
|
||||
module = this;
|
||||
|
@ -28,7 +28,7 @@ function __zone_execute__(moduleName, functionName, args, contextHandle) {
|
|||
func = transport.loadFunction(functionName);
|
||||
}
|
||||
|
||||
var transportContext = transport.createTransportContext(contextHandle);
|
||||
var transportContext = transport.createTransportContext(transportContextHandle);
|
||||
var args = args.map((arg) => { return transport.unmarshall(arg, transportContext); });
|
||||
return transport.marshall(func.apply(this, args), transportContext);
|
||||
}
|
|
@ -14,6 +14,39 @@ export let DEFAULT_SETTINGS: ZoneSettings = {
|
|||
workers: 2
|
||||
};
|
||||
|
||||
/// <summary> Represent option to transport arguments in zone.execute. </summary>
|
||||
export enum TransportOption {
|
||||
|
||||
/// <summary> transport.marshall/unmarshall will be done by `napajs` automatically.
|
||||
/// This is the most common way, but may not be performance optimal with objects
|
||||
/// that will be shared in multiple zone.execute.
|
||||
/// </summary>
|
||||
AUTO,
|
||||
|
||||
/// <summary> transport.marshall/unmarshall will be done by user manually. </summary>
|
||||
MANUAL,
|
||||
}
|
||||
|
||||
/// <summary> Represent the options of an execute call. </summary>
|
||||
export interface ExecuteOptions {
|
||||
|
||||
/// <summary> Timeout in milliseconds. By default set to 0 if timeout is not needed. </summary>
|
||||
timeout?: number,
|
||||
|
||||
/// <summary> Transport option on passing arguments. By default set to TransportOption.AUTO </summary>
|
||||
transport?: TransportOption
|
||||
}
|
||||
|
||||
/// <summary> Default execution options. </summary>
|
||||
export let DEFAULT_EXECUTE_OPTIONS: ExecuteOptions = {
|
||||
|
||||
/// <summary> No timeout. </summary>
|
||||
timeout: 0,
|
||||
|
||||
/// <summary> Set argument transport option to automatic. </summary>
|
||||
transport: TransportOption.AUTO
|
||||
}
|
||||
|
||||
/// <summary> Represent the result of an execute call. </summary>
|
||||
export interface ExecuteResult {
|
||||
|
||||
|
@ -48,14 +81,14 @@ 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="timeout"> The timeout of the execution in milliseconds, defaults to infinity. </param>
|
||||
execute(module: string, func: string, args: any[], timeout?: number) : Promise<ExecuteResult>;
|
||||
executeSync(module: string, func: string, args: any[], timeout?: number) : ExecuteResult;
|
||||
/// <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;
|
||||
|
||||
/// <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="timeout"> The timeout of the execution in milliseconds, defaults to infinity. </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;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ static PlatformSettings _platformSettings;
|
|||
/// <summary> a simple wrapper around Zone for managing lifetime using shared_ptr. </summary>
|
||||
struct napa_zone {
|
||||
std::string id;
|
||||
std::shared_ptr<Zone> zone;
|
||||
std::shared_ptr<internal::Zone> zone;
|
||||
};
|
||||
|
||||
napa_zone_handle napa_zone_create(napa_string_ref id) {
|
||||
|
@ -115,7 +115,7 @@ void napa_zone_broadcast(napa_zone_handle handle,
|
|||
}
|
||||
|
||||
void napa_zone_execute(napa_zone_handle handle,
|
||||
napa_zone_request request,
|
||||
napa_zone_execute_request request,
|
||||
napa_zone_execute_callback callback,
|
||||
void* context) {
|
||||
NAPA_ASSERT(_initialized, "Napa wasn't initialized");
|
||||
|
@ -131,13 +131,13 @@ void napa_zone_execute(napa_zone_handle handle,
|
|||
req.arguments.emplace_back(request.arguments[i]);
|
||||
}
|
||||
|
||||
req.timeout = request.timeout;
|
||||
req.options = request.options;
|
||||
|
||||
// Assume ownership of transport context
|
||||
req.transportContext.reset(reinterpret_cast<napa::transport::TransportContext*>(request.transport_context));
|
||||
|
||||
handle->zone->Execute(req, [callback, context](ExecuteResponse response) {
|
||||
napa_zone_response res;
|
||||
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);
|
||||
|
|
|
@ -1,18 +1,79 @@
|
|||
#include <napa-memory.h>
|
||||
#include <napa-c.h>
|
||||
|
||||
/// <summary> C runtime allocator from napa.dll. </summary>
|
||||
class CrtAllocator: public napa::memory::Allocator {
|
||||
public:
|
||||
/// <summary> Allocate memory of given size. </summary>
|
||||
/// <param name="size"> Requested size. </summary>
|
||||
/// <returns> Allocated memory. May throw if error happens. </returns>
|
||||
void* Allocate(size_t size) override {
|
||||
return ::napa_malloc(size);
|
||||
}
|
||||
|
||||
/// <summary> Deallocate memory allocated from this allocator. </summary>
|
||||
/// <param name="memory"> Pointer to the memory. </summary>
|
||||
/// <param name="sizeHint"> Hint of size to delete. 0 if not available from caller. </summary>
|
||||
/// <returns> None. May throw if error happens. </returns>
|
||||
void CrtAllocator::Deallocate(void* memory, size_t sizeHint) override {
|
||||
::napa_free(memory, sizeHint);
|
||||
}
|
||||
|
||||
/// <summary> Get allocator type for better debuggability. </summary>
|
||||
const char* CrtAllocator::GetType() const override {
|
||||
return "CrtAllocator";
|
||||
}
|
||||
|
||||
/// <summary> Tell if another allocator equals to this allocator. </summary>
|
||||
bool operator==(const Allocator& other) const override {
|
||||
return strcmp(other.GetType(), GetType()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary> Allocator that uses napa_allocate and napa_deallocate. </summary>
|
||||
class DefaultAllocator: public napa::memory::Allocator {
|
||||
public:
|
||||
public:
|
||||
/// <summary> Allocate memory of given size. </summary>
|
||||
/// <param name="size"> Requested size. </summary>
|
||||
/// <returns> Allocated memory. May throw if error happens. </returns>
|
||||
void* Allocate(size_t size) override {
|
||||
return ::napa_allocate(size);
|
||||
}
|
||||
|
||||
/// <summary> Deallocate memory allocated from this allocator. </summary>
|
||||
/// <param name="memory"> Pointer to the memory. </summary>
|
||||
/// <param name="sizeHint"> Hint of size to delete. 0 if not available from caller. </summary>
|
||||
/// <returns> None. May throw if error happens. </returns>
|
||||
void Deallocate(void* memory, size_t sizeHint) override {
|
||||
return ::napa_deallocate(memory, sizeHint);
|
||||
}
|
||||
|
||||
/// <summary> Get allocator type for better debuggability. </summary>
|
||||
const char* GetType() const override {
|
||||
return "DefaultAllocator";
|
||||
}
|
||||
|
||||
/// <summary> Tell if another allocator equals to this allocator. </summary>
|
||||
bool operator==(const Allocator& other) const override {
|
||||
return strcmp(other.GetType(), GetType()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace napa {
|
||||
namespace memory {
|
||||
namespace {
|
||||
CrtAllocator _crtAllocator;
|
||||
DefaultAllocator _defaultAllocator;
|
||||
} // namespace
|
||||
namespace memory {
|
||||
|
||||
Allocator& GetCrtAllocator() {
|
||||
return _crtAllocator;
|
||||
}
|
||||
namespace {
|
||||
CrtAllocator _crtAllocator;
|
||||
DefaultAllocator _defaultAllocator;
|
||||
} // namespace
|
||||
|
||||
Allocator& GetDefaultAllocator() {
|
||||
return _defaultAllocator;
|
||||
}
|
||||
} // namespace memory
|
||||
Allocator& GetCrtAllocator() {
|
||||
return _crtAllocator;
|
||||
}
|
||||
|
||||
Allocator& GetDefaultAllocator() {
|
||||
return _defaultAllocator;
|
||||
}
|
||||
} // namespace memory
|
||||
} // namespace napa
|
|
@ -37,7 +37,9 @@ void AllocatorDebuggerWrap::ConstructorCallback(const v8::FunctionCallbackInfo<v
|
|||
|
||||
std::shared_ptr<napa::memory::Allocator> allocator;
|
||||
if (args.Length() == 0) {
|
||||
allocator = NAPA_MAKE_SHARED<napa::memory::DefaultAllocator>();
|
||||
allocator = std::shared_ptr<napa::memory::Allocator>(
|
||||
&napa::memory::GetDefaultAllocator(),
|
||||
[](napa::memory::Allocator*){});
|
||||
}
|
||||
else {
|
||||
CHECK_ARG(isolate, args[0]->IsObject(), "Argument \"allocator\" should be \"AllocatorWrap\" type.'");
|
||||
|
|
|
@ -47,7 +47,7 @@ static void CreateZone(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
}
|
||||
|
||||
try {
|
||||
auto zoneProxy = std::make_unique<napa::ZoneProxy>(*zoneId, ss.str());
|
||||
auto zoneProxy = std::make_unique<napa::Zone>(*zoneId, ss.str());
|
||||
args.GetReturnValue().Set(ZoneWrap::NewInstance(std::move(zoneProxy)));
|
||||
} catch (const std::exception& ex) {
|
||||
JS_FAIL(isolate, ex.what());
|
||||
|
@ -62,7 +62,7 @@ static void GetZone(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
v8::String::Utf8Value zoneId(args[0]->ToString());
|
||||
|
||||
try {
|
||||
auto zoneProxy = napa::ZoneProxy::Get(*zoneId);
|
||||
auto zoneProxy = napa::Zone::Get(*zoneId);
|
||||
args.GetReturnValue().Set(ZoneWrap::NewInstance(std::move(zoneProxy)));
|
||||
}
|
||||
catch (const std::exception &ex) {
|
||||
|
@ -74,7 +74,7 @@ static void GetCurrentZone(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
args.GetReturnValue().Set(ZoneWrap::NewInstance(napa::ZoneProxy::GetCurrent()));
|
||||
args.GetReturnValue().Set(ZoneWrap::NewInstance(napa::Zone::GetCurrent()));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -128,11 +128,17 @@ static void GetStoreCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
}
|
||||
|
||||
static void GetCrtAllocator(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(binding::CreateAllocatorWrap(NAPA_MAKE_SHARED<napa::memory::CrtAllocator>()));
|
||||
args.GetReturnValue().Set(binding::CreateAllocatorWrap(
|
||||
std::shared_ptr<napa::memory::Allocator>(
|
||||
&napa::memory::GetCrtAllocator(),
|
||||
[](napa::memory::Allocator*){})));
|
||||
}
|
||||
|
||||
static void GetDefaultAllocator(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(binding::CreateAllocatorWrap(NAPA_MAKE_SHARED<napa::memory::DefaultAllocator>()));
|
||||
args.GetReturnValue().Set(binding::CreateAllocatorWrap(
|
||||
std::shared_ptr<napa::memory::Allocator>(
|
||||
&napa::memory::GetDefaultAllocator(),
|
||||
[](napa::memory::Allocator*){})));
|
||||
}
|
||||
|
||||
static void Log(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
|
|
|
@ -38,7 +38,7 @@ void ZoneWrap::Init() {
|
|||
NAPA_SET_PERSISTENT_CONSTRUCTOR(exportName, functionTemplate->GetFunction());
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> ZoneWrap::NewInstance(std::unique_ptr<napa::ZoneProxy> zoneProxy) {
|
||||
v8::Local<v8::Object> ZoneWrap::NewInstance(std::unique_ptr<napa::Zone> zoneProxy) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
|
@ -70,7 +70,7 @@ void ZoneWrap::Broadcast(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
[&args, &source](std::function<void(void*)> complete) {
|
||||
auto wrap = ObjectWrap::Unwrap<ZoneWrap>(args.Holder());
|
||||
|
||||
wrap->_zoneProxy->Broadcast(*source, [complete = std::move(complete)](NapaResponseCode responseCode) {
|
||||
wrap->_zoneProxy->Broadcast(*source, [complete = std::move(complete)](ResponseCode responseCode) {
|
||||
complete(reinterpret_cast<void*>(static_cast<uintptr_t>(responseCode)));
|
||||
});
|
||||
},
|
||||
|
@ -81,7 +81,7 @@ void ZoneWrap::Broadcast(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
v8::HandleScope scope(isolate);
|
||||
|
||||
std::vector<v8::Local<v8::Value>> argv;
|
||||
auto responseCode = static_cast<NapaResponseCode>(reinterpret_cast<uintptr_t>(result));
|
||||
auto responseCode = static_cast<ResponseCode>(reinterpret_cast<uintptr_t>(result));
|
||||
argv.emplace_back(v8::Uint32::NewFromUnsigned(isolate, responseCode));
|
||||
|
||||
(void)jsCallback->Call(context, context->Global(), static_cast<int>(argv.size()), argv.data());
|
||||
|
@ -216,10 +216,24 @@ static void CreateRequestAndExecute(v8::Local<v8::Object> obj, Func&& func) {
|
|||
}
|
||||
}
|
||||
|
||||
// timeout argument is optional
|
||||
maybe = obj->Get(context, MakeV8String(isolate, "timeout"));
|
||||
// options argument is optional.
|
||||
maybe = obj->Get(context, MakeV8String(isolate, "options"));
|
||||
if (!maybe.IsEmpty()) {
|
||||
request.timeout = maybe.ToLocalChecked()->Uint32Value(context).FromJust();
|
||||
auto optionsValue = maybe.ToLocalChecked();
|
||||
JS_ENSURE(isolate, optionsValue->IsObject(), "argument 'options' must be an object.");
|
||||
auto options = v8::Local<v8::Object>::Cast(optionsValue);
|
||||
|
||||
// timeout is optional.
|
||||
maybe = options->Get(context, MakeV8String(isolate, "timeout"));
|
||||
if (!maybe.IsEmpty()) {
|
||||
request.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());
|
||||
}
|
||||
}
|
||||
|
||||
// transportContext property is mandatory in a request
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
// Forward declare zone.
|
||||
namespace napa {
|
||||
class ZoneProxy;
|
||||
class Zone;
|
||||
}
|
||||
|
||||
namespace napa {
|
||||
|
@ -24,14 +24,14 @@ namespace module {
|
|||
static void Init();
|
||||
|
||||
/// <summary> Create a new ZoneWrap instance that wraps the provided proxy. </summary>
|
||||
static v8::Local<v8::Object> NewInstance(std::unique_ptr<napa::ZoneProxy> zoneProxy);
|
||||
static v8::Local<v8::Object> NewInstance(std::unique_ptr<napa::Zone> zoneProxy);
|
||||
|
||||
private:
|
||||
|
||||
/// <summary> Declare persistent constructor to create Zone Javascript wrapper instance. </summary>
|
||||
NAPA_DECLARE_PERSISTENT_CONSTRUCTOR;
|
||||
|
||||
std::unique_ptr<napa::ZoneProxy> _zoneProxy;
|
||||
std::unique_ptr<napa::Zone> _zoneProxy;
|
||||
|
||||
// ZoneWrap methods
|
||||
static void GetId(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "task.h"
|
||||
|
||||
#include "napa/common.h"
|
||||
#include "napa/types.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
@ -15,7 +15,7 @@ namespace scheduler {
|
|||
public:
|
||||
|
||||
/// <summary> Signature of the callback function. </summary>
|
||||
typedef std::function<void(NapaResponseCode responseCode)> BroadcastTaskCallback;
|
||||
typedef std::function<void(ResponseCode responseCode)> BroadcastTaskCallback;
|
||||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="source"> The JS source code to load on the isolate the runs this task. </param>
|
||||
|
@ -23,7 +23,7 @@ namespace scheduler {
|
|||
/// <param name="callback"> A callback that is triggered when the task execution completed. </param>
|
||||
BroadcastTask(std::string source,
|
||||
std::string sourceOrigin = "",
|
||||
BroadcastTaskCallback callback = [](NapaResponseCode) {});
|
||||
BroadcastTaskCallback callback = [](ResponseCode) {});
|
||||
|
||||
/// <summary> Overrides Task.Execute to define loading execution logic. </summary>
|
||||
virtual void Execute() override;
|
||||
|
|
|
@ -17,6 +17,7 @@ napa::scheduler::ExecuteTask::ExecuteTask(const ExecuteRequest& request, Execute
|
|||
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);
|
||||
|
@ -37,16 +38,21 @@ void ExecuteTask::Execute() {
|
|||
(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())
|
||||
PtrToV8Uint32Array(isolate, _transportContext.get()),
|
||||
options
|
||||
};
|
||||
|
||||
// Execute the function.
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
auto res = v8::Local<v8::Function>::Cast(executeFunction)->Call(context->Global(), 4, argv);
|
||||
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
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
#include "terminable-task.h"
|
||||
|
||||
#include <napa/common.h>
|
||||
#include <napa/zone.h>
|
||||
#include <napa/types.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
@ -28,6 +27,7 @@ namespace scheduler {
|
|||
std::string _module;
|
||||
std::string _func;
|
||||
std::vector<std::string> _args;
|
||||
ExecuteOptions _options;
|
||||
ExecuteCallback _callback;
|
||||
std::unique_ptr<napa::transport::TransportContext> _transportContext;
|
||||
};
|
||||
|
|
|
@ -47,7 +47,6 @@ std::shared_ptr<ZoneImpl> ZoneImpl::Create(const ZoneSettings& settings) {
|
|||
LOG_ERROR("Zone", "Failed to initialize zone '%s': %s", settings.id.c_str(), ex.what());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
|
@ -102,9 +101,9 @@ void ZoneImpl::Broadcast(const std::string& source, BroadcastCallback callback)
|
|||
void ZoneImpl::Execute(const ExecuteRequest& request, ExecuteCallback callback) {
|
||||
std::shared_ptr<Task> task;
|
||||
|
||||
if (request.timeout > 0) {
|
||||
if (request.options.timeout > 0) {
|
||||
task = std::make_shared<TimeoutTaskDecorator<ExecuteTask>>(
|
||||
std::chrono::milliseconds(request.timeout),
|
||||
std::chrono::milliseconds(request.options.timeout),
|
||||
request,
|
||||
std::move(callback));
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/zone.h>
|
||||
#include "zone.h"
|
||||
|
||||
#include "scheduler/scheduler.h"
|
||||
#include "settings/settings.h"
|
||||
|
@ -13,7 +13,7 @@
|
|||
namespace napa {
|
||||
|
||||
/// <summary> Concrete implementation of a zone. </summary>
|
||||
class ZoneImpl : public Zone {
|
||||
class ZoneImpl : public internal::Zone {
|
||||
public:
|
||||
|
||||
/// <summary> Creates a new zone with the provided id and settings. </summary>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/types.h>
|
||||
|
||||
namespace napa {
|
||||
namespace internal {
|
||||
|
||||
/// <summary> Interface for Zone. </summary>
|
||||
struct Zone {
|
||||
|
||||
/// <summary> Get the zone id. </summary>
|
||||
virtual const std::string& GetId() const = 0;
|
||||
|
||||
/// <summary> Compiles and run the provided source code on all zone workers asynchronously. </summary>
|
||||
/// <param name="source"> The source code. </param>
|
||||
/// <param name="callback"> A callback that is triggered when broadcasting is done. </param>
|
||||
virtual void Broadcast(const std::string& source, BroadcastCallback callback) = 0;
|
||||
|
||||
/// <summary> Executes a pre-loaded JS function asynchronously. </summary>
|
||||
/// <param name="request"> The execution request. </param>
|
||||
/// <param name="callback"> A callback that is triggered when execution is done. </param>
|
||||
virtual void Execute(const ExecuteRequest& request, ExecuteCallback callback) = 0;
|
||||
|
||||
/// <summary> Virtual destructor. </summary>
|
||||
virtual ~Zone() {}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -104,7 +104,7 @@ TEST_CASE("Napa memory allocator tests", "[memory-allocators]") {
|
|||
SECTION("Test CreateSimpleAllocatorDebugger") {
|
||||
NAPA_SET_DEFAULT_ALLOCATOR(custom_allocator::malloc, custom_allocator::free);
|
||||
|
||||
SimpleAllocatorDebugger debugger(std::make_shared<DefaultAllocator>());
|
||||
SimpleAllocatorDebugger debugger(std::shared_ptr<Allocator>(&GetDefaultAllocator(), [](Allocator*){}));
|
||||
REQUIRE(std::string(debugger.GetType()) == "SimpleAllocatorDebugger<DefaultAllocator>");
|
||||
|
||||
size_t size = 5;
|
||||
|
|
|
@ -12,13 +12,13 @@ static NapaInitializationGuard _guard;
|
|||
TEST_CASE("zone apis", "[api]") {
|
||||
|
||||
SECTION("create zone") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
REQUIRE(zone.GetId() == "zone1");
|
||||
}
|
||||
|
||||
SECTION("broadcast valid javascript") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto response = zone.BroadcastSync("var i = 3 + 5;");
|
||||
|
||||
|
@ -26,7 +26,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("broadcast illegal javascript") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto response = zone.BroadcastSync("var i = 3 +");
|
||||
|
||||
|
@ -34,7 +34,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("broadcast and execute javascript") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto responseCode = zone.BroadcastSync("function func(a, b) { return Number(a) + Number(b); }");
|
||||
REQUIRE(responseCode == NAPA_RESPONSE_SUCCESS);
|
||||
|
@ -49,12 +49,12 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("broadcast and execute javascript async") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
zone.Broadcast("function func(a, b) { return Number(a) + Number(b); }", [&promise, &zone](NapaResponseCode) {
|
||||
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") };
|
||||
|
@ -70,7 +70,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("broadcast and execute javascript without timing out") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise;
|
||||
auto future = promise.get_future();
|
||||
|
@ -78,11 +78,11 @@ TEST_CASE("zone apis", "[api]") {
|
|||
// 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](NapaResponseCode) {
|
||||
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.timeout = 100;
|
||||
request.options.timeout = 100;
|
||||
|
||||
zone.Execute(request, [&promise](napa::ExecuteResponse response) {
|
||||
promise.set_value(std::move(response));
|
||||
|
@ -95,7 +95,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("broadcast and execute javascript with exceeded timeout") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
std::promise<napa::ExecuteResponse> promise;
|
||||
auto future = promise.get_future();
|
||||
|
@ -103,10 +103,10 @@ TEST_CASE("zone apis", "[api]") {
|
|||
// Warmup to avoid loading napajs on first call
|
||||
zone.BroadcastSync("require('napajs');");
|
||||
|
||||
zone.Broadcast("function func() { while(true) {} }", [&promise, &zone](NapaResponseCode) {
|
||||
zone.Broadcast("function func() { while(true) {} }", [&promise, &zone](napa::ResponseCode) {
|
||||
napa::ExecuteRequest request;
|
||||
request.function = NAPA_STRING_REF("func");
|
||||
request.timeout = 200;
|
||||
request.options.timeout = 200;
|
||||
|
||||
zone.Execute(request, [&promise](napa::ExecuteResponse response) {
|
||||
promise.set_value(std::move(response));
|
||||
|
@ -119,7 +119,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("execute 2 javascript functions, one succeeds and one times out") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
// Warmup to avoid loading napajs on first call
|
||||
zone.BroadcastSync("require('napajs');");
|
||||
|
@ -138,11 +138,11 @@ TEST_CASE("zone apis", "[api]") {
|
|||
napa::ExecuteRequest request1;
|
||||
request1.function = NAPA_STRING_REF("f1");
|
||||
request1.arguments = { NAPA_STRING_REF("2"), NAPA_STRING_REF("3") };
|
||||
request1.timeout = 100;
|
||||
request1.options.timeout = 100;
|
||||
|
||||
napa::ExecuteRequest request2;
|
||||
request2.function = NAPA_STRING_REF("f2");
|
||||
request2.timeout = 100;
|
||||
request2.options.timeout = 100;
|
||||
|
||||
zone.Execute(request1, [&promise1](napa::ExecuteResponse response) {
|
||||
promise1.set_value(std::move(response));
|
||||
|
@ -162,7 +162,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("broadcast javascript requiring a module") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
auto responseCode = zone.BroadcastSync("var path = require('path'); function func() { return path.extname('test.txt'); }");
|
||||
REQUIRE(responseCode == NAPA_RESPONSE_SUCCESS);
|
||||
|
@ -176,7 +176,7 @@ TEST_CASE("zone apis", "[api]") {
|
|||
}
|
||||
|
||||
SECTION("execute function in a module") {
|
||||
napa::ZoneProxy zone("zone1");
|
||||
napa::Zone zone("zone1");
|
||||
|
||||
napa::ExecuteRequest request;
|
||||
request.module = NAPA_STRING_REF("path");
|
||||
|
|
|
@ -37,8 +37,8 @@ TEST_CASE("tasks", "[tasks]") {
|
|||
BroadcastTask("function __zone_execute__(module, func, args) { return this[func].apply(this, args); }").Execute();
|
||||
|
||||
SECTION("load valid javascript") {
|
||||
NapaResponseCode loadResponseCode;
|
||||
BroadcastTask("var i = 3 + 5;", "", [&loadResponseCode](NapaResponseCode code) {
|
||||
ResponseCode loadResponseCode;
|
||||
BroadcastTask("var i = 3 + 5;", "", [&loadResponseCode](ResponseCode code) {
|
||||
loadResponseCode = code;
|
||||
}).Execute();
|
||||
|
||||
|
@ -46,8 +46,8 @@ TEST_CASE("tasks", "[tasks]") {
|
|||
}
|
||||
|
||||
SECTION("load fails when javascript is malformed") {
|
||||
NapaResponseCode loadResponseCode;
|
||||
BroadcastTask("var j = 3 +", "", [&loadResponseCode](NapaResponseCode code) {
|
||||
ResponseCode loadResponseCode;
|
||||
BroadcastTask("var j = 3 +", "", [&loadResponseCode](ResponseCode code) {
|
||||
loadResponseCode = code;
|
||||
}).Execute();
|
||||
|
||||
|
@ -55,8 +55,8 @@ TEST_CASE("tasks", "[tasks]") {
|
|||
}
|
||||
|
||||
SECTION("load fails when javascript exception is thrown") {
|
||||
NapaResponseCode loadResponseCode;
|
||||
BroadcastTask("throw Error('error');", "", [&loadResponseCode](NapaResponseCode code) {
|
||||
ResponseCode loadResponseCode;
|
||||
BroadcastTask("throw Error('error');", "", [&loadResponseCode](ResponseCode code) {
|
||||
loadResponseCode = code;
|
||||
}).Execute();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче