Files
uWebSockets.js/src/Utilities.h
2022-09-28 05:52:29 +02:00

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