uwebsockets 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +11 -0
- package/README.md +38 -44
- package/build.c +185 -0
- package/docs/Makefile +2 -0
- package/docs/generated/.nojekyll +1 -0
- package/docs/generated/assets/highlight.css +22 -0
- package/docs/generated/assets/main.js +4 -0
- package/docs/generated/assets/search.js +1 -0
- package/docs/generated/assets/style.css +1280 -0
- package/docs/generated/enums/ListenOptions.html +70 -0
- package/docs/generated/functions/App.html +94 -0
- package/docs/generated/functions/SSLApp.html +93 -0
- package/docs/generated/functions/getParts.html +95 -0
- package/docs/generated/functions/us_listen_socket_close.html +93 -0
- package/docs/generated/functions/us_socket_local_port.html +93 -0
- package/docs/generated/index.html +131 -0
- package/docs/generated/interfaces/AppOptions.html +115 -0
- package/docs/generated/interfaces/HttpRequest.html +204 -0
- package/docs/generated/interfaces/HttpResponse.html +400 -0
- package/docs/generated/interfaces/MultipartField.html +88 -0
- package/docs/generated/interfaces/TemplatedApp.html +595 -0
- package/docs/generated/interfaces/WebSocket.html +303 -0
- package/docs/generated/interfaces/WebSocketBehavior.html +331 -0
- package/docs/generated/interfaces/us_listen_socket.html +89 -0
- package/docs/generated/interfaces/us_socket.html +89 -0
- package/docs/generated/interfaces/us_socket_context_t.html +89 -0
- package/docs/generated/types/CompressOptions.html +84 -0
- package/docs/generated/types/RecognizedString.html +89 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_128KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_16KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_256KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_32KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_3KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_4KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_64KB.html +84 -0
- package/docs/generated/variables/DEDICATED_COMPRESSOR_8KB.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_16KB.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_1KB.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_2KB.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_32KB.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_4KB.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_512B.html +84 -0
- package/docs/generated/variables/DEDICATED_DECOMPRESSOR_8KB.html +84 -0
- package/docs/generated/variables/DISABLED.html +84 -0
- package/docs/generated/variables/SHARED_COMPRESSOR.html +84 -0
- package/docs/generated/variables/SHARED_DECOMPRESSOR.html +84 -0
- package/docs/index.d.ts +395 -0
- package/docs/report.pdf +0 -0
- package/docs/tsconfig.json +11 -0
- package/examples/AsyncFunction.js +43 -0
- package/examples/AutomaticPortSelection.js +20 -0
- package/examples/Backpressure.js +75 -0
- package/examples/Broadcast.js +39 -0
- package/examples/GracefulShutdown.js +39 -0
- package/examples/H3lloWorld.js +23 -0
- package/examples/Headers.js +31 -0
- package/examples/HelloWorld.js +18 -0
- package/examples/JsonPost.js +72 -0
- package/examples/ProxyProtocol.js +25 -0
- package/examples/PubSub.js +57 -0
- package/examples/RateLimit.js +69 -0
- package/examples/Router.js +30 -0
- package/examples/ServerName.js +34 -0
- package/examples/ServerSentEvents.js +48 -0
- package/examples/SlowReceiver.js +53 -0
- package/examples/Upgrade.js +51 -0
- package/examples/UpgradeAsync.js +80 -0
- package/examples/Upload.js +36 -0
- package/examples/VideoStreamer.js +115 -0
- package/examples/VideoStreamerSync.js +42 -0
- package/examples/WebSockets.js +37 -0
- package/examples/WorkerThreads.js +33 -0
- package/misc/Manycast latency comparison [lower is better].png +0 -0
- package/misc/addon.pro +24 -0
- package/misc/cert.pem +21 -0
- package/misc/chart.png +0 -0
- package/misc/features_strip.png +0 -0
- package/misc/host.pro +31 -0
- package/misc/key.pem +28 -0
- package/misc/logo.svg +1 -0
- package/misc/streaming.png +0 -0
- package/package.json +8 -4
- package/src/AppWrapper.h +734 -0
- package/src/HttpRequestWrapper.h +196 -0
- package/src/HttpResponseWrapper.h +463 -0
- package/src/Utilities.h +172 -0
- package/src/WebSocketWrapper.h +348 -0
- package/src/addon.cpp +437 -0
- package/src/host.cpp +115 -0
- package/src/uws.js +24 -0
- package/tests/Autobahn.js +102 -0
- package/tests/Hammer.js +203 -0
- package/tests/Makefile +2 -0
- package/tests/fuzzingclient.json +28 -0
package/src/Utilities.h
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Authored by Alex Hultman, 2018-2021.
|
|
3
|
+
* Intellectual property of third-party.
|
|
4
|
+
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#ifndef ADDON_UTILITIES_H
|
|
19
|
+
#define ADDON_UTILITIES_H
|
|
20
|
+
|
|
21
|
+
#include <v8.h>
|
|
22
|
+
using namespace v8;
|
|
23
|
+
|
|
24
|
+
/* Unfortunately we _have_ to depend on Node.js crap */
|
|
25
|
+
#include <node.h>
|
|
26
|
+
|
|
27
|
+
MaybeLocal<Value> CallJS(Isolate *isolate, Local<Function> f, int argc, Local<Value> *argv) {
|
|
28
|
+
extern int calledIntoJS;
|
|
29
|
+
extern thread_local int insideCorkCallback;
|
|
30
|
+
/* All calls we do into JS are properly corked, except for res.cork, where we increase the counter explicitly */
|
|
31
|
+
insideCorkCallback++;
|
|
32
|
+
/* Slow path */
|
|
33
|
+
auto ret = node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), f, argc, argv, {0, 0});
|
|
34
|
+
insideCorkCallback--;
|
|
35
|
+
return ret;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Local<v8::ArrayBuffer> ArrayBuffer_New(Isolate *isolate, void *data, size_t length) {
|
|
39
|
+
std::unique_ptr<BackingStore> backingStore = ArrayBuffer::NewBackingStore(data, length, [](void* data, size_t length, void* deleter_data) {}, nullptr);
|
|
40
|
+
return ArrayBuffer::New(isolate, std::shared_ptr<BackingStore>(backingStore.release()));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Local<v8::ArrayBuffer> ArrayBuffer_NewCopy(Isolate *isolate, void *data, size_t length) {
|
|
44
|
+
Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, length);
|
|
45
|
+
memcpy(ab->GetBackingStore()->Data(), data, length);
|
|
46
|
+
return ab;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
struct PerSocketData {
|
|
50
|
+
UniquePersistent<Object> socketPf;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
struct PerContextData {
|
|
54
|
+
Isolate *isolate;
|
|
55
|
+
UniquePersistent<Object> reqTemplate[2]; // 0 = non-SSL/SSL, 1 = Http3
|
|
56
|
+
UniquePersistent<Object> resTemplate[3]; // 0 = non-SSL, 1 = SSL, 2 = Http3
|
|
57
|
+
UniquePersistent<Object> wsTemplate[2];
|
|
58
|
+
|
|
59
|
+
/* We hold all apps until free */
|
|
60
|
+
std::vector<std::unique_ptr<uWS::App>> apps;
|
|
61
|
+
std::vector<std::unique_ptr<uWS::SSLApp>> sslApps;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
template <class APP>
|
|
65
|
+
static constexpr int getAppTypeIndex() {
|
|
66
|
+
/* Returns 1 for SSLApp and 0 for App */
|
|
67
|
+
//return std::is_same<APP, uWS::SSLApp>::value;
|
|
68
|
+
|
|
69
|
+
/* Returns 2 for H3App */
|
|
70
|
+
|
|
71
|
+
if constexpr (std::is_same<APP, uWS::App>::value) {
|
|
72
|
+
return 0;
|
|
73
|
+
} else if constexpr (std::is_same<APP, uWS::SSLApp>::value) {
|
|
74
|
+
return 1;
|
|
75
|
+
} else if constexpr (std::is_same<APP, uWS::H3App>::value) {
|
|
76
|
+
return 2;
|
|
77
|
+
} else {
|
|
78
|
+
// why does this fail?
|
|
79
|
+
//static_assert(false);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static inline bool missingArguments(int length, const FunctionCallbackInfo<Value> &args) {
|
|
84
|
+
if (args.Length() < length) {
|
|
85
|
+
std::string message = "Function requires at least ";
|
|
86
|
+
message += std::to_string(length);
|
|
87
|
+
message += " arguments.";
|
|
88
|
+
args.GetReturnValue().Set(args.GetIsolate()->ThrowException(v8::Exception::Error(String::NewFromUtf8(args.GetIsolate(), message.c_str(), NewStringType::kNormal).ToLocalChecked())));
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
struct Callback {
|
|
95
|
+
bool invalid = false;
|
|
96
|
+
UniquePersistent<Function> f;
|
|
97
|
+
Callback(Isolate *isolate, const Local<Value> &value) {
|
|
98
|
+
|
|
99
|
+
if (!value->IsFunction()) {
|
|
100
|
+
invalid = true;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
f.Reset(isolate, Local<Function>::Cast(value));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
bool isInvalid(const FunctionCallbackInfo<Value> &args) {
|
|
108
|
+
if (invalid) {
|
|
109
|
+
args.GetReturnValue().Set(args.GetIsolate()->ThrowException(v8::Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Passed callback is not a valid function.", NewStringType::kNormal).ToLocalChecked())));
|
|
110
|
+
}
|
|
111
|
+
return invalid;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
UniquePersistent<Function> &&getFunction() {
|
|
115
|
+
return std::move(f);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
class NativeString {
|
|
120
|
+
char *data;
|
|
121
|
+
size_t length;
|
|
122
|
+
char utf8ValueMemory[sizeof(String::Utf8Value)];
|
|
123
|
+
String::Utf8Value *utf8Value = nullptr;
|
|
124
|
+
bool invalid = false;
|
|
125
|
+
public:
|
|
126
|
+
NativeString(Isolate *isolate, const Local<Value> &value) {
|
|
127
|
+
if (value->IsUndefined()) {
|
|
128
|
+
data = nullptr;
|
|
129
|
+
length = 0;
|
|
130
|
+
} else if (value->IsString()) {
|
|
131
|
+
utf8Value = new (utf8ValueMemory) String::Utf8Value(isolate, value);
|
|
132
|
+
data = (**utf8Value);
|
|
133
|
+
length = utf8Value->length();
|
|
134
|
+
} else if (value->IsTypedArray()) {
|
|
135
|
+
Local<ArrayBufferView> arrayBufferView = Local<ArrayBufferView>::Cast(value);
|
|
136
|
+
auto contents = arrayBufferView->Buffer()->GetBackingStore();
|
|
137
|
+
length = arrayBufferView->ByteLength();
|
|
138
|
+
data = (char *) contents->Data() + arrayBufferView->ByteOffset();
|
|
139
|
+
} else if (value->IsArrayBuffer()) {
|
|
140
|
+
Local<ArrayBuffer> arrayBuffer = Local<ArrayBuffer>::Cast(value);
|
|
141
|
+
auto contents = arrayBuffer->GetBackingStore();
|
|
142
|
+
length = contents->ByteLength();
|
|
143
|
+
data = (char *) contents->Data();
|
|
144
|
+
} else if (value->IsSharedArrayBuffer()) {
|
|
145
|
+
Local<SharedArrayBuffer> arrayBuffer = Local<SharedArrayBuffer>::Cast(value);
|
|
146
|
+
auto contents = arrayBuffer->GetBackingStore();
|
|
147
|
+
length = contents->ByteLength();
|
|
148
|
+
data = (char *) contents->Data();
|
|
149
|
+
} else {
|
|
150
|
+
invalid = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
bool isInvalid(const FunctionCallbackInfo<Value> &args) {
|
|
155
|
+
if (invalid) {
|
|
156
|
+
args.GetReturnValue().Set(args.GetIsolate()->ThrowException(v8::Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Text and data can only be passed by String, ArrayBuffer or TypedArray.", NewStringType::kNormal).ToLocalChecked())));
|
|
157
|
+
}
|
|
158
|
+
return invalid;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
std::string_view getString() {
|
|
162
|
+
return {data, length};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
~NativeString() {
|
|
166
|
+
if (utf8Value) {
|
|
167
|
+
utf8Value->~Utf8Value();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
#endif
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Authored by Alex Hultman, 2018-2020.
|
|
3
|
+
* Intellectual property of third-party.
|
|
4
|
+
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "App.h"
|
|
19
|
+
#include "Utilities.h"
|
|
20
|
+
|
|
21
|
+
#include <v8.h>
|
|
22
|
+
using namespace v8;
|
|
23
|
+
|
|
24
|
+
/* todo: probably isCorked, cork should be exposed? */
|
|
25
|
+
|
|
26
|
+
struct WebSocketWrapper {
|
|
27
|
+
|
|
28
|
+
template <bool SSL>
|
|
29
|
+
static inline uWS::WebSocket<SSL, true, PerSocketData> *getWebSocket(const FunctionCallbackInfo<Value> &args) {
|
|
30
|
+
Isolate *isolate = args.GetIsolate();
|
|
31
|
+
auto *ws = (uWS::WebSocket<SSL, true, PerSocketData> *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
32
|
+
if (!ws) {
|
|
33
|
+
args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(String::NewFromUtf8(isolate, "Invalid access of closed uWS.WebSocket/SSLWebSocket.", NewStringType::kNormal).ToLocalChecked())));
|
|
34
|
+
}
|
|
35
|
+
return ws;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static inline void invalidateWsObject(const FunctionCallbackInfo<Value> &args) {
|
|
39
|
+
args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Takes nothing returns holder (only used to fool TypeScript, as a conversion from WS to UserData) */
|
|
43
|
+
template <bool SSL>
|
|
44
|
+
static void uWS_WebSocket_getUserData(const FunctionCallbackInfo<Value> &args) {
|
|
45
|
+
args.GetReturnValue().Set(args.Holder());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Takes string topic */
|
|
49
|
+
template <bool SSL>
|
|
50
|
+
static void uWS_WebSocket_subscribe(const FunctionCallbackInfo<Value> &args) {
|
|
51
|
+
Isolate *isolate = args.GetIsolate();
|
|
52
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
53
|
+
if (ws) {
|
|
54
|
+
NativeString topic(isolate, args[0]);
|
|
55
|
+
if (topic.isInvalid(args)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
bool nonStrict = args.Length() > 1 && args[1]->BooleanValue(isolate);
|
|
59
|
+
bool success = ws->subscribe(topic.getString(), nonStrict);
|
|
60
|
+
args.GetReturnValue().Set(Boolean::New(isolate, success));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Takes string topic, returns boolean success */
|
|
65
|
+
template <bool SSL>
|
|
66
|
+
static void uWS_WebSocket_unsubscribe(const FunctionCallbackInfo<Value> &args) {
|
|
67
|
+
Isolate *isolate = args.GetIsolate();
|
|
68
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
69
|
+
if (ws) {
|
|
70
|
+
NativeString topic(isolate, args[0]);
|
|
71
|
+
if (topic.isInvalid(args)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
bool nonStrict = args.Length() > 1 && args[1]->BooleanValue(isolate);
|
|
75
|
+
bool success = ws->unsubscribe(topic.getString(), nonStrict);
|
|
76
|
+
args.GetReturnValue().Set(Boolean::New(isolate, success));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Takes string topic, message, returns boolean success */
|
|
81
|
+
template <bool SSL>
|
|
82
|
+
static void uWS_WebSocket_publish(const FunctionCallbackInfo<Value> &args) {
|
|
83
|
+
Isolate *isolate = args.GetIsolate();
|
|
84
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
85
|
+
if (ws) {
|
|
86
|
+
if (missingArguments(2, args)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
NativeString topic(isolate, args[0]);
|
|
91
|
+
if (topic.isInvalid(args)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
NativeString message(isolate, args[1]);
|
|
95
|
+
if (message.isInvalid(args)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
bool success = ws->publish(topic.getString(), message.getString(), args[2]->BooleanValue(isolate) ? uWS::OpCode::BINARY : uWS::OpCode::TEXT, args[3]->BooleanValue(isolate));
|
|
100
|
+
args.GetReturnValue().Set(Boolean::New(isolate, success));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* It would make sense to call terminate "close" and call close "end" to line up with HTTP */
|
|
105
|
+
/* That also makes sense seince close takes message and code -> you can end with a string message */
|
|
106
|
+
|
|
107
|
+
/* Takes nothing returns nothing */
|
|
108
|
+
template <bool SSL>
|
|
109
|
+
static void uWS_WebSocket_close(const FunctionCallbackInfo<Value> &args) {
|
|
110
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
111
|
+
if (ws) {
|
|
112
|
+
invalidateWsObject(args);
|
|
113
|
+
ws->close();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Takes code, message, returns undefined */
|
|
118
|
+
template <bool SSL>
|
|
119
|
+
static void uWS_WebSocket_end(const FunctionCallbackInfo<Value> &args) {
|
|
120
|
+
Isolate *isolate = args.GetIsolate();
|
|
121
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
122
|
+
if (ws) {
|
|
123
|
+
int code = 0;
|
|
124
|
+
if (args.Length() >= 1) {
|
|
125
|
+
code = args[0]->Uint32Value(isolate->GetCurrentContext()).ToChecked();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
NativeString message(args.GetIsolate(), args[1]);
|
|
129
|
+
if (message.isInvalid(args)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
invalidateWsObject(args);
|
|
134
|
+
ws->end(code, message.getString());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Takes nothing returns arraybuffer */
|
|
139
|
+
template <bool SSL>
|
|
140
|
+
static void uWS_WebSocket_getRemoteAddress(const FunctionCallbackInfo<Value> &args) {
|
|
141
|
+
Isolate *isolate = args.GetIsolate();
|
|
142
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
143
|
+
if (ws) {
|
|
144
|
+
std::string_view ip = ws->getRemoteAddress();
|
|
145
|
+
|
|
146
|
+
args.GetReturnValue().Set(ArrayBuffer_NewCopy(isolate, (void *) ip.data(), ip.length()));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Takes nothing returns arraybuffer */
|
|
151
|
+
template <bool SSL>
|
|
152
|
+
static void uWS_WebSocket_getRemoteAddressAsText(const FunctionCallbackInfo<Value> &args) {
|
|
153
|
+
Isolate *isolate = args.GetIsolate();
|
|
154
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
155
|
+
if (ws) {
|
|
156
|
+
std::string_view ip = ws->getRemoteAddressAsText();
|
|
157
|
+
|
|
158
|
+
args.GetReturnValue().Set(ArrayBuffer_NewCopy(isolate, (void *) ip.data(), ip.length()));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Takes nothing, returns integer */
|
|
163
|
+
template <bool SSL>
|
|
164
|
+
static void uWS_WebSocket_getBufferedAmount(const FunctionCallbackInfo<Value> &args) {
|
|
165
|
+
Isolate *isolate = args.GetIsolate();
|
|
166
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
167
|
+
if (ws) {
|
|
168
|
+
unsigned int bufferedAmount = ws->getBufferedAmount();
|
|
169
|
+
args.GetReturnValue().Set(Integer::NewFromUnsigned(isolate, bufferedAmount));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Takes message, isBinary, compressed. Returns true on success, false otherwise */
|
|
174
|
+
template <bool SSL>
|
|
175
|
+
static void uWS_WebSocket_sendFirstFragment(const FunctionCallbackInfo<Value> &args) {
|
|
176
|
+
Isolate *isolate = args.GetIsolate();
|
|
177
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
178
|
+
if (ws) {
|
|
179
|
+
NativeString message(args.GetIsolate(), args[0]);
|
|
180
|
+
if (message.isInvalid(args)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
unsigned int sendStatus = ws->sendFirstFragment(message.getString(), args[1]->BooleanValue(isolate) ? uWS::OpCode::BINARY : uWS::OpCode::TEXT, args[2]->BooleanValue(isolate));
|
|
185
|
+
|
|
186
|
+
args.GetReturnValue().Set(Integer::NewFromUnsigned(isolate, sendStatus));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* Takes message, compressed. Returns true on success, false otherwise */
|
|
191
|
+
template <bool SSL>
|
|
192
|
+
static void uWS_WebSocket_sendFragment(const FunctionCallbackInfo<Value> &args) {
|
|
193
|
+
Isolate *isolate = args.GetIsolate();
|
|
194
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
195
|
+
if (ws) {
|
|
196
|
+
NativeString message(args.GetIsolate(), args[0]);
|
|
197
|
+
if (message.isInvalid(args)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
unsigned int sendStatus = ws->sendFragment(message.getString(), args[1]->BooleanValue(isolate));
|
|
202
|
+
|
|
203
|
+
args.GetReturnValue().Set(Integer::NewFromUnsigned(isolate, sendStatus));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Takes message, compressed. Returns true on success, false otherwise */
|
|
208
|
+
template <bool SSL>
|
|
209
|
+
static void uWS_WebSocket_sendLastFragment(const FunctionCallbackInfo<Value> &args) {
|
|
210
|
+
Isolate *isolate = args.GetIsolate();
|
|
211
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
212
|
+
if (ws) {
|
|
213
|
+
NativeString message(args.GetIsolate(), args[0]);
|
|
214
|
+
if (message.isInvalid(args)) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
unsigned int sendStatus = ws->sendLastFragment(message.getString(), args[1]->BooleanValue(isolate));
|
|
219
|
+
|
|
220
|
+
args.GetReturnValue().Set(Integer::NewFromUnsigned(isolate, sendStatus));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Takes message, isBinary, compressed. Returns true on success, false otherwise */
|
|
225
|
+
template <bool SSL>
|
|
226
|
+
static void uWS_WebSocket_send(const FunctionCallbackInfo<Value> &args) {
|
|
227
|
+
Isolate *isolate = args.GetIsolate();
|
|
228
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
229
|
+
if (ws) {
|
|
230
|
+
NativeString message(args.GetIsolate(), args[0]);
|
|
231
|
+
if (message.isInvalid(args)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
unsigned int sendStatus = ws->send(message.getString(), args[1]->BooleanValue(isolate) ? uWS::OpCode::BINARY : uWS::OpCode::TEXT, args[2]->BooleanValue(isolate));
|
|
236
|
+
|
|
237
|
+
args.GetReturnValue().Set(Integer::NewFromUnsigned(isolate, sendStatus));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Takes topic string, returns bool */
|
|
242
|
+
template <bool SSL>
|
|
243
|
+
static void uWS_WebSocket_isSubscribed(const FunctionCallbackInfo<Value> &args) {
|
|
244
|
+
Isolate *isolate = args.GetIsolate();
|
|
245
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
246
|
+
if (ws) {
|
|
247
|
+
NativeString topic(args.GetIsolate(), args[0]);
|
|
248
|
+
if (topic.isInvalid(args)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
bool subscribed = ws->isSubscribed(topic.getString());
|
|
253
|
+
|
|
254
|
+
args.GetReturnValue().Set(Boolean::New(isolate, subscribed));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Takes message. Returns true on success, false otherwise */
|
|
259
|
+
template <bool SSL>
|
|
260
|
+
static void uWS_WebSocket_ping(const FunctionCallbackInfo<Value> &args) {
|
|
261
|
+
Isolate *isolate = args.GetIsolate();
|
|
262
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
263
|
+
if (ws) {
|
|
264
|
+
NativeString message(args.GetIsolate(), args[0]);
|
|
265
|
+
if (message.isInvalid(args)) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* This is a wrapper that does not exist in the C++ project */
|
|
270
|
+
unsigned int sendStatus = ws->send(message.getString(), uWS::OpCode::PING);
|
|
271
|
+
|
|
272
|
+
args.GetReturnValue().Set(Integer::NewFromUnsigned(isolate, sendStatus));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* Takes function, returns this */
|
|
277
|
+
template <bool SSL>
|
|
278
|
+
static void uWS_WebSocket_cork(const FunctionCallbackInfo<Value> &args) {
|
|
279
|
+
Isolate *isolate = args.GetIsolate();
|
|
280
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
281
|
+
if (ws) {
|
|
282
|
+
|
|
283
|
+
ws->cork([cb = Local<Function>::Cast(args[0]), isolate]() {
|
|
284
|
+
/* No need for CallJS here */
|
|
285
|
+
cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
args.GetReturnValue().Set(args.Holder());
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* This one is wrapped instead of iterateTopics as JS-people will put their hands in wood chipper for sure. */
|
|
293
|
+
template <bool SSL>
|
|
294
|
+
static void uWS_WebSocket_getTopics(const FunctionCallbackInfo<Value> &args) {
|
|
295
|
+
Isolate *isolate = args.GetIsolate();
|
|
296
|
+
auto *ws = getWebSocket<SSL>(args);
|
|
297
|
+
if (ws) {
|
|
298
|
+
|
|
299
|
+
Local<Array> topicsArray = Array::New(isolate, 0);
|
|
300
|
+
|
|
301
|
+
ws->iterateTopics([&topicsArray, isolate](std::string_view topic) {
|
|
302
|
+
Local<String> topicString = String::NewFromUtf8(isolate, topic.data(), NewStringType::kNormal, topic.length()).ToLocalChecked();
|
|
303
|
+
|
|
304
|
+
topicsArray->Set(isolate->GetCurrentContext(), topicsArray->Length(), topicString).IsNothing();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
args.GetReturnValue().Set(topicsArray);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
template <bool SSL>
|
|
312
|
+
static Local<Object> init(Isolate *isolate) {
|
|
313
|
+
Local<FunctionTemplate> wsTemplateLocal = FunctionTemplate::New(isolate);
|
|
314
|
+
if (SSL) {
|
|
315
|
+
wsTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.SSLWebSocket", NewStringType::kNormal).ToLocalChecked());
|
|
316
|
+
} else {
|
|
317
|
+
wsTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.WebSocket", NewStringType::kNormal).ToLocalChecked());
|
|
318
|
+
}
|
|
319
|
+
wsTemplateLocal->InstanceTemplate()->SetInternalFieldCount(1);
|
|
320
|
+
|
|
321
|
+
/* Register our functions */
|
|
322
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "sendFirstFragment", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_sendFirstFragment<SSL>));
|
|
323
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "sendFragment", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_sendFragment<SSL>));
|
|
324
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "sendLastFragment", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_sendLastFragment<SSL>));
|
|
325
|
+
|
|
326
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getUserData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_getUserData<SSL>));
|
|
327
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "send", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_send<SSL>));
|
|
328
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "end", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_end<SSL>));
|
|
329
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_close<SSL>));
|
|
330
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getBufferedAmount", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_getBufferedAmount<SSL>));
|
|
331
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_getRemoteAddress<SSL>));
|
|
332
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "subscribe", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_subscribe<SSL>));
|
|
333
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "unsubscribe", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_unsubscribe<SSL>));
|
|
334
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "publish", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_publish<SSL>));
|
|
335
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "cork", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_cork<SSL>));
|
|
336
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "ping", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_ping<SSL>));
|
|
337
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddressAsText", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_getRemoteAddressAsText<SSL>));
|
|
338
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "isSubscribed", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_isSubscribed<SSL>));
|
|
339
|
+
|
|
340
|
+
/* This one does not exist in C++ */
|
|
341
|
+
wsTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getTopics", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_WebSocket_getTopics<SSL>));
|
|
342
|
+
|
|
343
|
+
/* Create the template */
|
|
344
|
+
Local<Object> wsObjectLocal = wsTemplateLocal->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
|
345
|
+
|
|
346
|
+
return wsObjectLocal;
|
|
347
|
+
}
|
|
348
|
+
};
|