From 787bd7d9b1d68538b32a101e6458392ff8b953eb Mon Sep 17 00:00:00 2001 From: Bent Cardan Date: Mon, 18 Feb 2019 16:24:57 -0800 Subject: [PATCH] open nng socket types, pass them to js as node buffers --- COPYING | 4 + binding.cc | 239 ++++++++++++++++++++++--------------------- compile | 2 +- package.json | 2 +- readme.markdown | 38 +++++++ ref.h | 66 ++++++++++++ test/index.js | 2 +- test/nng.js | 11 -- test/open.js | 34 ++++++ test/readme.markdown | 22 ++++ 10 files changed, 287 insertions(+), 133 deletions(-) create mode 100644 ref.h delete mode 100644 test/nng.js create mode 100644 test/open.js create mode 100644 test/readme.markdown diff --git a/COPYING b/COPYING index 02413e6..dbd38c7 100644 --- a/COPYING +++ b/COPYING @@ -1,3 +1,7 @@ +Copyright (c) 2019 Bent Cardan +Copyright (c) 2019 Garrett D'Amore +Copyright (c) 2018 Staysail Systems, Inc. +Copyright (c) 2018 Capitar IT Group BV Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/binding.cc b/binding.cc index 919809f..c619012 100644 --- a/binding.cc +++ b/binding.cc @@ -1,36 +1,40 @@ +/* + + Copyright (c) 2019 Bent Cardan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + #include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include "timer.h" #include "nan.h" - -#define CLIENT "client" -#define SERVER "server" -#define DATECMD 1 - -#define PUT64(ptr, u) \ - do { \ - (ptr)[0] = (uint8_t)(((uint64_t)(u)) >> 56); \ - (ptr)[1] = (uint8_t)(((uint64_t)(u)) >> 48); \ - (ptr)[2] = (uint8_t)(((uint64_t)(u)) >> 40); \ - (ptr)[3] = (uint8_t)(((uint64_t)(u)) >> 32); \ - (ptr)[4] = (uint8_t)(((uint64_t)(u)) >> 24); \ - (ptr)[5] = (uint8_t)(((uint64_t)(u)) >> 16); \ - (ptr)[6] = (uint8_t)(((uint64_t)(u)) >> 8); \ - (ptr)[7] = (uint8_t)((uint64_t)(u)); \ - } while (0) - -#define GET64(ptr, v) \ - v = (((uint64_t)((uint8_t)(ptr)[0])) << 56) + \ - (((uint64_t)((uint8_t)(ptr)[1])) << 48) + \ - (((uint64_t)((uint8_t)(ptr)[2])) << 40) + \ - (((uint64_t)((uint8_t)(ptr)[3])) << 32) + \ - (((uint64_t)((uint8_t)(ptr)[4])) << 24) + \ - (((uint64_t)((uint8_t)(ptr)[5])) << 16) + \ - (((uint64_t)((uint8_t)(ptr)[6])) << 8) + \ - (((uint64_t)(uint8_t)(ptr)[7])) - +#include "ref.h" using v8::FunctionTemplate; using v8::Function; @@ -40,6 +44,7 @@ using v8::String; using v8::Object; using v8::Value; using v8::Local; + using Nan::HandleScope; using Nan::MaybeLocal; using Nan::NewBuffer; @@ -49,107 +54,92 @@ using Nan::Set; using Nan::New; using Nan::To; -void -fatal(const char *func, int rv) -{ - fprintf(stderr, "%s: %s\n", func, nng_strerror(rv)); - exit(1); +//NAN_METHOD(aiosock1){ +// const char *addr = "inproc://aio"; +// printf("aio test\n"); +// nng_socket s1; +// nng_socket s2; +// nng_aio * txaio; +// nng_aio * rxaio; +// int txdone = 0; +// int rxdone = 0; +// nng_msg * m; +// nng_pair1_open(&s1); +// nng_pair1_open(&s2); +// nng_listen(s1, addr, NULL, 0); +// nng_aio *saio; +// nng_aio_alloc(&saio, sleepdone, &end)); +// return; +//} + +NAN_METHOD(bus_open) { + nng_socket s; + nng_bus0_open(&s); //nng_bus0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); } -void -showdate(time_t now) -{ - struct tm *info = localtime(&now); - printf("%s", asctime(info)); +NAN_METHOD(pair0_open) { + nng_socket s; + nng_pair0_open(&s); //nng_pair0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); } -int -server(const char *url) -{ - nng_socket sock; - int rv; - - if ((rv = nng_rep0_open(&sock)) != 0) { - fatal("nng_rep0_open", rv); - } - if ((rv = nng_listen(sock, url, NULL, 0)) != 0) { - fatal("nng_listen", rv); - } - for (;;) { - char * buf = NULL; - size_t sz; - uint64_t val; - if ((rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC)) != 0) { - fatal("nng_recv", rv); - } - if ((sz == sizeof(uint64_t)) && - ((GET64(buf, val)) == DATECMD)) { - time_t now; - printf("SERVER: RECEIVED DATE REQUEST\n"); - now = time(&now); - printf("SERVER: SENDING DATE: "); - showdate(now); - - // Reuse the buffer. We know it is big enough. - PUT64(buf, (uint64_t) now); - rv = nng_send(sock, buf, sz, NNG_FLAG_ALLOC); - if (rv != 0) { - fatal("nng_send", rv); - } - continue; - } - // Unrecognized command, so toss the buffer. - nng_free(buf, sz); - } +//NNG_OPT_PAIR1_POLY +//NNG_OPT_MAXTTL +NAN_METHOD(pair1_open) { + nng_socket s; + nng_pair1_open(&s); //nng_pair1_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); } -int -client(const char *url) -{ - nng_socket sock; - int rv; - size_t sz; - char * buf = NULL; - uint8_t cmd[sizeof(uint64_t)]; - - PUT64(cmd, DATECMD); - - if ((rv = nng_req0_open(&sock)) != 0) { - fatal("nng_socket", rv); - } - if ((rv = nng_dial(sock, url, NULL, 0)) != 0) { - fatal("nng_dial", rv); - } - printf("CLIENT: SENDING DATE REQUEST\n"); - if ((rv = nng_send(sock, cmd, sizeof(cmd), 0)) != 0) { - fatal("nng_send", rv); - } - if ((rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC)) != 0) { - fatal("nng_recv", rv); - } - - if (sz == sizeof(uint64_t)) { - uint64_t now; - GET64(buf, now); - printf("CLIENT: RECEIVED DATE: "); - showdate((time_t) now); - } else { - printf("CLIENT: GOT WRONG SIZE!\n"); - } - - // This assumes that buf is ASCIIZ (zero terminated). - nng_free(buf, sz); - nng_close(sock); - return (0); + +NAN_METHOD(pub_open) { + nng_socket s; + nng_pub0_open(&s); //nng_pub0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); +} + +NAN_METHOD(pull_open) { + nng_socket s; + nng_pull0_open(&s); //nng_pull0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); +} + +NAN_METHOD(push_open) { + nng_socket s; + nng_push0_open(&s); //nng_push0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); } -NAN_METHOD(client){ - client("tcp://127.0.0.1:5555"); +NAN_METHOD(rep_open) { + nng_socket s; + nng_rep0_open(&s); //nng_rep0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); } -NAN_METHOD(server){ - server("tcp://127.0.0.1:5555"); +NAN_METHOD(req_open) { + nng_socket s; + nng_req0_open(&s); //nng_req0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); +} + +NAN_METHOD(respondent_open) { + nng_socket s; + nng_respondent0_open(&s); //nng_respondent0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); +} + +NAN_METHOD(sub_open) { + nng_socket s; + nng_sub0_open(&s); //nng_sub0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); +} + +NAN_METHOD(surveyor_open) { + nng_socket s; + nng_surveyor0_open(&s); // nng_surveyor0_open_raw + info.GetReturnValue().Set(WrapPointer(&s, sizeof(nng_socket))); } NAN_METHOD(test){ @@ -159,15 +149,26 @@ NAN_METHOD(test){ return; } + #define EXPORT_METHOD(C, S) \ Set(C, New(#S).ToLocalChecked(), \ Nan::GetFunction(New(S)).ToLocalChecked()); NAN_MODULE_INIT(Init) { HandleScope scope; + EXPORT_METHOD(target, bus_open); + EXPORT_METHOD(target, pair0_open); + EXPORT_METHOD(target, pair1_open); + EXPORT_METHOD(target, pub_open); + EXPORT_METHOD(target, pull_open); + EXPORT_METHOD(target, push_open); + EXPORT_METHOD(target, rep_open); + EXPORT_METHOD(target, req_open); + EXPORT_METHOD(target, respondent_open); + EXPORT_METHOD(target, sub_open); + EXPORT_METHOD(target, surveyor_open); + /* debug */ EXPORT_METHOD(target, test); - EXPORT_METHOD(target, client); - EXPORT_METHOD(target, server); } NODE_MODULE(nodenng, Init) diff --git a/compile b/compile index 97714ed..9ccd661 100755 --- a/compile +++ b/compile @@ -3,6 +3,6 @@ if [ ! -d nng ]; then rm -rf deps nng build && mkdir deps git clone --depth 1 https://github.com/nanomsg/nng && cd nng mkdir build && cd build - cmake -DCMAKE_INSTALL_MESSAGE=NEVER -DCMAKE_INSTALL_PREFIX=$(pwd)/../../deps .. -DNNG_TESTS=OFF -DNNG_TOOLS=OFF -DNNG_ENABLE_NNGCAT=OFF -DNNG_ENABLE_COVERAGE=OFF + cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_MESSAGE=NEVER -DCMAKE_INSTALL_PREFIX=$(pwd)/../../deps .. -DNNG_TESTS=OFF -DNNG_TOOLS=OFF -DNNG_ENABLE_NNGCAT=OFF -DNNG_ENABLE_COVERAGE=OFF make MACOSX_DEPLOYMENT_TARGET=10.7 all install fi diff --git a/package.json b/package.json index 13a542c..0286d89 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "test": "node test | tap-spec", "install": "./compile && node-gyp rebuild" }, - "homepage": "http://github.com/reqhsark/nodenng", + "homepage": "http://github.com/reqshark/nodenng", "keywords": [ "nng", "nodenng", diff --git a/readme.markdown b/readme.markdown index c9bc570..1ef65c3 100644 --- a/readme.markdown +++ b/readme.markdown @@ -1,3 +1,41 @@ # nodenng bindings to nng (nanomsg next generation) + +# install +```bash +npm i nodenng +``` + +# use +```js +const { + bus_open, + pair0_open, + pair1_open, + pub_open, + pull_open, + push_open, + rep_open, + req_open, + respondent_open, + sub_open, + surveyor_open, +} = require('nodenng') + + +const pub = pub_open() +const sub = sub_open() + +// more nng api will be made available to javascript in the coming days +// please help add stuff or send PRs if you'd like faster access from node.js +``` + +# test +see [`test` directory](test) + +## license + +MIT. © 2019 Bent Cardan + +*currently tested on linux and osx but very shortly full windows support* diff --git a/ref.h b/ref.h new file mode 100644 index 0000000..c27ee13 --- /dev/null +++ b/ref.h @@ -0,0 +1,66 @@ +// Source: @tootallnate https://gist.github.com/TooTallNate/3987725 +// Maintain an up-to-date copy of this file when necessary. + +#pragma once + +#include + +/* + * Called when the "pointer" is garbage collected. + */ + +// UNUSED: however, inline functions don't generate code. +inline static void wrap_pointer_cb(char *data, void *hint) { + // fprintf(stderr, "wrap_pointer_cb\n"); +} + +/* + * Wraps "ptr" into a new SlowBuffer instance with size "length". + */ + +inline static v8::Local WrapPointer(void *ptr, size_t length) { + return Nan::NewBuffer(static_cast(ptr), length, wrap_pointer_cb, 0) + .ToLocalChecked(); +} + +/* + * Wraps "ptr" into a new SlowBuffer instance with length 0. + */ + +inline static v8::Local WrapPointer(void *ptr) { + return WrapPointer(ptr, 0); +} + +/* + * Unwraps Buffer instance "buffer" to a C `char *` with the offset specified. + */ + +inline static char *UnwrapPointer(v8::Local buffer, int64_t offset) { + if (node::Buffer::HasInstance(buffer)) { + return node::Buffer::Data(buffer.As()) + offset; + } else { + return 0; + } +} + +/* + * Unwraps Buffer instance "buffer" to a C `char *` (no offset applied). + */ + +inline static char *UnwrapPointer(v8::Local buffer) { + if (node::Buffer::HasInstance(buffer)) { + return node::Buffer::Data(buffer.As()); + } else { + return 0; + } +} + +/** + * Templated version of UnwrapPointer that does a reinterpret_cast() on the + * pointer before returning it. + */ + +template +inline static Type UnwrapPointer(v8::Local buffer) { + return reinterpret_cast(UnwrapPointer(buffer)); +} diff --git a/test/index.js b/test/index.js index 9bb571d..9d51dfa 100644 --- a/test/index.js +++ b/test/index.js @@ -1,6 +1,6 @@ const bar = '====================' require ('tape')(`${bar} nng testsuite summary ${bar}`, function tests (t){ - test('nng') + test('open') function test(name){ return t.test(`${bar.slice(7)} ${name} ${bar.slice(7)}`, diff --git a/test/nng.js b/test/nng.js deleted file mode 100644 index 2487e3f..0000000 --- a/test/nng.js +++ /dev/null @@ -1,11 +0,0 @@ -const nng = require('..') - -module.exports = nngt - -function nngt(t){ - t.plan(1) - - nng.test() - - t.ok ( 'nngjs', 'or nodenng') -} diff --git a/test/open.js b/test/open.js new file mode 100644 index 0000000..72b2e8d --- /dev/null +++ b/test/open.js @@ -0,0 +1,34 @@ +const nng = require('..') + +module.exports = open + +function open(t){ + t.plan(11) + + const { + bus_open, + pair0_open, + pair1_open, + pub_open, + pull_open, + push_open, + rep_open, + req_open, + respondent_open, + sub_open, + surveyor_open, + } = nng + + t.ok ( Buffer.isBuffer(bus_open()), 'open bus sock is a node buffer') + t.ok ( Buffer.isBuffer(pair0_open()), 'open pair0 sock is a node buffer') + t.ok ( Buffer.isBuffer(pair1_open()), 'open pair1 sock is a node buffer') + t.ok ( Buffer.isBuffer(pub_open()), 'open pub sock is a node buffer') + t.ok ( Buffer.isBuffer(pull_open()), 'open pull sock is a node buffer') + t.ok ( Buffer.isBuffer(push_open()), 'open push sock is a node buffer') + t.ok ( Buffer.isBuffer(rep_open()), 'open rep sock is a node buffer') + t.ok ( Buffer.isBuffer(req_open()), 'open req sock is a node buffer') + t.ok ( Buffer.isBuffer(respondent_open()), 'open respondent sock is a node buffer') + t.ok ( Buffer.isBuffer(sub_open()), 'open sub sock is a node buffer') + t.ok ( Buffer.isBuffer(surveyor_open()), 'open surveyor sock is a node buffer') + +} diff --git a/test/readme.markdown b/test/readme.markdown new file mode 100644 index 0000000..9bb84d1 --- /dev/null +++ b/test/readme.markdown @@ -0,0 +1,22 @@ +# build and test [![Build Status](https://travis-ci.org/reqshark/mill.svg?branch=master)](https://travis-ci.org/reqshark/mill) + +`test/index.js` file runs the tests by iterating contents top-down within this +directory. + +process is launched from project root by `node test` piped to `tap-spec`. +```js +$ node test | tap-spec +``` + +there are also some convenience operations via make: +```bash +$ git clone git@github.com:reqshark/nodenng.git && cd nodenng +$ make clean && make && make check +``` + +these are respectively: +```bash +$ rm -rf package-* node_modules build nng deps # make clean +$ npm i # make +$ npm t # make check +```