diff --git a/examples/HelloWorld.js b/examples/HelloWorld.js index 00c1161..f4d112b 100644 --- a/examples/HelloWorld.js +++ b/examples/HelloWorld.js @@ -3,21 +3,26 @@ var uWS = uWS ? uWS : require('../dist/uws.js'); const port = 9001; -// nice milestone to pass autobahn on both ssl and non-ssl with an without compression - -const app = uWS.SSLApp({ +const app = uWS./*SSL*/App({ key_file_name: '/home/alexhultman/key.pem', cert_file_name: '/home/alexhultman/cert.pem', passphrase: '1234' }).get('/hello', (res, req) => { res.end('Hejdå!'); }).ws('/*', { + compression: 0, maxPayloadLength: 16 * 1024 * 1024, open: (ws, req) => { console.log(ws); }, message: (ws, message, isBinary) => { ws.send(message, isBinary); + }, + drain: (ws) => { + console.log('WebSocket drained'); + }, + close: (ws, code, message) => { + console.log('WebSocket closed'); } }).listen(port, (token) => { if (token) { diff --git a/src/addon.cpp b/src/addon.cpp index a88e55a..7bcaf50 100644 --- a/src/addon.cpp +++ b/src/addon.cpp @@ -158,10 +158,10 @@ Local getResInstance() { return Local::New(isolate, resTemplate[std::is_same::value])->Clone(); } +/* The only thing this req needs is getHeader and similar, getParameter, getUrl and so on */ Persistent reqTemplate; void req_getHeader(const FunctionCallbackInfo &args) { - // get string NativeString data(args.GetIsolate(), args[0]); char *buf = data.getData(); int length = data.getLength(); @@ -175,13 +175,21 @@ template void uWS_App_ws(const FunctionCallbackInfo &args) { APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0); + // pattern NativeString nativeString(args.GetIsolate(), args[0]); + // todo: small leak here, should be unique_ptrs moved in Persistent *openPf = new Persistent(); Persistent *messagePf = new Persistent(); + Persistent *drainPf = new Persistent(); + Persistent *closePf = new Persistent(); int maxPayloadLength = 0; + /* For now, let's have 0, 1, 2 be from nothing to shared, to dedicated */ + int compression = 0; + uWS::CompressOptions mappedCompression = uWS::CompressOptions::DISABLED; + struct PerSocketData { Persistent *socketPf; }; @@ -193,52 +201,97 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { /* maxPayloadLength */ maxPayloadLength = behaviorObject->Get(String::NewFromUtf8(isolate, "maxPayloadLength"))->Int32Value(); + /* Compression */ + compression = behaviorObject->Get(String::NewFromUtf8(isolate, "compression"))->Int32Value(); + /* Open */ openPf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "open")))); /* Message */ messagePf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "message")))); + /* Drain */ + drainPf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "drain")))); + /* Close */ + closePf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "close")))); + } + + /* Map compression options from integer values */ + if (compression == 1) { + mappedCompression = uWS::CompressOptions::SHARED_COMPRESSOR; + } else if (compression == 2) { + mappedCompression = uWS::CompressOptions::DEDICATED_COMPRESSOR; } app->template ws(std::string(nativeString.getData(), nativeString.getLength()), { - - /*.compression = uWS::SHARED_COMPRESSOR,*/ + /* idleTimeout */ + .compression = mappedCompression, .maxPayloadLength = maxPayloadLength, + /* Handlers */ .open = [openPf](auto *ws, auto *req) { - HandleScope hs(isolate); + HandleScope hs(isolate); - /* Create a new websocket object */ - Local wsObject = getWsInstance(); - wsObject->SetAlignedPointerInInternalField(0, ws); + /* Create a new websocket object */ + Local wsObject = getWsInstance(); + wsObject->SetAlignedPointerInInternalField(0, ws); - /* Attach a new V8 object with pointer to us, to us */ - PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); - perSocketData->socketPf = new Persistent; - perSocketData->socketPf->Reset(isolate, wsObject); + /* Attach a new V8 object with pointer to us, to us */ + PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); + perSocketData->socketPf = new Persistent; + perSocketData->socketPf->Reset(isolate, wsObject); - Local argv[] = {wsObject}; - Local::New(isolate, *openPf)->Call(isolate->GetCurrentContext()->Global(), 1, argv); + Local argv[] = {wsObject}; + Local::New(isolate, *openPf)->Call(isolate->GetCurrentContext()->Global(), 1, argv); }, .message = [messagePf](auto *ws, std::string_view message, uWS::OpCode opCode) { HandleScope hs(isolate); + Local messageArrayBuffer = ArrayBuffer::New(isolate, (void *) message.data(), message.length()); + PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); Local argv[3] = {Local::New(isolate, *(perSocketData->socketPf)), - ArrayBuffer::New(isolate, (void *) message.data(), message.length()), + /*ArrayBuffer::New(isolate, (void *) message.data(), message.length())*/ messageArrayBuffer, Boolean::New(isolate, opCode == uWS::OpCode::BINARY) }; Local::New(isolate, *messagePf)->Call(isolate->GetCurrentContext()->Global(), 3, argv); - }/* - .drain = []() {}, - .ping = []() {}, - .pong = []() {}, - .close = []() {}*/ + + /* Important: we clear the ArrayBuffer to make sure it is not invalidly used after return */ + messageArrayBuffer->Neuter(); + }, + .drain = [drainPf](auto *ws) { + HandleScope hs(isolate); + + PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); + Local argv[1] = {Local::New(isolate, *(perSocketData->socketPf)) + }; + Local::New(isolate, *drainPf)->Call(isolate->GetCurrentContext()->Global(), 1, argv); + }, + .ping = [](auto *ws) { + + }, + .pong = [](auto *ws) { + + }, + .close = [closePf](auto *ws, int code, std::string_view message) { + HandleScope hs(isolate); + + Local messageArrayBuffer = ArrayBuffer::New(isolate, (void *) message.data(), message.length()); + + PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); + Local argv[3] = {Local::New(isolate, *(perSocketData->socketPf)), + Integer::New(isolate, code), + messageArrayBuffer + }; + Local::New(isolate, *closePf)->Call(isolate->GetCurrentContext()->Global(), 3, argv); + + /* Again, here we clear the buffer to avoid strange bugs */ + messageArrayBuffer->Neuter(); + } }); - // Return this + /* Return this */ args.GetReturnValue().Set(args.Holder()); } -// todo: all other methods +// todo: all other methods, in particular post! template void uWS_App_get(const FunctionCallbackInfo &args) { APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0); @@ -330,6 +383,9 @@ void uWS_App(const FunctionCallbackInfo &args) { appTemplate->InstanceTemplate()->SetInternalFieldCount(1); + + /* Most used functions will be get, post, ws, listen */ + // Get and all the Http methods appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "get"), FunctionTemplate::New(isolate, uWS_App_get));