Files
LNXRNT/Sources/websocket_v8_bindings.cpp
2026-02-20 23:40:15 -08:00

231 lines
12 KiB
C++

#include "websocket_v8_bindings.h"
#include "websocket_bridge.h"
#include <kinc/log.h>
using namespace v8;
void v8_runt_websocket_server_create(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 3 || !args[0]->IsString() || !args[1]->IsNumber() || !args[2]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_create requires (host, port, maxConnections)").ToLocalChecked()));
return;
}
String::Utf8Value host(isolate, args[0]);
int port = args[1]->Int32Value(isolate->GetCurrentContext()).FromJust();
int maxConnections = args[2]->Int32Value(isolate->GetCurrentContext()).FromJust();
int serverId = runt_websocket_server_create(*host, port, maxConnections);
args.GetReturnValue().Set(Integer::New(isolate, serverId));
}
void v8_runt_websocket_server_start(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 1 || !args[0]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_start requires serverId").ToLocalChecked()));
return;
}
int serverId = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust();
bool success = runt_websocket_server_start(serverId);
args.GetReturnValue().Set(Boolean::New(isolate, success));
}
void v8_runt_websocket_server_stop(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 1 || !args[0]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_stop requires serverId").ToLocalChecked()));
return;
}
int serverId = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust();
runt_websocket_server_stop(serverId);
args.GetReturnValue().Set(Undefined(isolate));
}
void v8_runt_websocket_server_tick(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 1 || !args[0]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_tick requires serverId").ToLocalChecked()));
return;
}
int serverId = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust();
runt_websocket_server_tick(serverId);
args.GetReturnValue().Set(Undefined(isolate));
}
void v8_runt_websocket_server_send_all(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 2 || !args[0]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_send_all requires (serverId, data)").ToLocalChecked()));
return;
}
int serverId = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust();
if (args[1]->IsArrayBuffer()) {
Local<ArrayBuffer> buffer = args[1].As<ArrayBuffer>();
void* data = buffer->GetBackingStore()->Data();
size_t length = buffer->ByteLength();
runt_websocket_server_send_all_binary(serverId, static_cast<const char*>(data), length);
} else if (args[1]->IsArrayBufferView()) {
Local<ArrayBufferView> view = args[1].As<ArrayBufferView>();
Local<ArrayBuffer> buffer = view->Buffer();
void* data = static_cast<char*>(buffer->GetBackingStore()->Data()) + view->ByteOffset();
size_t length = view->ByteLength();
runt_websocket_server_send_all_binary(serverId, static_cast<const char*>(data), length);
} else if (args[1]->IsString()) {
String::Utf8Value data(isolate, args[1]);
runt_websocket_server_send_all(serverId, *data);
} else {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_send_all data must be String or ArrayBuffer").ToLocalChecked()));
return;
}
args.GetReturnValue().Set(Undefined(isolate));
}
//#ifdef WITH_BENCHMARK
//extern "C" {
// void websocket_run_groupchat_test(int rate, int duration);
// void websocket_run_benchmark();
//}
//void v8_websocket_run_test(const FunctionCallbackInfo<Value>& args) {
// Isolate* isolate = args.GetIsolate();
// int rate = 60, duration = 5;
// if (args.Length() >= 1 && args[0]->IsNumber()) {
// rate = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust();
// }
// if (args.Length() >= 2 && args[1]->IsNumber()) {
// duration = args[1]->Int32Value(isolate->GetCurrentContext()).FromJust();
// }
// websocket_run_groupchat_test(rate, duration);
//}
//void v8_websocket_run_benchmark(const FunctionCallbackInfo<Value>& args) {
// websocket_run_benchmark();
//}
//#endif
void v8_runt_websocket_server_send_client(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 3 || !args[0]->IsNumber() || !args[1]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_send_client requires (serverId, clientId, data)").ToLocalChecked()));
return;
}
int serverId = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust();
int clientId = args[1]->Int32Value(isolate->GetCurrentContext()).FromJust();
if (args[2]->IsArrayBuffer()) {
Local<ArrayBuffer> buffer = args[2].As<ArrayBuffer>();
void* data = buffer->GetBackingStore()->Data();
size_t length = buffer->ByteLength();
runt_websocket_server_send_client_binary(serverId, clientId, static_cast<const char*>(data), length);
} else if (args[2]->IsArrayBufferView()) {
Local<ArrayBufferView> view = args[2].As<ArrayBufferView>();
Local<ArrayBuffer> buffer = view->Buffer();
void* data = static_cast<char*>(buffer->GetBackingStore()->Data()) + view->ByteOffset();
size_t length = view->ByteLength();
runt_websocket_server_send_client_binary(serverId, clientId, static_cast<const char*>(data), length);
} else if (args[2]->IsString()) {
String::Utf8Value data(isolate, args[2]);
runt_websocket_server_send_client(serverId, clientId, *data);
} else {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "runt_websocket_server_send_client data must be String or ArrayBuffer").ToLocalChecked()));
return;
}
args.GetReturnValue().Set(Undefined(isolate));
}
void bind_websocket_bridge(Isolate* isolate, const Global<Context>& context) {
// TODO: thread locking
Locker locker{isolate};
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<Context> current_context = Local<Context>::New(isolate, context);
Context::Scope context_scope(current_context);
Local<Object> global = current_context->Global();
Local<Object> runt_obj;
Local<Value> existing_runt = global->Get(current_context, String::NewFromUtf8(isolate, "RunT").ToLocalChecked()).ToLocalChecked();
if (existing_runt->IsObject()) {
runt_obj = existing_runt->ToObject(current_context).ToLocalChecked();
} else {
runt_obj = Object::New(isolate);
global->Set(current_context, String::NewFromUtf8(isolate, "RunT").ToLocalChecked(), runt_obj);
}
runt_obj->Set(current_context, String::NewFromUtf8(isolate, "websocketServerCreate").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_create).ToLocalChecked());
runt_obj->Set(current_context, String::NewFromUtf8(isolate, "websocketServerStart").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_start).ToLocalChecked());
runt_obj->Set(current_context, String::NewFromUtf8(isolate, "websocketServerStop").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_stop).ToLocalChecked());
runt_obj->Set(current_context, String::NewFromUtf8(isolate, "websocketServerTick").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_tick).ToLocalChecked());
runt_obj->Set(current_context, String::NewFromUtf8(isolate, "websocketServerSendAll").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_send_all).ToLocalChecked());
runt_obj->Set(current_context, String::NewFromUtf8(isolate, "websocketServerSendClient").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_send_client).ToLocalChecked());
// uWS compatibility aliases
//runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerCreate").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_create).ToLocalChecked());
//runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerDestroy").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_stop).ToLocalChecked());
//runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerSend").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_send_all).ToLocalChecked());
// runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerTick").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_tick).ToLocalChecked());
//runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerSetOnConnection").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_start).ToLocalChecked());
//runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerSetOnMessage").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_start).ToLocalChecked());
//runt_obj->Set(current_context, String::NewFromUtf8(isolate, "uwsWebsocketServerSetOnDisconnection").ToLocalChecked(),
// Function::New(current_context, v8_runt_websocket_server_stop).ToLocalChecked());
global->Set(current_context, String::NewFromUtf8(isolate, "runt_websocket_server_create").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_create).ToLocalChecked());
global->Set(current_context, String::NewFromUtf8(isolate, "runt_websocket_server_start").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_start).ToLocalChecked());
global->Set(current_context, String::NewFromUtf8(isolate, "runt_websocket_server_stop").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_stop).ToLocalChecked());
global->Set(current_context, String::NewFromUtf8(isolate, "runt_websocket_server_tick").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_tick).ToLocalChecked());
global->Set(current_context, String::NewFromUtf8(isolate, "runt_websocket_server_send_all").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_send_all).ToLocalChecked());
global->Set(current_context, String::NewFromUtf8(isolate, "runt_websocket_server_send_client").ToLocalChecked(),
Function::New(current_context, v8_runt_websocket_server_send_client).ToLocalChecked());
//#ifdef WITH_BENCHMARK
// global->Set(current_context, String::NewFromUtf8(isolate, "websocket_run_test").ToLocalChecked(),
// Function::New(current_context, v8_websocket_run_test).ToLocalChecked());
// global->Set(current_context, String::NewFromUtf8(isolate, "websocket_run_benchmark").ToLocalChecked(),
// Function::New(current_context, v8_websocket_run_benchmark).ToLocalChecked());
//#endif
}