From 67fdec20726e48ba3a934cb25bb30d47ec4a4f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20De=20La=20Pe=C3=B1a=20Smirnov?= Date: Wed, 29 Nov 2017 11:44:34 +0300 Subject: Initial commit, version 0.5.3 --- node_modules/uws/src/addon.h | 464 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 node_modules/uws/src/addon.h (limited to 'node_modules/uws/src/addon.h') diff --git a/node_modules/uws/src/addon.h b/node_modules/uws/src/addon.h new file mode 100644 index 0000000..93a41e5 --- /dev/null +++ b/node_modules/uws/src/addon.h @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace v8; + +uWS::Hub hub(0, true); +uv_check_t check; +Persistent noop; + +void registerCheck(Isolate *isolate) { + uv_check_init((uv_loop_t *) hub.getLoop(), &check); + check.data = isolate; + uv_check_start(&check, [](uv_check_t *check) { + Isolate *isolate = (Isolate *) check->data; + HandleScope hs(isolate); + node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, noop), 0, nullptr); + }); + uv_unref((uv_handle_t *) &check); +} + +class NativeString { + char *data; + size_t length; + char utf8ValueMemory[sizeof(String::Utf8Value)]; + String::Utf8Value *utf8Value = nullptr; +public: + NativeString(const Local &value) { + if (value->IsUndefined()) { + data = nullptr; + length = 0; + } else if (value->IsString()) { + utf8Value = new (utf8ValueMemory) String::Utf8Value(value); + data = (**utf8Value); + length = utf8Value->length(); + } else if (node::Buffer::HasInstance(value)) { + data = node::Buffer::Data(value); + length = node::Buffer::Length(value); + } else if (value->IsTypedArray()) { + Local arrayBufferView = Local::Cast(value); + ArrayBuffer::Contents contents = arrayBufferView->Buffer()->GetContents(); + length = contents.ByteLength(); + data = (char *) contents.Data(); + } else if (value->IsArrayBuffer()) { + Local arrayBuffer = Local::Cast(value); + ArrayBuffer::Contents contents = arrayBuffer->GetContents(); + length = contents.ByteLength(); + data = (char *) contents.Data(); + } else { + static char empty[] = ""; + data = empty; + length = 0; + } + } + + char *getData() {return data;} + size_t getLength() {return length;} + ~NativeString() { + if (utf8Value) { + utf8Value->~Utf8Value(); + } + } +}; + +struct GroupData { + Persistent connectionHandler, messageHandler, + disconnectionHandler, pingHandler, + pongHandler, errorHandler, httpRequestHandler, + httpUpgradeHandler, httpCancelledRequestCallback; + int size = 0; +}; + +template +void createGroup(const FunctionCallbackInfo &args) { + uWS::Group *group = hub.createGroup(args[0]->IntegerValue(), args[1]->IntegerValue()); + group->setUserData(new GroupData); + args.GetReturnValue().Set(External::New(args.GetIsolate(), group)); +} + +template +void deleteGroup(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + delete (GroupData *) group->getUserData(); + delete group; +} + +template +inline Local wrapSocket(uWS::WebSocket *webSocket, Isolate *isolate) { + return External::New(isolate, webSocket); +} + +template +inline uWS::WebSocket *unwrapSocket(Local external) { + return (uWS::WebSocket *) external->Value(); +} + +inline Local wrapMessage(const char *message, size_t length, uWS::OpCode opCode, Isolate *isolate) { + return opCode == uWS::OpCode::BINARY ? (Local) ArrayBuffer::New(isolate, (char *) message, length) : (Local) String::NewFromUtf8(isolate, message, String::kNormalString, length); +} + +template +inline Local getDataV8(uWS::WebSocket *webSocket, Isolate *isolate) { + return webSocket->getUserData() ? Local::New(isolate, *(Persistent *) webSocket->getUserData()) : Local::Cast(Undefined(isolate)); +} + +template +void getUserData(const FunctionCallbackInfo &args) { + args.GetReturnValue().Set(getDataV8(unwrapSocket(args[0].As()), args.GetIsolate())); +} + +template +void clearUserData(const FunctionCallbackInfo &args) { + uWS::WebSocket *webSocket = unwrapSocket(args[0].As()); + ((Persistent *) webSocket->getUserData())->Reset(); + delete (Persistent *) webSocket->getUserData(); +} + +template +void setUserData(const FunctionCallbackInfo &args) { + uWS::WebSocket *webSocket = unwrapSocket(args[0].As()); + if (webSocket->getUserData()) { + ((Persistent *) webSocket->getUserData())->Reset(args.GetIsolate(), args[1]); + } else { + webSocket->setUserData(new Persistent(args.GetIsolate(), args[1])); + } +} + +template +void getAddress(const FunctionCallbackInfo &args) +{ + typename uWS::WebSocket::Address address = unwrapSocket(args[0].As())->getAddress(); + Local array = Array::New(args.GetIsolate(), 3); + array->Set(0, Integer::New(args.GetIsolate(), address.port)); + array->Set(1, String::NewFromUtf8(args.GetIsolate(), address.address)); + array->Set(2, String::NewFromUtf8(args.GetIsolate(), address.family)); + args.GetReturnValue().Set(array); +} + +uv_handle_t *getTcpHandle(void *handleWrap) { + volatile char *memory = (volatile char *) handleWrap; + for (volatile uv_handle_t *tcpHandle = (volatile uv_handle_t *) memory; tcpHandle->type != UV_TCP + || tcpHandle->data != handleWrap || tcpHandle->loop != uv_default_loop(); tcpHandle = (volatile uv_handle_t *) memory) { + memory++; + } + return (uv_handle_t *) memory; +} + +struct SendCallbackData { + Persistent jsCallback; + Isolate *isolate; +}; + +template +void sendCallback(uWS::WebSocket *webSocket, void *data, bool cancelled, void *reserved) +{ + SendCallbackData *sc = (SendCallbackData *) data; + if (!cancelled) { + HandleScope hs(sc->isolate); + node::MakeCallback(sc->isolate, sc->isolate->GetCurrentContext()->Global(), Local::New(sc->isolate, sc->jsCallback), 0, nullptr); + } + sc->jsCallback.Reset(); + delete sc; +} + +template +void send(const FunctionCallbackInfo &args) +{ + uWS::OpCode opCode = (uWS::OpCode) args[2]->IntegerValue(); + NativeString nativeString(args[1]); + + SendCallbackData *sc = nullptr; + void (*callback)(uWS::WebSocket *, void *, bool, void *) = nullptr; + + if (args[3]->IsFunction()) { + callback = sendCallback; + sc = new SendCallbackData; + sc->jsCallback.Reset(args.GetIsolate(), Local::Cast(args[3])); + sc->isolate = args.GetIsolate(); + } + + unwrapSocket(args[0].As())->send(nativeString.getData(), + nativeString.getLength(), opCode, callback, sc); +} + +void connect(const FunctionCallbackInfo &args) { + uWS::Group *clientGroup = (uWS::Group *) args[0].As()->Value(); + NativeString uri(args[1]); + hub.connect(std::string(uri.getData(), uri.getLength()), new Persistent(args.GetIsolate(), args[2]), {}, 5000, clientGroup); +} + +struct Ticket { + uv_os_sock_t fd; + SSL *ssl; +}; + +void upgrade(const FunctionCallbackInfo &args) { + uWS::Group *serverGroup = (uWS::Group *) args[0].As()->Value(); + Ticket *ticket = (Ticket *) args[1].As()->Value(); + NativeString secKey(args[2]); + NativeString extensions(args[3]); + NativeString subprotocol(args[4]); + + // todo: move this check into core! + if (ticket->fd != INVALID_SOCKET) { + hub.upgrade(ticket->fd, secKey.getData(), ticket->ssl, extensions.getData(), extensions.getLength(), subprotocol.getData(), subprotocol.getLength(), serverGroup); + } else { + if (ticket->ssl) { + SSL_free(ticket->ssl); + } + } + delete ticket; +} + +void transfer(const FunctionCallbackInfo &args) { + // (_handle.fd OR _handle), SSL + uv_handle_t *handle = nullptr; + Ticket *ticket = new Ticket; + if (args[0]->IsObject()) { + uv_fileno((handle = getTcpHandle(args[0]->ToObject()->GetAlignedPointerFromInternalField(0))), (uv_os_fd_t *) &ticket->fd); + } else { + ticket->fd = args[0]->IntegerValue(); + } + + ticket->fd = dup(ticket->fd); + ticket->ssl = nullptr; + if (args[1]->IsExternal()) { + ticket->ssl = (SSL *) args[1].As()->Value(); + SSL_up_ref(ticket->ssl); + } + + // uv_close calls shutdown if not set on Windows + if (handle) { + // UV_HANDLE_SHARED_TCP_SOCKET + handle->flags |= 0x40000000; + } + + args.GetReturnValue().Set(External::New(args.GetIsolate(), ticket)); +} + +template +void onConnection(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + + Isolate *isolate = args.GetIsolate(); + Persistent *connectionCallback = &groupData->connectionHandler; + connectionCallback->Reset(isolate, Local::Cast(args[1])); + group->onConnection([isolate, connectionCallback, groupData](uWS::WebSocket *webSocket, uWS::HttpRequest req) { + groupData->size++; + HandleScope hs(isolate); + Local argv[] = {wrapSocket(webSocket, isolate)}; + node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *connectionCallback), 1, argv); + }); +} + +template +void onMessage(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + + Isolate *isolate = args.GetIsolate(); + Persistent *messageCallback = &groupData->messageHandler; + messageCallback->Reset(isolate, Local::Cast(args[1])); + group->onMessage([isolate, messageCallback](uWS::WebSocket *webSocket, const char *message, size_t length, uWS::OpCode opCode) { + HandleScope hs(isolate); + Local argv[] = {wrapMessage(message, length, opCode, isolate), + getDataV8(webSocket, isolate)}; + Local::New(isolate, *messageCallback)->Call(isolate->GetCurrentContext()->Global(), 2, argv); + }); +} + +template +void onPing(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + + Isolate *isolate = args.GetIsolate(); + Persistent *pingCallback = &groupData->pingHandler; + pingCallback->Reset(isolate, Local::Cast(args[1])); + group->onPing([isolate, pingCallback](uWS::WebSocket *webSocket, const char *message, size_t length) { + HandleScope hs(isolate); + Local argv[] = {wrapMessage(message, length, uWS::OpCode::PING, isolate), + getDataV8(webSocket, isolate)}; + node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *pingCallback), 2, argv); + }); +} + +template +void onPong(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + + Isolate *isolate = args.GetIsolate(); + Persistent *pongCallback = &groupData->pongHandler; + pongCallback->Reset(isolate, Local::Cast(args[1])); + group->onPong([isolate, pongCallback](uWS::WebSocket *webSocket, const char *message, size_t length) { + HandleScope hs(isolate); + Local argv[] = {wrapMessage(message, length, uWS::OpCode::PONG, isolate), + getDataV8(webSocket, isolate)}; + node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *pongCallback), 2, argv); + }); +} + +template +void onDisconnection(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + + Isolate *isolate = args.GetIsolate(); + Persistent *disconnectionCallback = &groupData->disconnectionHandler; + disconnectionCallback->Reset(isolate, Local::Cast(args[1])); + + group->onDisconnection([isolate, disconnectionCallback, groupData](uWS::WebSocket *webSocket, int code, char *message, size_t length) { + groupData->size--; + HandleScope hs(isolate); + Local argv[] = {wrapSocket(webSocket, isolate), + Integer::New(isolate, code), + wrapMessage(message, length, uWS::OpCode::CLOSE, isolate), + getDataV8(webSocket, isolate)}; + node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *disconnectionCallback), 4, argv); + }); +} + +void onError(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + + Isolate *isolate = args.GetIsolate(); + Persistent *errorCallback = &groupData->errorHandler; + errorCallback->Reset(isolate, Local::Cast(args[1])); + + group->onError([isolate, errorCallback](void *user) { + HandleScope hs(isolate); + Local argv[] = {Local::New(isolate, *(Persistent *) user)}; + node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *errorCallback), 1, argv); + + ((Persistent *) user)->Reset(); + delete (Persistent *) user; + }); +} + +template +void closeSocket(const FunctionCallbackInfo &args) { + NativeString nativeString(args[2]); + unwrapSocket(args[0].As())->close(args[1]->IntegerValue(), nativeString.getData(), nativeString.getLength()); +} + +template +void terminateSocket(const FunctionCallbackInfo &args) { + unwrapSocket(args[0].As())->terminate(); +} + +template +void closeGroup(const FunctionCallbackInfo &args) { + NativeString nativeString(args[2]); + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + group->close(args[1]->IntegerValue(), nativeString.getData(), nativeString.getLength()); +} + +template +void terminateGroup(const FunctionCallbackInfo &args) { + ((uWS::Group *) args[0].As()->Value())->terminate(); +} + +template +void broadcast(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + uWS::OpCode opCode = args[2]->BooleanValue() ? uWS::OpCode::BINARY : uWS::OpCode::TEXT; + NativeString nativeString(args[1]); + group->broadcast(nativeString.getData(), nativeString.getLength(), opCode); +} + +template +void prepareMessage(const FunctionCallbackInfo &args) { + uWS::OpCode opCode = (uWS::OpCode) args[1]->IntegerValue(); + NativeString nativeString(args[0]); + args.GetReturnValue().Set(External::New(args.GetIsolate(), uWS::WebSocket::prepareMessage(nativeString.getData(), nativeString.getLength(), opCode, false))); +} + +template +void sendPrepared(const FunctionCallbackInfo &args) { + unwrapSocket(args[0].As()) + ->sendPrepared((typename uWS::WebSocket::PreparedMessage *) args[1].As()->Value()); +} + +template +void finalizeMessage(const FunctionCallbackInfo &args) { + uWS::WebSocket::finalizeMessage((typename uWS::WebSocket::PreparedMessage *) args[0].As()->Value()); +} + +void forEach(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + Local cb = Local::Cast(args[1]); + group->forEach([isolate, &cb](uWS::WebSocket *webSocket) { + Local argv[] = { + getDataV8(webSocket, isolate) + }; + cb->Call(Null(isolate), 1, argv); + }); +} + +void getSize(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + GroupData *groupData = (GroupData *) group->getUserData(); + args.GetReturnValue().Set(Integer::New(args.GetIsolate(), groupData->size)); +} + +void startAutoPing(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + NativeString nativeString(args[2]); + group->startAutoPing(args[1]->IntegerValue(), std::string(nativeString.getData(), nativeString.getLength())); +} + +void setNoop(const FunctionCallbackInfo &args) { + noop.Reset(args.GetIsolate(), Local::Cast(args[0])); +} + +void listen(const FunctionCallbackInfo &args) { + uWS::Group *group = (uWS::Group *) args[0].As()->Value(); + hub.listen(args[1]->IntegerValue(), nullptr, 0, group); +} + +template +struct Namespace { + Local object; + Namespace (Isolate *isolate) { + object = Object::New(isolate); + NODE_SET_METHOD(object, "send", send); + NODE_SET_METHOD(object, "close", closeSocket); + NODE_SET_METHOD(object, "terminate", terminateSocket); + NODE_SET_METHOD(object, "prepareMessage", prepareMessage); + NODE_SET_METHOD(object, "sendPrepared", sendPrepared); + NODE_SET_METHOD(object, "finalizeMessage", finalizeMessage); + + Local group = Object::New(isolate); + NODE_SET_METHOD(group, "onConnection", onConnection); + NODE_SET_METHOD(group, "onMessage", onMessage); + NODE_SET_METHOD(group, "onDisconnection", onDisconnection); + + if (!isServer) { + NODE_SET_METHOD(group, "onError", onError); + } else { + NODE_SET_METHOD(group, "forEach", forEach); + NODE_SET_METHOD(group, "getSize", getSize); + NODE_SET_METHOD(group, "startAutoPing", startAutoPing); + NODE_SET_METHOD(group, "listen", listen); + } + + NODE_SET_METHOD(group, "onPing", onPing); + NODE_SET_METHOD(group, "onPong", onPong); + NODE_SET_METHOD(group, "create", createGroup); + NODE_SET_METHOD(group, "delete", deleteGroup); + NODE_SET_METHOD(group, "close", closeGroup); + NODE_SET_METHOD(group, "terminate", terminateGroup); + NODE_SET_METHOD(group, "broadcast", broadcast); + + object->Set(String::NewFromUtf8(isolate, "group"), group); + } +}; -- cgit v1.2.3