Skip to content

Commit

Permalink
Wrap cache a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
uNetworkingAB committed Aug 2, 2024
1 parent 54f6830 commit c25e9e3
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 26 deletions.
62 changes: 61 additions & 1 deletion src/AppWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,9 +810,69 @@ void uWS_App(const FunctionCallbackInfo<Value> &args) {

appTemplate->InstanceTemplate()->SetInternalFieldCount(1);


/* All the http methods */
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "get", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
uWS_App_get<APP>(&APP::get, args);

/* Add non-cached variants */
if constexpr (std::is_same<APP, uWS::App>::value) {

if (args.Length() == 3) {
/* Use cached variant */
std::cout << "Registering cached get handler" << std::endl;


APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0);

/* Pattern */
NativeString pattern(args.GetIsolate(), args[0]);
if (pattern.isInvalid(args)) {
return;
}

/* Handler */
Callback checkedCallback(args.GetIsolate(), args[1]);
if (checkedCallback.isInvalid(args)) {
return;
}
UniquePersistent<Function> cb = checkedCallback.getFunction();

/* This function requires perContextData */
PerContextData *perContextData = (PerContextData *) Local<External>::Cast(args.Data())->Value();

app->get(std::string(pattern.getString()), [cb = std::move(cb), perContextData](auto *res, auto *req) {
Isolate *isolate = perContextData->isolate;
HandleScope hs(isolate);


// this needs to be cachedresponse wrapper (for both cached tcp and cached SSL?)
Local<Object> resObject = perContextData->resTemplate[/*getAppTypeIndex<APP>()*/3].Get(isolate)->Clone();
resObject->SetAlignedPointerInInternalField(0, res);

Local<Object> reqObject = perContextData->reqTemplate[std::is_same<APP, uWS::H3App>::value].Get(isolate)->Clone();
reqObject->SetAlignedPointerInInternalField(0, req);

Local<Value> argv[] = {resObject, reqObject};
CallJS(isolate, cb.Get(isolate), 2, 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 */
}, 13);

args.GetReturnValue().Set(args.Holder());


} else {
uWS_App_get<APP>(&uWS::TemplatedApp<false, uWS::CachingApp<false>>::get, args);
}

} else if constexpr (std::is_same<APP, uWS::SSLApp>::value) {
uWS_App_get<APP>(&uWS::TemplatedApp<true, uWS::CachingApp<true>>::get, args);
}

}, args.Data()));

appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "post", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, [](auto &args) {
Expand Down
59 changes: 35 additions & 24 deletions src/HttpResponseWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ using namespace v8;

thread_local int insideCorkCallback = 0;

/* PROTOCOL is 0 = TCP, 1 = TLS, 2 = QUIC, 3 = CACHE */

struct HttpResponseWrapper {

static void assumeCorked() {
Expand All @@ -34,15 +36,17 @@ struct HttpResponseWrapper {
template <int PROTOCOL>
static inline constexpr decltype(auto) getHttpResponse(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = (uWS::HttpResponse<PROTOCOL != 0> *) args.Holder()->GetAlignedPointerFromInternalField(0);
void *res = args.Holder()->GetAlignedPointerFromInternalField(0);
if (!res) {
args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(String::NewFromUtf8(isolate, "uWS.HttpResponse must not be accessed after uWS.HttpResponse.onAborted callback, or after a successful response. See documentation for uWS.HttpResponse and consult the user manual.", NewStringType::kNormal).ToLocalChecked())));
}

if constexpr (PROTOCOL == 2) {
return (uWS::Http3Response *) res;
} else if constexpr (PROTOCOL == 3) {
return (uWS::CachingHttpResponse *) res;
} else {
return res;
return (uWS::HttpResponse<PROTOCOL != 0> *) res;
}
}

Expand Down Expand Up @@ -417,7 +421,7 @@ struct HttpResponseWrapper {
}
}

/* 0 = TCP, 1 = TLS, 2 = QUIC */
/* 0 = TCP, 1 = TLS, 2 = QUIC, 3 = CACHE */
template <int SSL>
static Local<Object> init(Isolate *isolate) {
Local<FunctionTemplate> resTemplateLocal = FunctionTemplate::New(isolate);
Expand All @@ -427,32 +431,39 @@ struct HttpResponseWrapper {
resTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.HttpResponse", NewStringType::kNormal).ToLocalChecked());
} else if (SSL == 2) {
resTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.Http3Response", NewStringType::kNormal).ToLocalChecked());
} else if (SSL == 3) {
resTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.CachedHttpResponse", NewStringType::kNormal).ToLocalChecked());
}
resTemplateLocal->InstanceTemplate()->SetInternalFieldCount(1);

/* Register our functions */
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeStatus", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_writeStatus<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "end", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_end<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "endWithoutBody", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_endWithoutBody<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "tryEnd", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_tryEnd<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "write", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_write<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeHeader", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_writeHeader<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_close<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onWritable", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onWritable<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onAborted", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onAborted<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onData<SSL>));

if constexpr (SSL != 2) {
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getWriteOffset", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getWriteOffset<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, "collect", 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>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddressAsText", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getRemoteAddressAsText<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getProxiedRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getProxiedRemoteAddress<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getProxiedRemoteAddressAsText", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getProxiedRemoteAddressAsText<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "pause", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_pause<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "resume", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_resume<SSL>));

/* Cache has almost nothing wrapped yet */
if constexpr (SSL != 3) {
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeStatus", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_writeStatus<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "endWithoutBody", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_endWithoutBody<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "tryEnd", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_tryEnd<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "write", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_write<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeHeader", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_writeHeader<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_close<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onWritable", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onWritable<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onAborted", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onAborted<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onData<SSL>));

/* QUIC has a lot of functions unimplemented */
if constexpr (SSL != 2) {
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getWriteOffset", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getWriteOffset<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, "collect", 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>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddressAsText", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getRemoteAddressAsText<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getProxiedRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getProxiedRemoteAddress<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getProxiedRemoteAddressAsText", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getProxiedRemoteAddressAsText<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "pause", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_pause<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "resume", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_resume<SSL>));
}
}

/* Create our template */
Expand Down
2 changes: 1 addition & 1 deletion src/Utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct PerSocketData {
struct PerContextData {
Isolate *isolate;
UniquePersistent<Object> reqTemplate[2]; // 0 = non-SSL/SSL, 1 = Http3
UniquePersistent<Object> resTemplate[3]; // 0 = non-SSL, 1 = SSL, 2 = Http3
UniquePersistent<Object> resTemplate[4]; // 0 = non-SSL, 1 = SSL, 2 = Http3
UniquePersistent<Object> wsTemplate[2];

/* We hold all apps until free */
Expand Down
1 change: 1 addition & 0 deletions src/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ PerContextData *Main(Local<Object> exports) {
perContextData->resTemplate[0].Reset(isolate, HttpResponseWrapper::init<0>(isolate));
perContextData->resTemplate[1].Reset(isolate, HttpResponseWrapper::init<1>(isolate));
perContextData->resTemplate[2].Reset(isolate, HttpResponseWrapper::init<2>(isolate));
perContextData->resTemplate[3].Reset(isolate, HttpResponseWrapper::init<3>(isolate));
perContextData->wsTemplate[0].Reset(isolate, WebSocketWrapper::init<0>(isolate));
perContextData->wsTemplate[1].Reset(isolate, WebSocketWrapper::init<1>(isolate));

Expand Down

0 comments on commit c25e9e3

Please sign in to comment.