mirror of
https://github.com/uNetworking/uWebSockets.js.git
synced 2026-04-22 05:00:28 -04:00
167 lines
5.7 KiB
C++
167 lines
5.7 KiB
C++
/*
|
|
* Authored by Alex Hultman, 2018-2021.
|
|
* Intellectual property of third-party.
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ADDON_UTILITIES_H
|
|
#define ADDON_UTILITIES_H
|
|
|
|
#include <v8.h>
|
|
using namespace v8;
|
|
|
|
/* Unfortunately we _have_ to depend on Node.js crap */
|
|
#include <node.h>
|
|
|
|
MaybeLocal<Value> CallJS(Isolate *isolate, Local<Function> f, int argc, Local<Value> *argv) {
|
|
/* Slow path */
|
|
return node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), f, argc, argv, {0, 0});
|
|
}
|
|
|
|
Local<v8::ArrayBuffer> ArrayBuffer_New(Isolate *isolate, void *data, size_t length) {
|
|
std::unique_ptr<BackingStore> backingStore = ArrayBuffer::NewBackingStore(data, length, [](void* data, size_t length, void* deleter_data) {}, nullptr);
|
|
return ArrayBuffer::New(isolate, std::shared_ptr<BackingStore>(backingStore.release()));
|
|
}
|
|
|
|
Local<v8::ArrayBuffer> ArrayBuffer_NewCopy(Isolate *isolate, void *data, size_t length) {
|
|
Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, length);
|
|
memcpy(ab->GetBackingStore()->Data(), data, length);
|
|
return ab;
|
|
}
|
|
|
|
struct PerSocketData {
|
|
UniquePersistent<Object> socketPf;
|
|
};
|
|
|
|
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> wsTemplate[2];
|
|
|
|
/* We hold all apps until free */
|
|
std::vector<std::unique_ptr<uWS::App>> apps;
|
|
std::vector<std::unique_ptr<uWS::SSLApp>> sslApps;
|
|
};
|
|
|
|
template <class APP>
|
|
static constexpr int getAppTypeIndex() {
|
|
/* Returns 1 for SSLApp and 0 for App */
|
|
//return std::is_same<APP, uWS::SSLApp>::value;
|
|
|
|
/* Returns 2 for H3App */
|
|
|
|
if constexpr (std::is_same<APP, uWS::App>::value) {
|
|
return 0;
|
|
} else if constexpr (std::is_same<APP, uWS::SSLApp>::value) {
|
|
return 1;
|
|
} else if constexpr (std::is_same<APP, uWS::H3App>::value) {
|
|
return 2;
|
|
} else {
|
|
// why does this fail?
|
|
//static_assert(false);
|
|
}
|
|
}
|
|
|
|
static inline bool missingArguments(int length, const FunctionCallbackInfo<Value> &args) {
|
|
if (args.Length() < length) {
|
|
std::string message = "Function requires at least ";
|
|
message += std::to_string(length);
|
|
message += " arguments.";
|
|
args.GetReturnValue().Set(args.GetIsolate()->ThrowException(v8::Exception::Error(String::NewFromUtf8(args.GetIsolate(), message.c_str(), NewStringType::kNormal).ToLocalChecked())));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct Callback {
|
|
bool invalid = false;
|
|
UniquePersistent<Function> f;
|
|
Callback(Isolate *isolate, const Local<Value> &value) {
|
|
|
|
if (!value->IsFunction()) {
|
|
invalid = true;
|
|
return;
|
|
}
|
|
|
|
f.Reset(isolate, Local<Function>::Cast(value));
|
|
}
|
|
|
|
bool isInvalid(const FunctionCallbackInfo<Value> &args) {
|
|
if (invalid) {
|
|
args.GetReturnValue().Set(args.GetIsolate()->ThrowException(v8::Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Passed callback is not a valid function.", NewStringType::kNormal).ToLocalChecked())));
|
|
}
|
|
return invalid;
|
|
}
|
|
|
|
UniquePersistent<Function> &&getFunction() {
|
|
return std::move(f);
|
|
}
|
|
};
|
|
|
|
class NativeString {
|
|
char *data;
|
|
size_t length;
|
|
char utf8ValueMemory[sizeof(String::Utf8Value)];
|
|
String::Utf8Value *utf8Value = nullptr;
|
|
bool invalid = false;
|
|
public:
|
|
NativeString(Isolate *isolate, const Local<Value> &value) {
|
|
if (value->IsUndefined()) {
|
|
data = nullptr;
|
|
length = 0;
|
|
} else if (value->IsString()) {
|
|
utf8Value = new (utf8ValueMemory) String::Utf8Value(isolate, value);
|
|
data = (**utf8Value);
|
|
length = utf8Value->length();
|
|
} else if (value->IsTypedArray()) {
|
|
Local<ArrayBufferView> arrayBufferView = Local<ArrayBufferView>::Cast(value);
|
|
auto contents = arrayBufferView->Buffer()->GetBackingStore();
|
|
length = arrayBufferView->ByteLength();
|
|
data = (char *) contents->Data() + arrayBufferView->ByteOffset();
|
|
} else if (value->IsArrayBuffer()) {
|
|
Local<ArrayBuffer> arrayBuffer = Local<ArrayBuffer>::Cast(value);
|
|
auto contents = arrayBuffer->GetBackingStore();
|
|
length = contents->ByteLength();
|
|
data = (char *) contents->Data();
|
|
} else if (value->IsSharedArrayBuffer()) {
|
|
Local<SharedArrayBuffer> arrayBuffer = Local<SharedArrayBuffer>::Cast(value);
|
|
auto contents = arrayBuffer->GetBackingStore();
|
|
length = contents->ByteLength();
|
|
data = (char *) contents->Data();
|
|
} else {
|
|
invalid = true;
|
|
}
|
|
}
|
|
|
|
bool isInvalid(const FunctionCallbackInfo<Value> &args) {
|
|
if (invalid) {
|
|
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())));
|
|
}
|
|
return invalid;
|
|
}
|
|
|
|
std::string_view getString() {
|
|
return {data, length};
|
|
}
|
|
|
|
~NativeString() {
|
|
if (utf8Value) {
|
|
utf8Value->~Utf8Value();
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif
|