Initial upgrade to v18
This commit is contained in:
parent
550c49d302
commit
b4df9ebf5f
45
examples/Upgrade.js
vendored
Normal file
45
examples/Upgrade.js
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* A quite detailed WebSockets example */
|
||||||
|
|
||||||
|
const uWS = require('../dist/uws.js');
|
||||||
|
const port = 9001;
|
||||||
|
|
||||||
|
const app = uWS./*SSL*/App({
|
||||||
|
key_file_name: 'misc/key.pem',
|
||||||
|
cert_file_name: 'misc/cert.pem',
|
||||||
|
passphrase: '1234'
|
||||||
|
}).ws('/*', {
|
||||||
|
/* Options */
|
||||||
|
compression: 0,
|
||||||
|
maxPayloadLength: 16 * 1024 * 1024,
|
||||||
|
idleTimeout: 10,
|
||||||
|
/* Handlers */
|
||||||
|
upgrade: (res, req, context) => {
|
||||||
|
console.log('An Http connection wants to become WebSocket, URL: ' + req.getUrl() + '!');
|
||||||
|
|
||||||
|
res.upgrade({url: req.getUrl()}, req.getHeader('sec-websocket-key'),
|
||||||
|
req.getHeader('sec-websocket-protocol'),
|
||||||
|
req.getHeader('sec-websocket-extensions'),
|
||||||
|
context);
|
||||||
|
},
|
||||||
|
open: (ws) => {
|
||||||
|
console.log('A WebSocket connected with URL: ' + ws.userData.url);
|
||||||
|
},
|
||||||
|
message: (ws, message, isBinary) => {
|
||||||
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
|
let ok = ws.send(message, isBinary);
|
||||||
|
},
|
||||||
|
drain: (ws) => {
|
||||||
|
console.log('WebSocket backpressure: ' + ws.getBufferedAmount());
|
||||||
|
},
|
||||||
|
close: (ws, code, message) => {
|
||||||
|
console.log('WebSocket closed');
|
||||||
|
}
|
||||||
|
}).any('/*', (res, req) => {
|
||||||
|
res.end('Nothing to see here!');
|
||||||
|
}).listen(port, (token) => {
|
||||||
|
if (token) {
|
||||||
|
console.log('Listening to port ' + port);
|
||||||
|
} else {
|
||||||
|
console.log('Failed to listen to port ' + port);
|
||||||
|
}
|
||||||
|
});
|
4
examples/WebSockets.js
vendored
4
examples/WebSockets.js
vendored
@ -13,8 +13,8 @@ const app = uWS./*SSL*/App({
|
|||||||
maxPayloadLength: 16 * 1024 * 1024,
|
maxPayloadLength: 16 * 1024 * 1024,
|
||||||
idleTimeout: 10,
|
idleTimeout: 10,
|
||||||
/* Handlers */
|
/* Handlers */
|
||||||
open: (ws, req) => {
|
open: (ws) => {
|
||||||
console.log('A WebSocket connected via URL: ' + req.getUrl() + '!');
|
console.log('A WebSocket connected!');
|
||||||
},
|
},
|
||||||
message: (ws, message, isBinary) => {
|
message: (ws, message, isBinary) => {
|
||||||
/* Ok is false if backpressure was built up, wait for drain */
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
|
@ -20,6 +20,7 @@ void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniquePersistent<Function> upgradePf;
|
||||||
UniquePersistent<Function> openPf;
|
UniquePersistent<Function> openPf;
|
||||||
UniquePersistent<Function> messagePf;
|
UniquePersistent<Function> messagePf;
|
||||||
UniquePersistent<Function> drainPf;
|
UniquePersistent<Function> drainPf;
|
||||||
@ -27,10 +28,6 @@ void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
|
|||||||
UniquePersistent<Function> pingPf;
|
UniquePersistent<Function> pingPf;
|
||||||
UniquePersistent<Function> pongPf;
|
UniquePersistent<Function> pongPf;
|
||||||
|
|
||||||
struct PerSocketData {
|
|
||||||
UniquePersistent<Object> *socketPf;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Get the behavior object */
|
/* Get the behavior object */
|
||||||
if (args.Length() == 2) {
|
if (args.Length() == 2) {
|
||||||
Local<Object> behaviorObject = Local<Object>::Cast(args[1]);
|
Local<Object> behaviorObject = Local<Object>::Cast(args[1]);
|
||||||
@ -59,6 +56,8 @@ void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
|
|||||||
behavior.maxBackpressure = maybeMaxBackpressure.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
behavior.maxBackpressure = maybeMaxBackpressure.ToLocalChecked()->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Upgrade */
|
||||||
|
upgradePf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "upgrade", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
||||||
/* Open */
|
/* Open */
|
||||||
openPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "open", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
openPf.Reset(args.GetIsolate(), Local<Function>::Cast(behaviorObject->Get(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "open", NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()));
|
||||||
/* Message */
|
/* Message */
|
||||||
@ -74,28 +73,58 @@ void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open handler is NOT optional for the wrapper */
|
/* Upgrade handler is always optional */
|
||||||
behavior.open = [openPf = std::move(openPf), perContextData](auto *ws, auto *req) {
|
if (upgradePf != Undefined(isolate)) {
|
||||||
|
behavior.upgrade = [upgradePf = std::move(upgradePf), perContextData](auto *res, auto *req, auto *context) {
|
||||||
Isolate *isolate = perContextData->isolate;
|
Isolate *isolate = perContextData->isolate;
|
||||||
HandleScope hs(isolate);
|
HandleScope hs(isolate);
|
||||||
|
|
||||||
|
Local<Function> upgradeLf = Local<Function>::New(isolate, upgradePf);
|
||||||
|
Local<Object> resObject = perContextData->resTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
|
||||||
|
resObject->SetAlignedPointerInInternalField(0, res);
|
||||||
|
|
||||||
|
Local<Object> reqObject = perContextData->reqTemplate.Get(isolate)->Clone();
|
||||||
|
reqObject->SetAlignedPointerInInternalField(0, req);
|
||||||
|
|
||||||
|
Local<Value> argv[3] = {resObject, reqObject, External::New(isolate, (void *) context)};
|
||||||
|
CallJS(isolate, upgradeLf, 3, argv);
|
||||||
|
|
||||||
|
/* Properly invalidate req */
|
||||||
|
reqObject->SetAlignedPointerInInternalField(0, nullptr);
|
||||||
|
|
||||||
|
/* µWS itself will terminate if not responded and not attached
|
||||||
|
* onAborted handler, so we can assume it's done */
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open handler is NOT optional for the wrapper */
|
||||||
|
behavior.open = [openPf = std::move(openPf), perContextData](auto *ws) {
|
||||||
|
Isolate *isolate = perContextData->isolate;
|
||||||
|
HandleScope hs(isolate);
|
||||||
|
|
||||||
|
printf("Open event called!\n");
|
||||||
|
|
||||||
|
/* Retrieve temporary userData object */
|
||||||
|
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
||||||
|
|
||||||
|
// if socketPf is nullptr we have nothing to copy
|
||||||
|
Local<Object> userData = Local<Object>::New(isolate, *(perSocketData->socketPf));
|
||||||
|
|
||||||
/* Create a new websocket object */
|
/* Create a new websocket object */
|
||||||
Local<Object> wsObject = perContextData->wsTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
|
Local<Object> wsObject = perContextData->wsTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
|
||||||
wsObject->SetAlignedPointerInInternalField(0, ws);
|
wsObject->SetAlignedPointerInInternalField(0, ws);
|
||||||
|
|
||||||
/* Create the HttpRequest wrapper */
|
/* Copy entires from userData */
|
||||||
Local<Object> reqObject = perContextData->reqTemplate.Get(isolate)->Clone();
|
wsObject->Set(isolate->GetCurrentContext(), String::NewFromUtf8(isolate, "userData"), userData);
|
||||||
reqObject->SetAlignedPointerInInternalField(0, req);
|
|
||||||
|
|
||||||
/* Attach a new V8 object with pointer to us, to us */
|
/* Attach a new V8 object with pointer to us, to us */
|
||||||
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
|
|
||||||
perSocketData->socketPf = new UniquePersistent<Object>;
|
perSocketData->socketPf = new UniquePersistent<Object>;
|
||||||
perSocketData->socketPf->Reset(isolate, wsObject);
|
perSocketData->socketPf->Reset(isolate, wsObject);
|
||||||
|
|
||||||
Local<Function> openLf = Local<Function>::New(isolate, openPf);
|
Local<Function> openLf = Local<Function>::New(isolate, openPf);
|
||||||
if (!openLf->IsUndefined()) {
|
if (!openLf->IsUndefined()) {
|
||||||
Local<Value> argv[] = {wsObject, reqObject};
|
Local<Value> argv[] = {wsObject};
|
||||||
CallJS(isolate, openLf, 2, argv);
|
CallJS(isolate, openLf, 1, argv);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ struct HttpResponseWrapper {
|
|||||||
if (value.isInvalid(args)) {
|
if (value.isInvalid(args)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res->writeHeader(header.getString(),value.getString());
|
res->writeHeader(header.getString(), value.getString());
|
||||||
|
|
||||||
args.GetReturnValue().Set(args.Holder());
|
args.GetReturnValue().Set(args.Holder());
|
||||||
}
|
}
|
||||||
@ -248,6 +248,58 @@ struct HttpResponseWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool SSL>
|
||||||
|
static void res_upgrade(const FunctionCallbackInfo<Value> &args) {
|
||||||
|
Isolate *isolate = args.GetIsolate();
|
||||||
|
auto *res = getHttpResponse<SSL>(args);
|
||||||
|
if (res) {
|
||||||
|
|
||||||
|
printf("Calling upgrade!\n");
|
||||||
|
|
||||||
|
if (args.Length() != 5) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are being passed userData (wsObject) */
|
||||||
|
//Local<Object> wsObject = args[0];
|
||||||
|
//Local<String> secWebSocketKey = args[1];
|
||||||
|
//Local<String> secWebSocketProtocol = args[2];
|
||||||
|
//Local<String> secWebSocketExtensions = args[3];
|
||||||
|
//Local<External> context = args[4];
|
||||||
|
|
||||||
|
|
||||||
|
NativeString secWebSocketKey(args.GetIsolate(), args[1]);
|
||||||
|
if (secWebSocketKey.isInvalid(args)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeString secWebSocketProtocol(args.GetIsolate(), args[2]);
|
||||||
|
if (secWebSocketProtocol.isInvalid(args)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeString secWebSocketExtensions(args.GetIsolate(), args[3]);
|
||||||
|
if (secWebSocketExtensions.isInvalid(args)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *context = (struct us_socket_context_t *) Local<External>::Cast(args[4])->Value();
|
||||||
|
|
||||||
|
invalidateResObject(args);
|
||||||
|
|
||||||
|
UniquePersistent<Object> userData;
|
||||||
|
userData.Reset(isolate, Local<Object>::Cast(args[0]));
|
||||||
|
|
||||||
|
printf("Upgrading now!\n");
|
||||||
|
res->template upgrade<PerSocketData>({
|
||||||
|
.socketPf = &userData
|
||||||
|
}, secWebSocketKey.getString(), secWebSocketProtocol.getString(),
|
||||||
|
secWebSocketExtensions.getString(), context);
|
||||||
|
|
||||||
|
/* Nothing is returned */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <bool SSL>
|
template <bool SSL>
|
||||||
static Local<Object> init(Isolate *isolate) {
|
static Local<Object> init(Isolate *isolate) {
|
||||||
Local<FunctionTemplate> resTemplateLocal = FunctionTemplate::New(isolate);
|
Local<FunctionTemplate> resTemplateLocal = FunctionTemplate::New(isolate);
|
||||||
@ -271,6 +323,7 @@ struct HttpResponseWrapper {
|
|||||||
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onData<SSL>));
|
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onData<SSL>));
|
||||||
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getRemoteAddress<SSL>));
|
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getRemoteAddress<SSL>));
|
||||||
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "cork", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_cork<SSL>));
|
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "cork", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_cork<SSL>));
|
||||||
|
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "upgrade", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_upgrade<SSL>));
|
||||||
|
|
||||||
/* Create our template */
|
/* Create our template */
|
||||||
Local<Object> resObjectLocal = resTemplateLocal->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
Local<Object> resObjectLocal = resTemplateLocal->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
||||||
|
@ -17,6 +17,10 @@ MaybeLocal<Value> CallJS(Isolate *isolate, Local<Function> f, int argc, Local<Va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PerSocketData {
|
||||||
|
UniquePersistent<Object> *socketPf = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct PerContextData {
|
struct PerContextData {
|
||||||
Isolate *isolate;
|
Isolate *isolate;
|
||||||
UniquePersistent<Object> reqTemplate;
|
UniquePersistent<Object> reqTemplate;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit fb7a3303d627812651f7a4f87fe25ea6e74f86b3
|
Subproject commit 9e3a75b19ac560ea03e5064043f25a2857cc7105
|
Loading…
Reference in New Issue
Block a user