#include "App.h" #include #include "Utilities.h" using namespace v8; /* todo: probably isCorked, cork should be exposed? */ struct WebSocketWrapper { static Persistent wsTemplate[2]; template static inline uWS::WebSocket *getWebSocket(const FunctionCallbackInfo &args) { auto *ws = (uWS::WebSocket *) args.Holder()->GetAlignedPointerFromInternalField(0); if (!ws) { args.GetReturnValue().Set(isolate->ThrowException(String::NewFromUtf8(isolate, "Invalid access of closed uWS.WebSocket/SSLWebSocket."))); } return ws; } static inline void invalidateWsObject(const FunctionCallbackInfo &args) { args.Holder()->SetAlignedPointerInInternalField(0, nullptr); } /* Takes string topic */ template static void uWS_WebSocket_subscribe(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { NativeString topic(isolate, args[0]); ws->subscribe(topic.getString()); } } /* Takes string topic, message */ template static void uWS_WebSocket_publish(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { NativeString topic(isolate, args[0]); NativeString message(isolate, args[1]); ws->publish(topic.getString(), message.getString()); } } /* It would make sense to call terminate "close" and call close "end" to line up with HTTP */ /* That also makes sense seince close takes message and code -> you can end with a string message */ /* Takes nothing returns nothing */ template static void uWS_WebSocket_close(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { invalidateWsObject(args); ws->close(); } } /* Takes code, message, returns undefined */ template static void uWS_WebSocket_end(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { int code = 0; if (args.Length() >= 1) { code = args[0]->Uint32Value(); } NativeString message(args.GetIsolate(), args[1]); if (message.isInvalid(args)) { return; } invalidateWsObject(args); ws->end(code, message.getString()); } } /* Takes nothing returns arraybuffer */ template static void uWS_WebSocket_getRemoteAddress(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { std::string_view ip = ws->getRemoteAddress(); /* Todo: we need to pass a copy here */ args.GetReturnValue().Set(ArrayBuffer::New(isolate, (void *) ip.data(), ip.length()/*, ArrayBufferCreationMode::kInternalized*/)); } } /* Takes nothing, returns integer */ template static void uWS_WebSocket_getBufferedAmount(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { int bufferedAmount = ws->getBufferedAmount(); args.GetReturnValue().Set(Integer::New(isolate, bufferedAmount)); } } /* Takes message, isBinary. Returns true on success, false otherwise */ template static void uWS_WebSocket_send(const FunctionCallbackInfo &args) { auto *ws = getWebSocket(args); if (ws) { NativeString message(args.GetIsolate(), args[0]); if (message.isInvalid(args)) { return; } bool ok = ws->send(message.getString(), args[1]->BooleanValue() ? uWS::OpCode::BINARY : uWS::OpCode::TEXT); args.GetReturnValue().Set(Boolean::New(isolate, ok)); } } template static void initWsTemplate() { Local wsTemplateLocal = FunctionTemplate::New(isolate); if (SSL) { wsTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.SSLWebSocket")); } else { wsTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.WebSocket")); } wsTemplateLocal->InstanceTemplate()->SetInternalFieldCount(1); /* Register our functions */ wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "send"), FunctionTemplate::New(isolate, uWS_WebSocket_send)); wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "end"), FunctionTemplate::New(isolate, uWS_WebSocket_end)); wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close"), FunctionTemplate::New(isolate, uWS_WebSocket_close)); wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getBufferedAmount"), FunctionTemplate::New(isolate, uWS_WebSocket_getBufferedAmount)); wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddress"), FunctionTemplate::New(isolate, uWS_WebSocket_getRemoteAddress)); wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "subscribe"), FunctionTemplate::New(isolate, uWS_WebSocket_subscribe)); wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "publish"), FunctionTemplate::New(isolate, uWS_WebSocket_publish)); /* Create the template */ Local wsObjectLocal = wsTemplateLocal->GetFunction()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); wsTemplate[SSL].Reset(isolate, wsObjectLocal); } /* This is where we output an instance */ template static Local getWsInstance() { return Local::New(isolate, wsTemplate[std::is_same::value])->Clone(); } }; /* Fix this, should be nicer */ Persistent WebSocketWrapper::wsTemplate[2];