From f16350e774467d58bb31df42f626738fbaed0092 Mon Sep 17 00:00:00 2001 From: TekuConcept Date: Wed, 8 May 2019 17:45:05 -0600 Subject: [PATCH] Add Native Directive Example --- Examples/javascript/native/Makefile | 3 + Examples/javascript/native/binding.gyp.in | 9 +++ Examples/javascript/native/example.i | 92 +++++++++++++++++++++++ Examples/javascript/native/example.js | 1 + Examples/javascript/native/index.html | 31 ++++++++ Examples/javascript/native/runme.js | 5 ++ 6 files changed, 141 insertions(+) create mode 100644 Examples/javascript/native/Makefile create mode 100644 Examples/javascript/native/binding.gyp.in create mode 100644 Examples/javascript/native/example.i create mode 100644 Examples/javascript/native/example.js create mode 100644 Examples/javascript/native/index.html create mode 100644 Examples/javascript/native/runme.js diff --git a/Examples/javascript/native/Makefile b/Examples/javascript/native/Makefile new file mode 100644 index 000000000..0402f8d09 --- /dev/null +++ b/Examples/javascript/native/Makefile @@ -0,0 +1,3 @@ +SRCS = + +include $(SRCDIR)../example.mk diff --git a/Examples/javascript/native/binding.gyp.in b/Examples/javascript/native/binding.gyp.in new file mode 100644 index 000000000..59779aef4 --- /dev/null +++ b/Examples/javascript/native/binding.gyp.in @@ -0,0 +1,9 @@ +{ + "targets": [ + { + "target_name": "example", + "sources": [ "example_wrap.cxx" ], + "include_dirs": ["$srcdir"] + } + ] +} diff --git a/Examples/javascript/native/example.i b/Examples/javascript/native/example.i new file mode 100644 index 000000000..73582462e --- /dev/null +++ b/Examples/javascript/native/example.i @@ -0,0 +1,92 @@ +/* File : example.i */ +%module example + + +%wrapper +%{ +#include +#include + +#if (V8_MAJOR_VERSION-0) < 4 && (SWIG_V8_VERSION < 0x031903) +# define V8_RETURN(val) return scope.Close(val) +#else +# define V8_RETURN(val) args.GetReturnValue().Set(val); return +#endif +#if (V8_MAJOR_VERSION-0) < 4 && (SWIG_V8_VERSION < 0x032318) +# define V8_UNDEFINED() v8::Undefined() +#else +# define V8_UNDEFINED() v8::Undefined(v8::Isolate::GetCurrent()) +#endif + + +// 'unused' attribute only necessary for GNUC < v3.4 +static /* __attribute__ ((__unused__)) */ V8ErrorHandler V8_ErrorHandler; + + +typedef struct worker_packet { + // -- basic -- + uv_work_t request; + v8::Persistent callback; + // -- persistent variables -- + std::string result; + // -- async operation -- + void (*execute)(std::string&); +} worker_packet; + + +// async process - parallel with node thread +static void work_async(uv_work_t* request) { + worker_packet* packet = static_cast(request->data); + packet->execute(packet->result); + // add a delay for dramatic effect - not necessary +} + + +// send async result back to node's thread +static void work_complete(uv_work_t* request, int status) { + v8::Isolate* iso = v8::Isolate::GetCurrent(); + v8::HandleScope scope(iso); + worker_packet* packet = static_cast(request->data); + const int argc = 1; + v8::Handle argv[] = { + v8::String::NewFromUtf8(iso, packet->result.c_str()) + }; + v8::Local::New(iso, packet->callback)->Call + (iso->GetCurrentContext()->Global(), argc, argv); + packet->callback.Reset(); + delete work; +} + + +static void entry(const v8::FunctionCallbackInfo& args) { + v8::Isolate* iso = v8::Isolate::GetCurrent(); + v8::Local value = args[0]; + if (!value->IsFunction()) { + V8_ErrorHandler.error((-1), "Invalid parameter type."); + return; + } + worker_packet* packet = new worker_packet(); + packet->request.data = packet; + packet->execute = [](std::string& res) { res = "My delayed message."; }; + v8::Local callback = v8::Local::Cast(value); + packet->callback.Reset(iso, callback); + uv_queue_work(uv_default_loop(), &packet->request, + work_async, work_complete); + args.GetReturnValue().Set(Undefined(iso)); +} + + +void JavaScript_exampleV8_callback_function(const v8::Arguments& args) { + v8::HandleScope scope + if (args.Length() != 1) { + V8_ErrorHandler.error((-1), "Illegal number of arguments."); + V8_RETURN(V8_UNDEFINED()); + } + entry(args); + v8::Handle jsresult = V8_UNDEFINED(); + V8_RETURN(jsresult); +} +%} + + +%native(num_to_string) void JavaScript_exampleV8_callback_function(); diff --git a/Examples/javascript/native/example.js b/Examples/javascript/native/example.js new file mode 100644 index 000000000..2e7f83a06 --- /dev/null +++ b/Examples/javascript/native/example.js @@ -0,0 +1 @@ +module.exports = require("build/Release/example"); diff --git a/Examples/javascript/native/index.html b/Examples/javascript/native/index.html new file mode 100644 index 000000000..7c7d6b071 --- /dev/null +++ b/Examples/javascript/native/index.html @@ -0,0 +1,31 @@ + + +SWIG:Examples:javascript:native + + + + + +SWIG/Examples/javascript/native/ +
+ +

Manually wrapped callback function in JavaScript

+ +

+This example demonstrates how to manually add callback feature support to a SWIG module. +

+ +
    +
  • example.i. Interface file containing the API function and async behind-the-scenes functions. +
  • runme.js. Sample JavaScript program showing the API function being called with a callback function parameter. +
+ +

Notes

+ +The V8 code queues the callback request for processing using the UV interface. An async function callback is invoked when the system is ready to process the next request. When the async function finishes, a completion function callback is invoked to finalize the request. Here the callback function parameter is invoked. +

+UV request queueing is only necessary for operations that would take a really long or otherwise unpredictable amount of time (async operations). A callback parameter could also be invoked immediately within the API function. + +
+ + diff --git a/Examples/javascript/native/runme.js b/Examples/javascript/native/runme.js new file mode 100644 index 000000000..6577bb1fb --- /dev/null +++ b/Examples/javascript/native/runme.js @@ -0,0 +1,5 @@ +var example = require("example"); + +function callback(msg) { console.log(msg); } + +example.num_to_string(callback);