uwebsockets 2.0.0 → 2.1.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 +1 -1
- 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/AppWrapper.h
ADDED
|
@@ -0,0 +1,734 @@
|
|
|
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
|
+
#include "App.h"
|
|
19
|
+
#include <v8.h>
|
|
20
|
+
#include "Utilities.h"
|
|
21
|
+
using namespace v8;
|
|
22
|
+
|
|
23
|
+
/* uWS.App.ws('/pattern', behavior) */
|
|
24
|
+
template <typename APP>
|
|
25
|
+
void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
|
|
26
|
+
|
|
27
|
+
/* pattern, behavior */
|
|
28
|
+
if (missingArguments(2, args)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Isolate *isolate = args.GetIsolate();
|
|
33
|
+
|
|
34
|
+
PerContextData *perContextData = (PerContextData *) Local<External>::Cast(args.Data())->Value();
|
|
35
|
+
|
|
36
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
37
|
+
/* This one is default constructed with defaults */
|
|
38
|
+
typename APP::template WebSocketBehavior<PerSocketData> behavior = {};
|
|
39
|
+
|
|
40
|
+
NativeString pattern(args.GetIsolate(), args[0]);
|
|
41
|
+
if (pattern.isInvalid(args)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
UniquePersistent<Function> upgradePf;
|
|
46
|
+
UniquePersistent<Function> openPf;
|
|
47
|
+
UniquePersistent<Function> messagePf;
|
|
48
|
+
UniquePersistent<Function> drainPf;
|
|
49
|
+
UniquePersistent<Function> closePf;
|
|
50
|
+
UniquePersistent<Function> pingPf;
|
|
51
|
+
UniquePersistent<Function> pongPf;
|
|
52
|
+
UniquePersistent<Function> subscriptionPf;
|
|
53
|
+
|
|
54
|
+
/* Get the behavior object */
|
|
55
|
+
if (args.Length() == 2) {
|
|
56
|
+
Local<Object> behaviorObject = Local<Object>::Cast(args[1]);
|
|
57
|
+
|
|
58
|
+
/* maxPayloadLength or default */
|
|
59
|
+
MaybeLocal<Value> maybeMaxPayloadLength = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "maxPayloadLength", NewStringType::kNormal).ToLocalChecked());
|
|
60
|
+
if (!maybeMaxPayloadLength.IsEmpty() && !maybeMaxPayloadLength.ToLocalChecked()->IsUndefined()) {
|
|
61
|
+
behavior.maxPayloadLength = maybeMaxPayloadLength.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* idleTimeout or default */
|
|
65
|
+
MaybeLocal<Value> maybeIdleTimeout = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "idleTimeout", NewStringType::kNormal).ToLocalChecked());
|
|
66
|
+
if (!maybeIdleTimeout.IsEmpty() && !maybeIdleTimeout.ToLocalChecked()->IsUndefined()) {
|
|
67
|
+
behavior.idleTimeout = maybeIdleTimeout.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* maxLifetime or default */
|
|
71
|
+
MaybeLocal<Value> maybeMaxLifetime = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "maxLifetime", NewStringType::kNormal).ToLocalChecked());
|
|
72
|
+
if (!maybeMaxLifetime.IsEmpty() && !maybeMaxLifetime.ToLocalChecked()->IsUndefined()) {
|
|
73
|
+
behavior.maxLifetime = maybeMaxLifetime.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* closeOnBackpressureLimit or default */
|
|
77
|
+
MaybeLocal<Value> maybeCloseOnBackpressureLimit = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "closeOnBackpressureLimit", NewStringType::kNormal).ToLocalChecked());
|
|
78
|
+
if (!maybeCloseOnBackpressureLimit.IsEmpty() && !maybeCloseOnBackpressureLimit.ToLocalChecked()->IsUndefined()) {
|
|
79
|
+
behavior.closeOnBackpressureLimit = maybeCloseOnBackpressureLimit.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* sendPingsAutomatically or default */
|
|
83
|
+
MaybeLocal<Value> maybeSendPingsAutomatically = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "sendPingsAutomatically", NewStringType::kNormal).ToLocalChecked());
|
|
84
|
+
if (!maybeSendPingsAutomatically.IsEmpty() && !maybeSendPingsAutomatically.ToLocalChecked()->IsUndefined()) {
|
|
85
|
+
behavior.sendPingsAutomatically = maybeSendPingsAutomatically.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Compression or default, map from 0, 1, 2 to disabled, shared, dedicated. This is actually the enum */
|
|
89
|
+
MaybeLocal<Value> maybeCompression = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "compression", NewStringType::kNormal).ToLocalChecked());
|
|
90
|
+
if (!maybeCompression.IsEmpty() && !maybeCompression.ToLocalChecked()->IsUndefined()) {
|
|
91
|
+
behavior.compression = (uWS::CompressOptions) maybeCompression.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* maxBackpressure or default */
|
|
95
|
+
MaybeLocal<Value> maybeMaxBackpressure = behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "maxBackpressure", NewStringType::kNormal).ToLocalChecked());
|
|
96
|
+
if (!maybeMaxBackpressure.IsEmpty() && !maybeMaxBackpressure.ToLocalChecked()->IsUndefined()) {
|
|
97
|
+
behavior.maxBackpressure = maybeMaxBackpressure.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Upgrade */
|
|
101
|
+
upgradePf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "upgrade", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
102
|
+
/* Open */
|
|
103
|
+
openPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "open", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
104
|
+
/* Message */
|
|
105
|
+
messagePf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "message", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
106
|
+
/* Drain */
|
|
107
|
+
drainPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "drain", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
108
|
+
/* Close */
|
|
109
|
+
closePf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
110
|
+
/* Ping */
|
|
111
|
+
pingPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "ping", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
112
|
+
/* Pong */
|
|
113
|
+
pongPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "pong", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
114
|
+
/* Subscription */
|
|
115
|
+
subscriptionPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "subscription", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Upgrade handler is always optional */
|
|
120
|
+
if (upgradePf != Undefined(isolate)) {
|
|
121
|
+
behavior.upgrade = [upgradePf = std::move(upgradePf), perContextData](auto *res, auto *req, auto *context) {
|
|
122
|
+
Isolate *isolate = perContextData->isolate;
|
|
123
|
+
HandleScope hs(isolate);
|
|
124
|
+
|
|
125
|
+
Local<Function> upgradeLf = Local<Function>::New(isolate, upgradePf);
|
|
126
|
+
Local<Object> resObject = perContextData->resTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
|
|
127
|
+
resObject->SetAlignedPointerInInternalField(0, res);
|
|
128
|
+
|
|
129
|
+
Local<Object> reqObject = perContextData->reqTemplate[std::is_same<APP, uWS::H3App>::value].Get(isolate)->Clone();
|
|
130
|
+
reqObject->SetAlignedPointerInInternalField(0, req);
|
|
131
|
+
|
|
132
|
+
Local<Value> argv[3] = {resObject, reqObject, External::New(isolate, (void *) context)};
|
|
133
|
+
CallJS(isolate, upgradeLf, 3, argv);
|
|
134
|
+
|
|
135
|
+
/* Properly invalidate req */
|
|
136
|
+
reqObject->SetAlignedPointerInInternalField(0, nullptr);
|
|
137
|
+
|
|
138
|
+
/* µWS itself will terminate if not responded and not attached
|
|
139
|
+
* onAborted handler, so we can assume it's done */
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Open handler is NOT optional for the wrapper */
|
|
144
|
+
behavior.open = [openPf = std::move(openPf), perContextData](auto *ws) {
|
|
145
|
+
Isolate *isolate = perContextData->isolate;
|
|
146
|
+
HandleScope hs(isolate);
|
|
147
|
+
|
|
148
|
+
/* Create a new websocket object */
|
|
149
|
+
Local<Object> wsObject = perContextData->wsTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
|
|
150
|
+
wsObject->SetAlignedPointerInInternalField(0, ws);
|
|
151
|
+
|
|
152
|
+
/* Retrieve temporary userData object */
|
|
153
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
154
|
+
|
|
155
|
+
/* Copy entires from userData, only if we have it set (not the case for default constructor) */
|
|
156
|
+
if (!perSocketData->socketPf.IsEmpty()) {
|
|
157
|
+
/* socketPf points to a stack allocated UniquePersistent, or nullptr, at this point */
|
|
158
|
+
Local<Object> userData = Local<Object>::New(isolate, perSocketData->socketPf);
|
|
159
|
+
|
|
160
|
+
/* Merge userData and wsObject; this code is exceedingly horrible */
|
|
161
|
+
Local<Array> keys;
|
|
162
|
+
if (userData->GetOwnPropertyNames(isolate->GetCurrentContext()).ToLocal(&keys)) {
|
|
163
|
+
for (int i = 0; i < keys->Length(); i++) {
|
|
164
|
+
wsObject->Set(isolate->GetCurrentContext(),
|
|
165
|
+
keys->Get(isolate->GetCurrentContext(), i).ToLocalChecked(),
|
|
166
|
+
userData->Get(isolate->GetCurrentContext(), keys->Get(isolate->GetCurrentContext(), i).ToLocalChecked()).ToLocalChecked()
|
|
167
|
+
).ToChecked();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Attach a new V8 object with pointer to us, to it */
|
|
173
|
+
perSocketData->socketPf.Reset(isolate, wsObject);
|
|
174
|
+
|
|
175
|
+
Local<Function> openLf = Local<Function>::New(isolate, openPf);
|
|
176
|
+
if (!openLf->IsUndefined()) {
|
|
177
|
+
Local<Value> argv[] = {wsObject};
|
|
178
|
+
CallJS(isolate, openLf, 1, argv);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/* Message handler is always optional */
|
|
183
|
+
if (messagePf != Undefined(isolate)) {
|
|
184
|
+
behavior.message = [messagePf = std::move(messagePf), isolate](auto *ws, std::string_view message, uWS::OpCode opCode) {
|
|
185
|
+
HandleScope hs(isolate);
|
|
186
|
+
|
|
187
|
+
Local<ArrayBuffer> messageArrayBuffer = ArrayBuffer_New(isolate, (void *) message.data(), message.length());
|
|
188
|
+
|
|
189
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
190
|
+
Local<Value> argv[3] = {Local<Object>::New(isolate, perSocketData->socketPf),
|
|
191
|
+
messageArrayBuffer,
|
|
192
|
+
Boolean::New(isolate, opCode == uWS::OpCode::BINARY)};
|
|
193
|
+
|
|
194
|
+
CallJS(isolate, Local<Function>::New(isolate, messagePf), 3, argv);
|
|
195
|
+
|
|
196
|
+
/* Important: we clear the ArrayBuffer to make sure it is not invalidly used after return */
|
|
197
|
+
messageArrayBuffer->Detach();
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Drain handler is always optional */
|
|
202
|
+
if (drainPf != Undefined(isolate)) {
|
|
203
|
+
behavior.drain = [drainPf = std::move(drainPf), isolate](auto *ws) {
|
|
204
|
+
HandleScope hs(isolate);
|
|
205
|
+
|
|
206
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
207
|
+
Local<Value> argv[1] = {Local<Object>::New(isolate, perSocketData->socketPf)
|
|
208
|
+
};
|
|
209
|
+
CallJS(isolate, Local<Function>::New(isolate, drainPf), 1, argv);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* Subscription handler is always optional */
|
|
214
|
+
if (subscriptionPf != Undefined(isolate)) {
|
|
215
|
+
behavior.subscription = [subscriptionPf = std::move(subscriptionPf), isolate](auto *ws, std::string_view topic, int newCount, int oldCount) {
|
|
216
|
+
HandleScope hs(isolate);
|
|
217
|
+
|
|
218
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
219
|
+
Local<Value> argv[4] = {Local<Object>::New(isolate, perSocketData->socketPf), ArrayBuffer_New(isolate, (void *) topic.data(), topic.length()), Integer::New(isolate, newCount), Integer::New(isolate, oldCount)};
|
|
220
|
+
CallJS(isolate, Local<Function>::New(isolate, subscriptionPf), 4, argv);
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Ping handler is always optional */
|
|
225
|
+
if (pingPf != Undefined(isolate)) {
|
|
226
|
+
behavior.ping = [pingPf = std::move(pingPf), isolate](auto *ws, std::string_view message) {
|
|
227
|
+
HandleScope hs(isolate);
|
|
228
|
+
|
|
229
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
230
|
+
Local<Value> argv[2] = {Local<Object>::New(isolate, perSocketData->socketPf), ArrayBuffer_New(isolate, (void *) message.data(), message.length())};
|
|
231
|
+
CallJS(isolate, Local<Function>::New(isolate, pingPf), 2, argv);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Pong handler is always optional */
|
|
236
|
+
if (pongPf != Undefined(isolate)) {
|
|
237
|
+
behavior.pong = [pongPf = std::move(pongPf), isolate](auto *ws, std::string_view message) {
|
|
238
|
+
HandleScope hs(isolate);
|
|
239
|
+
|
|
240
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
241
|
+
Local<Value> argv[2] = {Local<Object>::New(isolate, perSocketData->socketPf), ArrayBuffer_New(isolate, (void *) message.data(), message.length())};
|
|
242
|
+
CallJS(isolate, Local<Function>::New(isolate, pongPf), 2, argv);
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* Close handler is NOT optional for the wrapper */
|
|
247
|
+
behavior.close = [closePf = std::move(closePf), isolate](auto *ws, int code, std::string_view message) {
|
|
248
|
+
HandleScope hs(isolate);
|
|
249
|
+
|
|
250
|
+
Local<ArrayBuffer> messageArrayBuffer = ArrayBuffer_New(isolate, (void *) message.data(), message.length());
|
|
251
|
+
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
252
|
+
Local<Object> wsObject = Local<Object>::New(isolate, perSocketData->socketPf);
|
|
253
|
+
|
|
254
|
+
/* Invalidate this wsObject */
|
|
255
|
+
wsObject->SetAlignedPointerInInternalField(0, nullptr);
|
|
256
|
+
|
|
257
|
+
/* Only call close handler if we have one set */
|
|
258
|
+
Local<Function> closeLf = Local<Function>::New(isolate, closePf);
|
|
259
|
+
if (!closeLf->IsUndefined()) {
|
|
260
|
+
Local<Value> argv[3] = {wsObject, Integer::New(isolate, code), messageArrayBuffer};
|
|
261
|
+
CallJS(isolate, closeLf, 3, argv);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* This should technically not be required */
|
|
265
|
+
perSocketData->socketPf.Reset();
|
|
266
|
+
|
|
267
|
+
/* Again, here we clear the buffer to avoid strange bugs */
|
|
268
|
+
messageArrayBuffer->Detach();
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
app->template ws<PerSocketData>(std::string(pattern.getString()), std::move(behavior));
|
|
272
|
+
|
|
273
|
+
/* Return this */
|
|
274
|
+
args.GetReturnValue().Set(args.Holder());
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* This method wraps get, post and all http methods */
|
|
278
|
+
template <typename APP, typename F>
|
|
279
|
+
void uWS_App_get(F f, const FunctionCallbackInfo<Value> &args) {
|
|
280
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
281
|
+
|
|
282
|
+
/* Pattern */
|
|
283
|
+
NativeString pattern(args.GetIsolate(), args[0]);
|
|
284
|
+
if (pattern.isInvalid(args)) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* If the handler is null */
|
|
289
|
+
if (args[1]->IsNull()) {
|
|
290
|
+
(app->*f)(std::string(pattern.getString()), nullptr);
|
|
291
|
+
args.GetReturnValue().Set(args.Holder());
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Handler */
|
|
296
|
+
Callback checkedCallback(args.GetIsolate(), args[1]);
|
|
297
|
+
if (checkedCallback.isInvalid(args)) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
UniquePersistent<Function> cb = checkedCallback.getFunction();
|
|
301
|
+
|
|
302
|
+
/* This function requires perContextData */
|
|
303
|
+
PerContextData *perContextData = (PerContextData *) Local<External>::Cast(args.Data())->Value();
|
|
304
|
+
|
|
305
|
+
(app->*f)(std::string(pattern.getString()), [cb = std::move(cb), perContextData](auto *res, auto *req) {
|
|
306
|
+
Isolate *isolate = perContextData->isolate;
|
|
307
|
+
HandleScope hs(isolate);
|
|
308
|
+
|
|
309
|
+
Local<Object> resObject = perContextData->resTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
|
|
310
|
+
resObject->SetAlignedPointerInInternalField(0, res);
|
|
311
|
+
|
|
312
|
+
Local<Object> reqObject = perContextData->reqTemplate[std::is_same<APP, uWS::H3App>::value].Get(isolate)->Clone();
|
|
313
|
+
reqObject->SetAlignedPointerInInternalField(0, req);
|
|
314
|
+
|
|
315
|
+
Local<Value> argv[] = {resObject, reqObject};
|
|
316
|
+
CallJS(isolate, cb.Get(isolate), 2, argv);
|
|
317
|
+
|
|
318
|
+
/* Properly invalidate req */
|
|
319
|
+
reqObject->SetAlignedPointerInInternalField(0, nullptr);
|
|
320
|
+
|
|
321
|
+
/* µWS itself will terminate if not responded and not attached
|
|
322
|
+
* onAborted handler, so we can assume it's done */
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
args.GetReturnValue().Set(args.Holder());
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
template <typename APP>
|
|
329
|
+
void uWS_App_close(const FunctionCallbackInfo<Value> &args) {
|
|
330
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
331
|
+
|
|
332
|
+
app->close();
|
|
333
|
+
args.GetReturnValue().Set(args.Holder());
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
template <typename APP>
|
|
337
|
+
void uWS_App_listen_unix(const FunctionCallbackInfo<Value> &args) {
|
|
338
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
339
|
+
|
|
340
|
+
Isolate *isolate = args.GetIsolate();
|
|
341
|
+
|
|
342
|
+
/* Require at least two arguments */
|
|
343
|
+
if (missingArguments(2, args)) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/* integer options is first (not implemented) */
|
|
348
|
+
|
|
349
|
+
/* Callback is first */
|
|
350
|
+
auto cb = [&args, isolate](auto *token) {
|
|
351
|
+
/* Return a false boolean if listen failed */
|
|
352
|
+
Local<Value> argv[] = {token ? Local<Value>::Cast(External::New(isolate, token)) : Local<Value>::Cast(Boolean::New(isolate, false))};
|
|
353
|
+
/* Immediate call cannot be CallJS */
|
|
354
|
+
Local<Function>::Cast(args[0])->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv).IsEmpty();
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
/* Path is last */
|
|
358
|
+
std::string path;
|
|
359
|
+
NativeString h(isolate, args[args.Length() - 1]);
|
|
360
|
+
if (h.isInvalid(args)) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
path = h.getString();
|
|
364
|
+
|
|
365
|
+
app->listen(std::move(cb), path);
|
|
366
|
+
|
|
367
|
+
args.GetReturnValue().Set(args.Holder());
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
template <typename APP>
|
|
371
|
+
void uWS_App_listen(const FunctionCallbackInfo<Value> &args) {
|
|
372
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
373
|
+
|
|
374
|
+
Isolate *isolate = args.GetIsolate();
|
|
375
|
+
|
|
376
|
+
/* Require at least two arguments */
|
|
377
|
+
if (missingArguments(2, args)) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* Callback is last */
|
|
382
|
+
auto cb = [&args, isolate](auto *token) {
|
|
383
|
+
/* Return a false boolean if listen failed */
|
|
384
|
+
Local<Value> argv[] = {token ? Local<Value>::Cast(External::New(isolate, token)) : Local<Value>::Cast(Boolean::New(isolate, false))};
|
|
385
|
+
/* Immediate call cannot be CallJS */
|
|
386
|
+
Local<Function>::Cast(args[args.Length() - 1])->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv).IsEmpty();
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
/* Host is first, if present */
|
|
390
|
+
std::string host;
|
|
391
|
+
if (!args[0]->IsNumber()) {
|
|
392
|
+
NativeString h(isolate, args[0]);
|
|
393
|
+
if (h.isInvalid(args)) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
host = h.getString();
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/* Port, options are in the middle, if present */
|
|
400
|
+
std::vector<int> numbers;
|
|
401
|
+
for (int i = std::min<int>(1, host.length()); i < args.Length() - 1; i++) {
|
|
402
|
+
numbers.push_back(args[i]->Uint32Value(args.GetIsolate()->GetCurrentContext()).ToChecked());
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/* We only use the most complete overload */
|
|
406
|
+
app->listen(host, numbers.size() ? numbers[0] : 0,
|
|
407
|
+
numbers.size() > 1 ? numbers[1] : 0, std::move(cb));
|
|
408
|
+
|
|
409
|
+
args.GetReturnValue().Set(args.Holder());
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
template <typename APP>
|
|
413
|
+
void uWS_App_domain(const FunctionCallbackInfo<Value> &args) {
|
|
414
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
415
|
+
|
|
416
|
+
Isolate *isolate = args.GetIsolate();
|
|
417
|
+
|
|
418
|
+
/* serverName */
|
|
419
|
+
if (missingArguments(1, args)) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
NativeString serverName(isolate, args[0]);
|
|
424
|
+
if (serverName.isInvalid(args)) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
app->domain(std::string(serverName.getString()));
|
|
429
|
+
|
|
430
|
+
args.GetReturnValue().Set(args.Holder());
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
template <typename APP>
|
|
434
|
+
void uWS_App_publish(const FunctionCallbackInfo<Value> &args) {
|
|
435
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
436
|
+
|
|
437
|
+
Isolate *isolate = args.GetIsolate();
|
|
438
|
+
|
|
439
|
+
/* topic, message [isBinary, compress] */
|
|
440
|
+
if (missingArguments(2, args)) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
NativeString topic(isolate, args[0]);
|
|
445
|
+
if (topic.isInvalid(args)) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
NativeString message(isolate, args[1]);
|
|
450
|
+
if (message.isInvalid(args)) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
bool ok = app->publish(topic.getString(), message.getString(), args[2]->BooleanValue(isolate) ? uWS::OpCode::BINARY : uWS::OpCode::TEXT, args[3]->BooleanValue(isolate));
|
|
455
|
+
|
|
456
|
+
args.GetReturnValue().Set(Boolean::New(isolate, ok));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
template <typename APP>
|
|
460
|
+
void uWS_App_numSubscribers(const FunctionCallbackInfo<Value> &args) {
|
|
461
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
462
|
+
|
|
463
|
+
Isolate *isolate = args.GetIsolate();
|
|
464
|
+
|
|
465
|
+
/* topic */
|
|
466
|
+
if (missingArguments(1, args)) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
NativeString topic(isolate, args[0]);
|
|
471
|
+
if (topic.isInvalid(args)) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
args.GetReturnValue().Set(Integer::New(isolate, app->numSubscribers(topic.getString())));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/* This one modified per-thread static strings temporarily */
|
|
479
|
+
std::pair<uWS::SocketContextOptions, bool> readOptionsObject(const FunctionCallbackInfo<Value> &args, int index) {
|
|
480
|
+
Isolate *isolate = args.GetIsolate();
|
|
481
|
+
/* Read the options object if any */
|
|
482
|
+
uWS::SocketContextOptions options = {};
|
|
483
|
+
thread_local std::string keyFileName, certFileName, passphrase, dhParamsFileName, caFileName, sslCiphers;
|
|
484
|
+
if (args.Length() > index) {
|
|
485
|
+
|
|
486
|
+
Local<Object> optionsObject = Local<Object>::Cast(args[index]);
|
|
487
|
+
|
|
488
|
+
/* Key file name */
|
|
489
|
+
NativeString keyFileNameValue(isolate, optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "key_file_name", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
|
|
490
|
+
if (keyFileNameValue.isInvalid(args)) {
|
|
491
|
+
return {};
|
|
492
|
+
}
|
|
493
|
+
if (keyFileNameValue.getString().length()) {
|
|
494
|
+
keyFileName = keyFileNameValue.getString();
|
|
495
|
+
options.key_file_name = keyFileName.c_str();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* Cert file name */
|
|
499
|
+
NativeString certFileNameValue(isolate, optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "cert_file_name", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
|
|
500
|
+
if (certFileNameValue.isInvalid(args)) {
|
|
501
|
+
return {};
|
|
502
|
+
}
|
|
503
|
+
if (certFileNameValue.getString().length()) {
|
|
504
|
+
certFileName = certFileNameValue.getString();
|
|
505
|
+
options.cert_file_name = certFileName.c_str();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* Passphrase */
|
|
509
|
+
NativeString passphraseValue(isolate, optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "passphrase", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
|
|
510
|
+
if (passphraseValue.isInvalid(args)) {
|
|
511
|
+
return {};
|
|
512
|
+
}
|
|
513
|
+
if (passphraseValue.getString().length()) {
|
|
514
|
+
passphrase = passphraseValue.getString();
|
|
515
|
+
options.passphrase = passphrase.c_str();
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/* DH params file name */
|
|
519
|
+
NativeString dhParamsFileNameValue(isolate, optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "dh_params_file_name", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
|
|
520
|
+
if (dhParamsFileNameValue.isInvalid(args)) {
|
|
521
|
+
return {};
|
|
522
|
+
}
|
|
523
|
+
if (dhParamsFileNameValue.getString().length()) {
|
|
524
|
+
dhParamsFileName = dhParamsFileNameValue.getString();
|
|
525
|
+
options.dh_params_file_name = dhParamsFileName.c_str();
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/* CA file name */
|
|
529
|
+
NativeString caFileNameValue(isolate, optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "ca_file_name", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
|
|
530
|
+
if (caFileNameValue.isInvalid(args)) {
|
|
531
|
+
return {};
|
|
532
|
+
}
|
|
533
|
+
if (caFileNameValue.getString().length()) {
|
|
534
|
+
caFileName = caFileNameValue.getString();
|
|
535
|
+
options.ca_file_name = caFileName.c_str();
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/* ssl_prefer_low_memory_usage */
|
|
539
|
+
options.ssl_prefer_low_memory_usage = optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "ssl_prefer_low_memory_usage", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()->BooleanValue(isolate);
|
|
540
|
+
|
|
541
|
+
/* ssl_ciphers */
|
|
542
|
+
NativeString sslCiphersValue(isolate, optionsObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "ssl_ciphers", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
|
|
543
|
+
if (sslCiphersValue.isInvalid(args)) {
|
|
544
|
+
return {};
|
|
545
|
+
}
|
|
546
|
+
if (sslCiphersValue.getString().length()) {
|
|
547
|
+
sslCiphers = sslCiphersValue.getString();
|
|
548
|
+
options.ssl_ciphers = sslCiphers.c_str();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return {options, true};
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
template <typename APP>
|
|
556
|
+
void uWS_App_addServerName(const FunctionCallbackInfo<Value> &args) {
|
|
557
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
558
|
+
|
|
559
|
+
Isolate *isolate = args.GetIsolate();
|
|
560
|
+
NativeString hostnamePatternValue(isolate, args[0]);
|
|
561
|
+
if (hostnamePatternValue.isInvalid(args)) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
std::string hostnamePattern;
|
|
565
|
+
if (hostnamePatternValue.getString().length()) {
|
|
566
|
+
hostnamePattern = hostnamePatternValue.getString();
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
auto [options, valid] = readOptionsObject(args, 1);
|
|
570
|
+
if (!valid) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
app->addServerName(hostnamePattern.c_str(), options);
|
|
575
|
+
|
|
576
|
+
args.GetReturnValue().Set(args.Holder());
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
template <typename APP>
|
|
580
|
+
void uWS_App_removeServerName(const FunctionCallbackInfo<Value> &args) {
|
|
581
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
582
|
+
|
|
583
|
+
Isolate *isolate = args.GetIsolate();
|
|
584
|
+
NativeString hostnamePatternValue(isolate, args[0]);
|
|
585
|
+
if (hostnamePatternValue.isInvalid(args)) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
std::string hostnamePattern;
|
|
589
|
+
if (hostnamePatternValue.getString().length()) {
|
|
590
|
+
hostnamePattern = hostnamePatternValue.getString();
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
app->removeServerName(hostnamePattern.c_str());
|
|
594
|
+
|
|
595
|
+
args.GetReturnValue().Set(args.Holder());
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
template <typename APP>
|
|
599
|
+
void uWS_App_missingServerName(const FunctionCallbackInfo<Value> &args) {
|
|
600
|
+
APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);
|
|
601
|
+
Isolate *isolate = args.GetIsolate();
|
|
602
|
+
|
|
603
|
+
UniquePersistent<Function> missingPf;
|
|
604
|
+
missingPf.Reset(args.GetIsolate(), Local<Function>::Cast(args[0]));
|
|
605
|
+
|
|
606
|
+
app->missingServerName([missingPf = std::move(missingPf), isolate](const char *hostname) {
|
|
607
|
+
/* We hand a JavaScript string here */
|
|
608
|
+
HandleScope hs(isolate);
|
|
609
|
+
Local<Function> missingLf = Local<Function>::New(isolate, missingPf);
|
|
610
|
+
Local<Value> argv[1] = {String::NewFromUtf8(isolate, hostname, NewStringType::kNormal).ToLocalChecked()};
|
|
611
|
+
CallJS(isolate, missingLf, 1, argv);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
args.GetReturnValue().Set(args.Holder());
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
template <typename APP>
|
|
618
|
+
void uWS_App(const FunctionCallbackInfo<Value> &args) {
|
|
619
|
+
|
|
620
|
+
Isolate *isolate = args.GetIsolate();
|
|
621
|
+
Local<FunctionTemplate> appTemplate = FunctionTemplate::New(isolate);
|
|
622
|
+
appTemplate->SetClassName(String::NewFromUtf8(isolate, std::is_same<APP, uWS::SSLApp>::value ? "uWS.SSLApp" : "uWS.App", NewStringType::kNormal).ToLocalChecked());
|
|
623
|
+
|
|
624
|
+
auto [options, valid] = readOptionsObject(args, 0);
|
|
625
|
+
if (!valid) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
APP *app;
|
|
630
|
+
|
|
631
|
+
if constexpr (!std::is_same<APP, uWS::H3App>::value) {
|
|
632
|
+
|
|
633
|
+
/* uSockets copies strings here */
|
|
634
|
+
app = new APP(options);
|
|
635
|
+
|
|
636
|
+
/* Throw if we failed to construct the app */
|
|
637
|
+
if (app->constructorFailed()) {
|
|
638
|
+
delete app;
|
|
639
|
+
args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(String::NewFromUtf8(isolate, "App construction failed", NewStringType::kNormal).ToLocalChecked())));
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
} else {
|
|
644
|
+
|
|
645
|
+
appTemplate->SetClassName(String::NewFromUtf8(isolate, "uWS.H3App", NewStringType::kNormal).ToLocalChecked());
|
|
646
|
+
|
|
647
|
+
app = new APP(options);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
appTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
|
651
|
+
|
|
652
|
+
/* All the http methods */
|
|
653
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "get", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
654
|
+
uWS_App_get<APP>(&APP::get, args);
|
|
655
|
+
}, args.Data()));
|
|
656
|
+
|
|
657
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "post", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
658
|
+
uWS_App_get<APP>(&APP::post, args);
|
|
659
|
+
}, args.Data()));
|
|
660
|
+
|
|
661
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "options", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
662
|
+
uWS_App_get<APP>(&APP::options, args);
|
|
663
|
+
}, args.Data()));
|
|
664
|
+
|
|
665
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "del", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
666
|
+
uWS_App_get<APP>(&APP::del, args);
|
|
667
|
+
}, args.Data()));
|
|
668
|
+
|
|
669
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "patch", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
670
|
+
uWS_App_get<APP>(&APP::patch, args);
|
|
671
|
+
}, args.Data()));
|
|
672
|
+
|
|
673
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "put", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
674
|
+
uWS_App_get<APP>(&APP::put, args);
|
|
675
|
+
}, args.Data()));
|
|
676
|
+
|
|
677
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "head", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
678
|
+
uWS_App_get<APP>(&APP::head, args);
|
|
679
|
+
}, args.Data()));
|
|
680
|
+
|
|
681
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "connect", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
682
|
+
uWS_App_get<APP>(&APP::connect, args);
|
|
683
|
+
}, args.Data()));
|
|
684
|
+
|
|
685
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "trace", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
686
|
+
uWS_App_get<APP>(&APP::trace, args);
|
|
687
|
+
}, args.Data()));
|
|
688
|
+
|
|
689
|
+
/* Any http method */
|
|
690
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "any", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
|
|
691
|
+
uWS_App_get<APP>(&APP::any, args);
|
|
692
|
+
}, args.Data()));
|
|
693
|
+
|
|
694
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_listen<APP>, args.Data()));
|
|
695
|
+
|
|
696
|
+
if constexpr (!std::is_same<APP, uWS::H3App>::value) {
|
|
697
|
+
|
|
698
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_close<APP>, args.Data()));
|
|
699
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen_unix", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_listen_unix<APP>, args.Data()));
|
|
700
|
+
|
|
701
|
+
/* ws, listen */
|
|
702
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "ws", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_ws<APP>, args.Data()));
|
|
703
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "publish", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_publish<APP>, args.Data()));
|
|
704
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "numSubscribers", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_numSubscribers<APP>, args.Data()));
|
|
705
|
+
|
|
706
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "domain", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_domain<APP>, args.Data()));
|
|
707
|
+
|
|
708
|
+
/* SNI */
|
|
709
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "addServerName", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_addServerName<APP>, args.Data()));
|
|
710
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "removeServerName", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_removeServerName<APP>, args.Data()));
|
|
711
|
+
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "missingServerName", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_missingServerName<APP>, args.Data()));
|
|
712
|
+
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
Local<Object> localApp = appTemplate->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
|
716
|
+
localApp->SetAlignedPointerInInternalField(0, app);
|
|
717
|
+
|
|
718
|
+
PerContextData *perContextData = (PerContextData *) Local<External>::Cast(args.Data())->Value();
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
if constexpr (!std::is_same<APP, uWS::H3App>::value) {
|
|
722
|
+
|
|
723
|
+
/* Add this to our delete list */
|
|
724
|
+
if constexpr (std::is_same<APP, uWS::SSLApp>::value) {
|
|
725
|
+
perContextData->sslApps.emplace_back(app);
|
|
726
|
+
} else {
|
|
727
|
+
perContextData->apps.emplace_back(app);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
args.GetReturnValue().Set(localApp);
|
|
733
|
+
|
|
734
|
+
}
|