enet and mailboxes now take strings or array buffers
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m3s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m3s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
This commit is contained in:
@@ -528,46 +528,30 @@ var enet = use('enet')
|
||||
var util = use('util')
|
||||
var math = use('math')
|
||||
var crypto = use('crypto')
|
||||
var nota = use('nota')
|
||||
|
||||
var HEADER = Symbol()
|
||||
var ACTORDATA = Symbol()
|
||||
var PEER = Symbol()
|
||||
|
||||
var ar = 1 // seconds before reclamation
|
||||
|
||||
function print_actor()
|
||||
{
|
||||
return json.encode(this[ACTORDATA], 1);
|
||||
function print_actor() {
|
||||
return json.encode(this.__ACTORDATA__, 1)
|
||||
}
|
||||
|
||||
function json_actor() {
|
||||
var ret = this[ACTORDATA]
|
||||
|
||||
// The idea here is that, if we're serializing an actor, it's being sent over the wire
|
||||
if (!ret.portal)
|
||||
ret.portal = local_portal
|
||||
|
||||
return ret
|
||||
if (!this.__ACTORDATA__.portal) this.__ACTORDATA__.portal = local_portal
|
||||
return this
|
||||
}
|
||||
|
||||
function create_actor(data) {
|
||||
return {
|
||||
[ACTORDATA]: data,
|
||||
__ACTORDATA__: data,
|
||||
toString: print_actor,
|
||||
toJSON: json_actor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
When an actor object like $_ is passed to another machine or function, it appears like this
|
||||
[ACTORDATA]: {
|
||||
id: local to the machine. Currently, the local port it is listening on
|
||||
address: the IP address of the portal that connects it, if set
|
||||
port: the public port of the portal that connects it, if set
|
||||
}
|
||||
*/
|
||||
|
||||
var $_ = {
|
||||
toString: print_actor,
|
||||
toJSON: json_actor
|
||||
@@ -587,10 +571,7 @@ globalThis.$_ = $_
|
||||
var receive_fn = undefined
|
||||
var greeters = {}
|
||||
|
||||
$_.is_actor = function(actor) {
|
||||
if (actor[ACTORDATA]) return true
|
||||
return false
|
||||
}
|
||||
$_.is_actor = function(actor) { return !!actor.__ACTORDATA__ }
|
||||
|
||||
function peer_connection(peer) {
|
||||
return {
|
||||
@@ -616,12 +597,12 @@ function peer_connection(peer) {
|
||||
}
|
||||
|
||||
$_.connection = function(callback, actor, config) {
|
||||
var peer = peers[actor[ACTORDATA].id]
|
||||
var peer = peers[actor.__ACTORDATA__.id]
|
||||
if (peer) {
|
||||
callback(peer_connection(peer))
|
||||
return
|
||||
}
|
||||
if (os.mailbox_exist(actor[ACTORDATA].id)) {
|
||||
if (os.mailbox_exist(actor.__ACTORDATA__.id)) {
|
||||
callback({type:"local"})
|
||||
return
|
||||
}
|
||||
@@ -635,7 +616,6 @@ var portal = undefined
|
||||
var portal_fn
|
||||
var local_portal
|
||||
|
||||
// The portal function is the only way an actor object can leave the machine; so on its way out, it needs tagged with the portal data
|
||||
$_.portal = function(fn, port) {
|
||||
if (portal) throw new Error(`Already started a portal listening on ${portal.port}`)
|
||||
console.log(`starting a portal on port ${port}`)
|
||||
@@ -653,7 +633,7 @@ function handle_host(e) {
|
||||
peers[`${e.peer.address}:${e.peer.port}`] = e.peer
|
||||
var queue = peer_queue.get(e.peer)
|
||||
if (queue) {
|
||||
for (var msg of queue) e.peer.send(msg)
|
||||
for (var msg of queue) e.peer.send(nota.encode(msg))
|
||||
console.log(`sent ${json.encode(msg)} out of queue`)
|
||||
peer_queue.delete(e.peer)
|
||||
}
|
||||
@@ -671,7 +651,7 @@ function handle_host(e) {
|
||||
|
||||
var contactor = undefined
|
||||
$_.contact = function(callback, record) {
|
||||
var sendto = { [ACTORDATA]: {address: record.address, port: record.port} }
|
||||
var sendto = { __ACTORDATA__: {address: record.address, port: record.port} }
|
||||
$_.send(create_actor({
|
||||
address: record.address,
|
||||
port: record.port
|
||||
@@ -695,7 +675,7 @@ $_.start[prosperon.DOC] = "The start function creates a new actor..."
|
||||
|
||||
$_.stop = function(actor) {
|
||||
if (!actor) destroyself()
|
||||
if (!underlings.has(actor[ACTORDATA].id))
|
||||
if (!underlings.has(actor.__ACTORDATA__.id))
|
||||
throw new Error('Can only call stop on an underling or self.')
|
||||
|
||||
actor_send(actor, {type:"stop", id: prosperon.id})
|
||||
@@ -724,36 +704,36 @@ $_.delay[prosperon.DOC] = "used to schedule the invocation of a function..."
|
||||
var couplings = new Set()
|
||||
|
||||
$_.couple = function(actor) {
|
||||
console.log(`coupled to ${actor[ACTORDATA].id}`)
|
||||
couplings.add(actor[ACTORDATA].id)
|
||||
console.log(`coupled to ${actor.__ACTORDATA__.id}`)
|
||||
couplings.add(actor.__ACTORDATA__.id)
|
||||
}
|
||||
$_.couple[prosperon.DOC] = "causes this actor to stop when another actor stops."
|
||||
|
||||
function actor_send(actor, message) {
|
||||
if (!$_.is_actor(actor)) throw new Error(`Must send to an actor object. Attempted send to ${json.encode(actor)}`)
|
||||
if (typeof message !== 'object') throw new Error('Must send an object record.')
|
||||
if (receive_fn && actor[ACTORDATA].id === prosperon.id) {
|
||||
if (receive_fn && actor.__ACTORDATA__.id === prosperon.id) {
|
||||
receive_fn(message.data)
|
||||
return
|
||||
}
|
||||
|
||||
if (actor[ACTORDATA].id && os.mailbox_exist(actor[ACTORDATA].id)) {
|
||||
os.mailbox_push(actor[ACTORDATA].id, message)
|
||||
if (actor.__ACTORDATA__.id && os.mailbox_exist(actor.__ACTORDATA__.id)) {
|
||||
os.mailbox_push(actor.__ACTORDATA__.id, nota.encode(message))
|
||||
return
|
||||
}
|
||||
|
||||
if (actor[ACTORDATA].address) {
|
||||
if (actor[ACTORDATA].id) message.target = actor[ACTORDATA].id
|
||||
if (actor.__ACTORDATA__.address) {
|
||||
if (actor.__ACTORDATA__.id) message.target = actor.__ACTORDATA__.id
|
||||
else message.type = "contact"
|
||||
var peer = peers[actor[ACTORDATA].address + ":" + actor[ACTORDATA].port]
|
||||
var peer = peers[actor.__ACTORDATA__.address + ":" + actor.__ACTORDATA__.port]
|
||||
if (!peer) {
|
||||
if (!contactor && !portal) {
|
||||
console.log(`creating a contactor ...`)
|
||||
contactor = enet.create_host()
|
||||
}
|
||||
peer = (contactor || portal).connect(actor[ACTORDATA].address, actor[ACTORDATA].port)
|
||||
peer = (contactor || portal).connect(actor.__ACTORDATA__.address, actor.__ACTORDATA__.port)
|
||||
peer_queue.set(peer, [message])
|
||||
} else peer.send(message)
|
||||
} else peer.send(nota.encode(message))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -766,15 +746,13 @@ var contact_replies = new WeakMap()
|
||||
|
||||
$_.send = function(actor, message, reply) {
|
||||
if (typeof message !== 'object') throw new Error('Message must be an object')
|
||||
|
||||
var send = {type:"user", data: message}
|
||||
|
||||
if (actor[HEADER]) { // This means it's a response message
|
||||
if (actor[HEADER]) {
|
||||
var header = actor[HEADER]
|
||||
console.log(`replying to a message: ${json.encode(header)}`)
|
||||
// Only set id if ACTORDATA exists, otherwise create it
|
||||
if (!actor[ACTORDATA]) actor[ACTORDATA] = {}
|
||||
actor[ACTORDATA].id = header.replycc
|
||||
if (!actor.__ACTORDATA__) actor.__ACTORDATA__ = {}
|
||||
actor.__ACTORDATA__.id = header.replycc
|
||||
send.return = header.reply
|
||||
}
|
||||
|
||||
@@ -795,13 +773,13 @@ cmd.process(prosperon.argv)
|
||||
if (!prosperon.args.id) prosperon.id = util.guid()
|
||||
else prosperon.id = prosperon.args.id
|
||||
|
||||
$_[ACTORDATA] = {id: prosperon.id}
|
||||
$_.__ACTORDATA__ = {id: prosperon.id}
|
||||
$_.toJSON = json_actor
|
||||
$_.toSring = print_actor
|
||||
|
||||
if (prosperon.args.overling) overling = { [ACTORDATA]: {id: prosperon.args.overling} }
|
||||
if (prosperon.args.root) root = { [ACTORDATA]: {id: prosperon.args.root} }
|
||||
else root = { [ACTORDATA]: {id: prosperon.id} }
|
||||
if (prosperon.args.overling) overling = { __ACTORDATA__: {id: prosperon.args.overling} }
|
||||
if (prosperon.args.root) root = { __ACTORDATA__: {id: prosperon.args.root} }
|
||||
else root = { __ACTORDATA__: {id: prosperon.id} }
|
||||
|
||||
os.mailbox_start(prosperon.id)
|
||||
|
||||
@@ -827,9 +805,11 @@ function handle_actor_disconnect(id) {
|
||||
}
|
||||
|
||||
function handle_message(msg) {
|
||||
msg = nota.decode(msg)
|
||||
|
||||
if (msg.target) {
|
||||
if (msg.target !== prosperon.id) {
|
||||
os.mailbox_push(msg.target, msg)
|
||||
os.mailbox_push(msg.target, nota.encode(msg))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -841,7 +821,7 @@ function handle_message(msg) {
|
||||
delete msg.data
|
||||
letter[HEADER] = msg
|
||||
if (msg.return) {
|
||||
console.log(`Received a message for the return id ${msg.return}`);
|
||||
console.log(`Received a message for the return id ${msg.return}`)
|
||||
var fn = replies[msg.return]
|
||||
if (!fn) throw new Error(`Could not find return function for message ${msg.return}`)
|
||||
fn(letter)
|
||||
@@ -852,7 +832,7 @@ function handle_message(msg) {
|
||||
break
|
||||
|
||||
case "stop":
|
||||
if (msg.id !== overling[ACTORDATA].id)
|
||||
if (msg.id !== overling.__ACTORDATA__.id)
|
||||
throw new Error(`Got a message from an actor ${msg.id} to stop...`)
|
||||
|
||||
destroyself()
|
||||
|
||||
@@ -7156,26 +7156,35 @@ static struct { char *key; mailbox value; } *mailboxes = NULL;
|
||||
static SDL_Mutex *mailboxes_mutex = NULL;
|
||||
|
||||
JSC_CCALL(os_mailbox_push,
|
||||
if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and an array buffer.");
|
||||
if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and a message");
|
||||
char *id = JS_ToCString(js, argv[0]);
|
||||
void *nota = value2nota(js, argv[1]);
|
||||
void *data = NULL;
|
||||
if (JS_IsString(argv[1]))
|
||||
data = (void*)JS_ToCString(js, argv[1]);
|
||||
else if (JS_IsArrayBuffer(js, argv[1])) {
|
||||
size_t size;
|
||||
uint8_t *buf = JS_GetArrayBuffer(js, &size, argv[1]);
|
||||
data = malloc(size + 1);
|
||||
memcpy(data, buf, size);
|
||||
((char*)data)[size] = 0;
|
||||
} else return JS_ThrowTypeError(js, "Message must be string or ArrayBuffer");
|
||||
|
||||
int mailbox_index = shgeti(mailboxes, id);
|
||||
if (mailbox_index == -1) {
|
||||
if (!JS_IsString(argv[1])) free(data);
|
||||
JS_FreeCString(js, id);
|
||||
return JS_ThrowInternalError(js, "No mailbox found for given ID.");
|
||||
return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
||||
}
|
||||
|
||||
mailbox *mb = &mailboxes[mailbox_index].value;
|
||||
|
||||
SDL_LockMutex(mb->mutex);
|
||||
arrput(mb->messages, nota);
|
||||
arrput(mb->messages, data);
|
||||
SDL_UnlockMutex(mb->mutex);
|
||||
|
||||
JS_FreeCString(js, id);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_mailbox_service, // grab all from our mailbox and
|
||||
JSC_CCALL(os_mailbox_service,
|
||||
char *id = JS_ToCString(js, argv[0]);
|
||||
JSValue fn = JS_DupValue(js, argv[1]);
|
||||
|
||||
@@ -7183,11 +7192,10 @@ JSC_CCALL(os_mailbox_service, // grab all from our mailbox and
|
||||
if (mb_index == -1) {
|
||||
JS_FreeCString(js, id);
|
||||
JS_FreeValue(js, fn);
|
||||
return JS_ThrowInternalError(js, "No mailbox found for given ID.");
|
||||
return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
||||
}
|
||||
|
||||
mailbox *mb = &mailboxes[mb_index].value;
|
||||
|
||||
void **temp = NULL;
|
||||
SDL_LockMutex(mb->mutex);
|
||||
int count = arrlen(mb->messages);
|
||||
@@ -7196,16 +7204,15 @@ JSC_CCALL(os_mailbox_service, // grab all from our mailbox and
|
||||
memcpy(temp, mb->messages, sizeof(void*) * count);
|
||||
arrsetlen(mb->messages, 0);
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(mb->mutex);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
void *nota = temp[i];
|
||||
JSValue obj = nota2value(js, nota);
|
||||
free(nota);
|
||||
JSValue call = JS_Call(js, fn, JS_UNDEFINED, 1, &obj); // todo: need to free obj here?
|
||||
void *data = temp[i];
|
||||
JSValue arg = JS_IsString(argv[1]) ? JS_NewString(js, (char*)data) : JS_NewArrayBufferCopy(js, data, strlen(data));
|
||||
JSValue call = JS_Call(js, fn, JS_UNDEFINED, 1, &arg);
|
||||
uncaught_exception(js, call);
|
||||
JS_FreeValue(js,obj);
|
||||
JS_FreeValue(js, arg);
|
||||
free(data);
|
||||
}
|
||||
arrfree(temp);
|
||||
|
||||
@@ -7215,18 +7222,17 @@ JSC_CCALL(os_mailbox_service, // grab all from our mailbox and
|
||||
|
||||
JSC_CCALL(os_mailbox_exist,
|
||||
char *id = JS_ToCString(js, argv[0]);
|
||||
|
||||
return JS_NewBool(js, shgeti(mailboxes,id) != -1);
|
||||
bool exists = shgeti(mailboxes, id) != -1;
|
||||
JS_FreeCString(js, id);
|
||||
return JS_NewBool(js, exists);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_mailbox_start,
|
||||
char *id = JS_ToCString(js, argv[0]);
|
||||
|
||||
mailbox mb;
|
||||
mb.mutex = SDL_CreateMutex();
|
||||
mb.messages = NULL;
|
||||
if (!mailboxes_mutex)
|
||||
mailboxes_mutex = SDL_CreateMutex();
|
||||
if (!mailboxes_mutex) mailboxes_mutex = SDL_CreateMutex();
|
||||
|
||||
SDL_LockMutex(mailboxes_mutex);
|
||||
shput(mailboxes, id, mb);
|
||||
|
||||
@@ -13,11 +13,10 @@ static JSClassID enet_host_id;
|
||||
static JSClassID enet_peer_class_id;
|
||||
|
||||
/* Finalizers */
|
||||
static void js_enet_host_finalizer(JSRuntime *rt, JSValue val) {
|
||||
static void js_enet_host_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(val, enet_host_id);
|
||||
if (host) {
|
||||
enet_host_destroy(host);
|
||||
}
|
||||
if (host) enet_host_destroy(host);
|
||||
}
|
||||
|
||||
static void js_enet_peer_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
|
||||
@@ -26,28 +25,28 @@ static void js_enet_peer_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark
|
||||
JS_MarkValue(rt, *(JSValue*)peer->data, mark_func);
|
||||
}
|
||||
|
||||
static void js_enet_peer_finalizer(JSRuntime *rt, JSValue val) {
|
||||
static void js_enet_peer_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(val, enet_peer_class_id);
|
||||
JS_FreeValueRT(rt, *(JSValue*)peer->data);
|
||||
free(peer->data);
|
||||
}
|
||||
|
||||
/* ENet init/deinit */
|
||||
static JSValue js_enet_initialize(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
if (enet_initialize() != 0) {
|
||||
return JS_ThrowInternalError(ctx, "Error initializing ENet.");
|
||||
}
|
||||
static JSValue js_enet_initialize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
if (enet_initialize() != 0) return JS_ThrowInternalError(ctx, "Error initializing ENet");
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
enet_deinitialize();
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host;
|
||||
ENetAddress address;
|
||||
ENetAddress *send = &address;
|
||||
@@ -127,20 +126,13 @@ static JSValue peer_get_value(JSContext *ctx, ENetPeer *peer)
|
||||
}
|
||||
|
||||
/* Host service: poll for events */
|
||||
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
|
||||
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
||||
if (!host) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!host) return JS_EXCEPTION;
|
||||
|
||||
// Expect a callback function
|
||||
if (argc < 1 || !JS_IsFunction(ctx, argv[0])) {
|
||||
return JS_ThrowTypeError(ctx, "Expected a callback function as first argument.");
|
||||
}
|
||||
JSValue callback = argv[0];
|
||||
JS_DupValue(ctx, callback);
|
||||
if (argc < 1 || !JS_IsFunction(ctx, argv[0])) return JS_ThrowTypeError(ctx, "Expected a callback function as first argument");
|
||||
JSValue callback = JS_DupValue(ctx, argv[0]);
|
||||
|
||||
double secs;
|
||||
JS_ToFloat64(ctx, &secs, argv[1]);
|
||||
@@ -151,48 +143,20 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
JS_SetPropertyStr(ctx, event_obj, "peer", peer_get_value(ctx, event.peer));
|
||||
|
||||
switch (event.type) {
|
||||
case ENET_EVENT_TYPE_CONNECT: {
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "connect"));
|
||||
break;
|
||||
}
|
||||
case ENET_EVENT_TYPE_RECEIVE: {
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "receive"));
|
||||
JS_SetPropertyStr(ctx, event_obj, "channelID", JS_NewInt32(ctx, event.channelID));
|
||||
|
||||
char *tmp = js_mallocz(ctx, event.packet->dataLength+1);
|
||||
memcpy(tmp, event.packet->data, event.packet->dataLength);
|
||||
tmp[event.packet->dataLength] = '\0';
|
||||
|
||||
// We expect strictly a JSON object
|
||||
JSValue packet_data = JS_ParseJSON(ctx,
|
||||
tmp,
|
||||
event.packet->dataLength,
|
||||
"<enet-packet>");
|
||||
|
||||
js_free(ctx,tmp);
|
||||
|
||||
if (JS_IsException(packet_data)) {
|
||||
// Malformed JSON -> throw error, abort
|
||||
printf("INVALID JSON!\n");
|
||||
enet_packet_destroy(event.packet);
|
||||
JS_FreeValue(ctx, event_obj);
|
||||
uncaught_exception(ctx, packet_data);
|
||||
continue;
|
||||
// Pass raw data as string or ArrayBuffer
|
||||
if (event.packet->dataLength > 0) {
|
||||
JSValue data_val = JS_NewArrayBufferCopy(ctx, event.packet->data, event.packet->dataLength);
|
||||
JS_SetPropertyStr(ctx, event_obj, "data", data_val);
|
||||
}
|
||||
|
||||
if (!JS_IsObject(packet_data)) {
|
||||
// It might be a string/number/array/... -> we want only a plain object
|
||||
JS_FreeValue(ctx, event_obj);
|
||||
JS_FreeValue(ctx, packet_data);
|
||||
enet_packet_destroy(event.packet);
|
||||
uncaught_exception(ctx, JS_ThrowTypeError(ctx, "Received data is not an object (must send a plain object)."));
|
||||
continue;
|
||||
}
|
||||
|
||||
JS_SetPropertyStr(ctx, event_obj, "data", packet_data);
|
||||
enet_packet_destroy(event.packet);
|
||||
break;
|
||||
}
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "disconnect"));
|
||||
break;
|
||||
@@ -201,7 +165,6 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
break;
|
||||
}
|
||||
|
||||
// Invoke callback
|
||||
uncaught_exception(ctx, JS_Call(ctx, callback, JS_UNDEFINED, 1, &event_obj));
|
||||
JS_FreeValue(ctx, event_obj);
|
||||
}
|
||||
@@ -211,21 +174,15 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
}
|
||||
|
||||
/* Host connect: client -> connect to server */
|
||||
static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
||||
if (!host) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!host) return JS_EXCEPTION;
|
||||
|
||||
if (argc < 2) {
|
||||
return JS_ThrowTypeError(ctx, "Expected 2 arguments: hostname, port.");
|
||||
}
|
||||
if (argc < 2) return JS_ThrowTypeError(ctx, "Expected 2 arguments: hostname, port");
|
||||
|
||||
const char *hostname = JS_ToCString(ctx, argv[0]);
|
||||
if (!hostname) {
|
||||
return JS_EXCEPTION; // out of memory or conversion error
|
||||
}
|
||||
if (!hostname) return JS_EXCEPTION;
|
||||
int port;
|
||||
JS_ToInt32(ctx, &port, argv[1]);
|
||||
|
||||
@@ -235,62 +192,46 @@ static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val,
|
||||
address.port = port;
|
||||
|
||||
ENetPeer *peer = enet_host_connect(host, &address, 2, 0);
|
||||
if (!peer) {
|
||||
return JS_ThrowInternalError(ctx, "No available peers for initiating an ENet connection.");
|
||||
}
|
||||
if (!peer) return JS_ThrowInternalError(ctx, "No available peers for initiating an ENet connection");
|
||||
|
||||
return peer_get_value(ctx, peer);
|
||||
}
|
||||
|
||||
/* Flush queued packets */
|
||||
static JSValue js_enet_host_flush(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_host_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
||||
if (!host) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!host) return JS_EXCEPTION;
|
||||
enet_host_flush(host);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
/* Broadcast a plain object */
|
||||
static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
/* Broadcast a string or ArrayBuffer */
|
||||
static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
||||
if (!host) {
|
||||
return JS_EXCEPTION;
|
||||
if (!host) return JS_EXCEPTION;
|
||||
|
||||
if (argc < 1) return JS_ThrowTypeError(ctx, "Expected a string or ArrayBuffer to broadcast");
|
||||
|
||||
const char *data_str = NULL;
|
||||
size_t data_len = 0;
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
if (JS_IsString(argv[0])) {
|
||||
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]);
|
||||
if (!data_str) return JS_EXCEPTION;
|
||||
} else if (JS_IsArrayBuffer(ctx,argv[0])) {
|
||||
buf = JS_GetArrayBuffer(ctx, &data_len, argv[0]);
|
||||
if (!buf) return JS_EXCEPTION;
|
||||
} else {
|
||||
return JS_ThrowTypeError(ctx, "broadcast() only accepts a string or ArrayBuffer");
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
return JS_ThrowTypeError(ctx, "Expected an object to broadcast.");
|
||||
}
|
||||
// Must be a JavaScript object
|
||||
if (!JS_IsObject(argv[0])) {
|
||||
return JS_ThrowTypeError(ctx,
|
||||
"broadcast() only accepts a plain JS object, not strings/numbers.");
|
||||
}
|
||||
ENetPacket *packet = enet_packet_create(data_str ? data_str : buf, data_len, ENET_PACKET_FLAG_RELIABLE);
|
||||
if (data_str) JS_FreeCString(ctx, data_str);
|
||||
if (!packet) return JS_ThrowInternalError(ctx, "Failed to create ENet packet");
|
||||
|
||||
// JSON.stringify the object
|
||||
JSValue json_data = JS_JSONStringify(ctx, argv[0], JS_NULL, JS_NULL);
|
||||
if (JS_IsException(json_data)) {
|
||||
return JS_ThrowTypeError(ctx,
|
||||
"Failed to stringify object (circular ref or non-serializable).");
|
||||
}
|
||||
|
||||
size_t data_len;
|
||||
const char *data_str = JS_ToCStringLen(ctx, &data_len, json_data);
|
||||
JS_FreeValue(ctx, json_data);
|
||||
|
||||
if (!data_str) {
|
||||
return JS_EXCEPTION; // out of memory
|
||||
}
|
||||
|
||||
ENetPacket *packet = enet_packet_create(data_str, data_len, ENET_PACKET_FLAG_RELIABLE);
|
||||
JS_FreeCString(ctx, data_str);
|
||||
|
||||
if (!packet) {
|
||||
return JS_ThrowInternalError(ctx, "Failed to create ENet packet.");
|
||||
}
|
||||
enet_host_broadcast(host, 0, packet);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
@@ -308,148 +249,109 @@ static JSValue js_enet_host_get_address(JSContext *js, JSValueConst self, int ar
|
||||
if (!me) return JS_EXCEPTION;
|
||||
|
||||
uint32_t host = ntohl(me->address.host);
|
||||
if (host == 0x7F000001) return JS_NewString(js, "localhost");
|
||||
|
||||
if (host == 0x7F000001)
|
||||
return JS_NewString(js, "localhost");
|
||||
|
||||
char ip_str[16]; // Enough space for "255.255.255.255" + null terminator
|
||||
char ip_str[16];
|
||||
snprintf(ip_str, sizeof(ip_str), "%u.%u.%u.%u",
|
||||
(host >> 24) & 0xFF,
|
||||
(host >> 16) & 0xFF,
|
||||
(host >> 8) & 0xFF,
|
||||
host & 0xFF);
|
||||
|
||||
return JS_NewString(js, ip_str);
|
||||
}
|
||||
|
||||
/* Peer-level operations */
|
||||
static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
enet_peer_disconnect(peer, 0);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
/* Peer send must only accept an object */
|
||||
static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
/* Peer send must only accept string or ArrayBuffer */
|
||||
static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
|
||||
if (argc < 1) return JS_ThrowTypeError(ctx, "Expected a string or ArrayBuffer to send");
|
||||
|
||||
const char *data_str = NULL;
|
||||
size_t data_len = 0;
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
if (JS_IsString(argv[0])) {
|
||||
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]);
|
||||
if (!data_str) return JS_EXCEPTION;
|
||||
} else if (JS_IsArrayBuffer(ctx,argv[0])) {
|
||||
buf = JS_GetArrayBuffer(ctx, &data_len, argv[0]);
|
||||
if (!buf) return JS_EXCEPTION;
|
||||
} else {
|
||||
return JS_ThrowTypeError(ctx, "send() only accepts a string or ArrayBuffer");
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
return JS_ThrowTypeError(ctx, "Expected an object to send.");
|
||||
}
|
||||
if (!JS_IsObject(argv[0])) {
|
||||
return JS_ThrowTypeError(ctx,
|
||||
"peer.send() only accepts a plain JS object, not strings/numbers.");
|
||||
}
|
||||
ENetPacket *packet = enet_packet_create(data_str ? data_str : buf, data_len, ENET_PACKET_FLAG_RELIABLE);
|
||||
if (data_str) JS_FreeCString(ctx, data_str);
|
||||
if (!packet) return JS_ThrowInternalError(ctx, "Failed to create ENet packet");
|
||||
|
||||
JSValue json_data = JS_JSONStringify(ctx, argv[0], JS_NULL, JS_NULL);
|
||||
if (JS_IsException(json_data)) {
|
||||
return JS_ThrowTypeError(ctx,
|
||||
"Failed to stringify object (circular ref or non-serializable).");
|
||||
}
|
||||
|
||||
size_t data_len;
|
||||
const char *data_str = JS_ToCStringLen(ctx, &data_len, json_data);
|
||||
JS_FreeValue(ctx, json_data);
|
||||
if (!data_str) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
// Create packet
|
||||
ENetPacket *packet = enet_packet_create(data_str, data_len, ENET_PACKET_FLAG_RELIABLE);
|
||||
JS_FreeCString(ctx, data_str);
|
||||
if (!packet) {
|
||||
return JS_ThrowInternalError(ctx, "Failed to create ENet packet.");
|
||||
}
|
||||
|
||||
if (enet_peer_send(peer, 0, packet) < 0) {
|
||||
return JS_ThrowInternalError(ctx, "unable to send packet. send returned error.");
|
||||
}
|
||||
if (enet_peer_send(peer, 0, packet) < 0) return JS_ThrowInternalError(ctx, "Unable to send packet");
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_peer_disconnect_now(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_disconnect_now(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
enet_peer_disconnect_now(peer, 0);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_peer_disconnect_later(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_disconnect_later(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
enet_peer_disconnect_later(peer, 0);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_peer_reset(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_reset(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
enet_peer_reset(peer);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_peer_ping(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_ping(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
enet_peer_ping(peer);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_peer_throttle_configure(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_throttle_configure(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
|
||||
int interval, acceleration, deceleration;
|
||||
if (argc < 3 ||
|
||||
JS_ToInt32(ctx, &interval, argv[0]) ||
|
||||
JS_ToInt32(ctx, &acceleration, argv[1]) ||
|
||||
JS_ToInt32(ctx, &deceleration, argv[2])) {
|
||||
return JS_ThrowTypeError(ctx,
|
||||
"Expected 3 int arguments: interval, acceleration, deceleration");
|
||||
}
|
||||
if (argc < 3 || JS_ToInt32(ctx, &interval, argv[0]) || JS_ToInt32(ctx, &acceleration, argv[1]) || JS_ToInt32(ctx, &deceleration, argv[2]))
|
||||
return JS_ThrowTypeError(ctx, "Expected 3 int arguments: interval, acceleration, deceleration");
|
||||
|
||||
enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_enet_peer_timeout(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_timeout(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
|
||||
int timeout_limit, timeout_min, timeout_max;
|
||||
if (argc < 3 ||
|
||||
JS_ToInt32(ctx, &timeout_limit, argv[0]) ||
|
||||
JS_ToInt32(ctx, &timeout_min, argv[1]) ||
|
||||
JS_ToInt32(ctx, &timeout_max, argv[2])) {
|
||||
return JS_ThrowTypeError(ctx,
|
||||
"Expected 3 integer arguments: timeout_limit, timeout_min, timeout_max");
|
||||
}
|
||||
if (argc < 3 || JS_ToInt32(ctx, &timeout_limit, argv[0]) || JS_ToInt32(ctx, &timeout_min, argv[1]) || JS_ToInt32(ctx, &timeout_max, argv[2]))
|
||||
return JS_ThrowTypeError(ctx, "Expected 3 integer arguments: timeout_limit, timeout_min, timeout_max");
|
||||
|
||||
enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max);
|
||||
return JS_UNDEFINED;
|
||||
@@ -471,6 +373,9 @@ JSValue js_enet_resolve_hostname(JSContext *js, JSValue self, int argc, JSValue
|
||||
{
|
||||
char *hostname = JS_ToCString(js, argv[0]);
|
||||
ENetAddress addr;
|
||||
// Note: This function seems incomplete in the original - should it return something?
|
||||
JS_FreeCString(js, hostname);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
/* Function lists */
|
||||
@@ -490,119 +395,90 @@ static const JSCFunctionListEntry js_enet_host_funcs[] = {
|
||||
JS_CGETSET_DEF("address", js_enet_host_get_address, NULL),
|
||||
};
|
||||
|
||||
/* Getter for roundTripTime (rtt) */
|
||||
static JSValue js_enet_peer_get_rtt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
/* Peer getters */
|
||||
static JSValue js_enet_peer_get_rtt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
return JS_NewInt32(ctx, peer->roundTripTime); // RTT in milliseconds
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
return JS_NewInt32(ctx, peer->roundTripTime);
|
||||
}
|
||||
|
||||
/* Getter for incomingBandwidth */
|
||||
static JSValue js_enet_peer_get_incoming_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_get_incoming_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (peer->incomingBandwidth == 0)
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
|
||||
return JS_NewInt32(ctx, peer->incomingBandwidth); // Bytes per second
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
if (peer->incomingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->incomingBandwidth);
|
||||
}
|
||||
|
||||
/* Getter for outgoingBandwidth */
|
||||
static JSValue js_enet_peer_get_outgoing_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_get_outgoing_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (peer->outgoingBandwidth == 0)
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
|
||||
return JS_NewInt32(ctx, peer->outgoingBandwidth); // Bytes per second
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
if (peer->outgoingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->outgoingBandwidth);
|
||||
}
|
||||
|
||||
/* Getter for lastSendTime */
|
||||
static JSValue js_enet_peer_get_last_send_time(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_get_last_send_time(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
return JS_NewInt32(ctx, peer->lastSendTime); // Timestamp in milliseconds
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
return JS_NewInt32(ctx, peer->lastSendTime);
|
||||
}
|
||||
|
||||
/* Getter for lastReceiveTime */
|
||||
static JSValue js_enet_peer_get_last_receive_time(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
static JSValue js_enet_peer_get_last_receive_time(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
return JS_NewInt32(ctx, peer->lastReceiveTime); // Timestamp in milliseconds
|
||||
if (!peer) return JS_EXCEPTION;
|
||||
return JS_NewInt32(ctx, peer->lastReceiveTime);
|
||||
}
|
||||
|
||||
#include <math.h> // Ensure this is included for INFINITY
|
||||
|
||||
/* Getter for mtu */
|
||||
static JSValue js_enet_peer_get_mtu(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_mtu(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
}
|
||||
if (!peer) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->mtu);
|
||||
}
|
||||
|
||||
/* Getter for outgoingDataTotal */
|
||||
static JSValue js_enet_peer_get_outgoing_data_total(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_outgoing_data_total(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
}
|
||||
if (!peer) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->outgoingDataTotal);
|
||||
}
|
||||
|
||||
/* Getter for incomingDataTotal */
|
||||
static JSValue js_enet_peer_get_incoming_data_total(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_incoming_data_total(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
}
|
||||
if (!peer) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->incomingDataTotal);
|
||||
}
|
||||
|
||||
/* Getter for roundTripTimeVariance */
|
||||
static JSValue js_enet_peer_get_rtt_variance(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_rtt_variance(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
}
|
||||
if (!peer) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->roundTripTimeVariance);
|
||||
}
|
||||
|
||||
/* Getter for packetLoss */
|
||||
static JSValue js_enet_peer_get_packet_loss(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_packet_loss(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
}
|
||||
return JS_NewInt32(ctx, peer->packetLoss); // Scaled by ENET_PEER_PACKET_LOSS_SCALE
|
||||
if (!peer) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->packetLoss);
|
||||
}
|
||||
|
||||
/* Getter for state */
|
||||
static JSValue js_enet_peer_get_state(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_state(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewInt32(ctx, -1); // Invalid state
|
||||
}
|
||||
return JS_NewInt32(ctx, peer->state); // ENetPeerState enum value
|
||||
if (!peer) return JS_NewInt32(ctx, -1);
|
||||
return JS_NewInt32(ctx, peer->state);
|
||||
}
|
||||
|
||||
/* Getter for reliableDataInTransit */
|
||||
static JSValue js_enet_peer_get_reliable_data_in_transit(JSContext *ctx, JSValueConst this_val) {
|
||||
static JSValue js_enet_peer_get_reliable_data_in_transit(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
|
||||
if (!peer) {
|
||||
return JS_NewFloat64(ctx, INFINITY);
|
||||
}
|
||||
if (!peer) return JS_NewFloat64(ctx, INFINITY);
|
||||
return JS_NewInt32(ctx, peer->reliableDataInTransit);
|
||||
}
|
||||
|
||||
@@ -616,17 +492,14 @@ static JSValue js_enet_peer_get_address(JSContext *js, JSValueConst self)
|
||||
{
|
||||
ENetPeer *peer = JS_GetOpaque(self, enet_peer_class_id);
|
||||
uint32_t host = ntohl(peer->address.host);
|
||||
if (host == 0x7F000001) return JS_NewString(js, "localhost");
|
||||
|
||||
if (host == 0x7F000001)
|
||||
return JS_NewString(js, "localhost");
|
||||
|
||||
char ip_str[16]; // Enough space for "255.255.255.255" + null terminator
|
||||
char ip_str[16];
|
||||
snprintf(ip_str, sizeof(ip_str), "%u.%u.%u.%u",
|
||||
(host >> 24) & 0xFF,
|
||||
(host >> 16) & 0xFF,
|
||||
(host >> 8) & 0xFF,
|
||||
host & 0xFF);
|
||||
|
||||
return JS_NewString(js, ip_str);
|
||||
}
|
||||
|
||||
@@ -658,23 +531,20 @@ static const JSCFunctionListEntry js_enet_peer_funcs[] = {
|
||||
/* Module entry point */
|
||||
static int js_enet_init(JSContext *ctx, JSModuleDef *m);
|
||||
|
||||
/* This function returns the default export object */
|
||||
JSValue js_enet_use(JSContext *ctx) {
|
||||
// Register ENetHost class
|
||||
JSValue js_enet_use(JSContext *ctx)
|
||||
{
|
||||
JS_NewClassID(&enet_host_id);
|
||||
JS_NewClass(JS_GetRuntime(ctx), enet_host_id, &enet_host);
|
||||
JSValue host_proto = JS_NewObject(ctx);
|
||||
JS_SetPropertyFunctionList(ctx, host_proto, js_enet_host_funcs, countof(js_enet_host_funcs));
|
||||
JS_SetClassProto(ctx, enet_host_id, host_proto);
|
||||
|
||||
// Register ENetPeer class
|
||||
JS_NewClassID(&enet_peer_class_id);
|
||||
JS_NewClass(JS_GetRuntime(ctx), enet_peer_class_id, &enet_peer_class);
|
||||
JSValue peer_proto = JS_NewObject(ctx);
|
||||
JS_SetPropertyFunctionList(ctx, peer_proto, js_enet_peer_funcs, countof(js_enet_peer_funcs));
|
||||
JS_SetClassProto(ctx, enet_peer_class_id, peer_proto);
|
||||
|
||||
// Optional: store references in a "prosperon.c_types" for your environment
|
||||
JSValue global = JS_GetGlobalObject(ctx);
|
||||
JSValue prosp = JS_GetPropertyStr(ctx, global, "prosperon");
|
||||
JSValue c_types = JS_GetPropertyStr(ctx, prosp, "c_types");
|
||||
@@ -686,13 +556,13 @@ JSValue js_enet_use(JSContext *ctx) {
|
||||
JS_FreeValue(ctx, prosp);
|
||||
JS_FreeValue(ctx, global);
|
||||
|
||||
// Create the default export object with top-level ENet functions
|
||||
JSValue export_obj = JS_NewObject(ctx);
|
||||
JS_SetPropertyFunctionList(ctx, export_obj, js_enet_funcs, countof(js_enet_funcs));
|
||||
return export_obj;
|
||||
}
|
||||
|
||||
static int js_enet_init(JSContext *ctx, JSModuleDef *m) {
|
||||
static int js_enet_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
return JS_SetModuleExport(ctx, m, "default", js_enet_use(ctx));
|
||||
}
|
||||
|
||||
@@ -702,12 +572,10 @@ static int js_enet_init(JSContext *ctx, JSModuleDef *m) {
|
||||
#define JS_INIT_MODULE js_init_module_enet
|
||||
#endif
|
||||
|
||||
/* Module definition */
|
||||
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) {
|
||||
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
|
||||
{
|
||||
JSModuleDef *m = JS_NewCModule(ctx, module_name, js_enet_init);
|
||||
if (!m) {
|
||||
return NULL;
|
||||
}
|
||||
if (!m) return NULL;
|
||||
JS_AddModuleExport(ctx, m, "default");
|
||||
return m;
|
||||
}
|
||||
Reference in New Issue
Block a user