From 1332af93ab74b328e78894e8c30206f0f14da574 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 13 Mar 2025 06:28:00 -0500 Subject: [PATCH] enet and mailboxes now take strings or array buffers --- scripts/core/engine.js | 88 ++--- source/jsffi.c | 70 ++-- source/qjs_enet.c | 778 +++++++++++++++++------------------------ 3 files changed, 395 insertions(+), 541 deletions(-) diff --git a/scripts/core/engine.js b/scripts/core/engine.js index d760ccf4..bb1c9bfa 100644 --- a/scripts/core/engine.js +++ b/scripts/core/engine.js @@ -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() diff --git a/source/jsffi.c b/source/jsffi.c index 6172208e..adfb75ee 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -7156,82 +7156,88 @@ 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."); - char *id = JS_ToCString(js,argv[0]); - void *nota = value2nota(js, argv[1]); + if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and a message"); + char *id = JS_ToCString(js, argv[0]); + 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) { - JS_FreeCString(js,id); - return JS_ThrowInternalError(js, "No mailbox found for given ID."); + if (!JS_IsString(argv[1])) free(data); + JS_FreeCString(js, 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); + JS_FreeCString(js, id); ) -JSC_CCALL(os_mailbox_service, // grab all from our mailbox and - char *id = JS_ToCString(js,argv[0]); - JSValue fn = JS_DupValue(js,argv[1]); +JSC_CCALL(os_mailbox_service, + char *id = JS_ToCString(js, argv[0]); + JSValue fn = JS_DupValue(js, argv[1]); int mb_index = shgeti(mailboxes, id); if (mb_index == -1) { - JS_FreeCString(js,id); - JS_FreeValue(js,fn); - return JS_ThrowInternalError(js, "No mailbox found for given ID."); + JS_FreeCString(js, id); + JS_FreeValue(js, fn); + 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); if (count > 0) { - arrsetlen(temp,count); + arrsetlen(temp, count); memcpy(temp, mb->messages, sizeof(void*) * count); - arrsetlen(mb->messages,0); + 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); - JS_FreeCString(js,id); - JS_FreeValue(js,fn); + JS_FreeCString(js, id); + JS_FreeValue(js, fn); ) 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]); - + 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); SDL_UnlockMutex(mailboxes_mutex); - JS_FreeCString(js,id); + JS_FreeCString(js, id); ) JSC_CCALL(os_waitevent, diff --git a/source/qjs_enet.c b/source/qjs_enet.c index ca97da28..5fadfb26 100644 --- a/source/qjs_enet.c +++ b/source/qjs_enet.c @@ -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) { - ENetHost *host = JS_GetOpaque(val, enet_host_id); - if (host) { - enet_host_destroy(host); - } +static void js_enet_host_finalizer(JSRuntime *rt, JSValue val) +{ + ENetHost *host = JS_GetOpaque(val, enet_host_id); + 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) { - ENetPeer *peer = JS_GetOpaque(val, enet_peer_class_id); - JS_FreeValueRT(rt, *(JSValue*)peer->data); - free(peer->data); +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."); - } - return JS_UNDEFINED; +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) { - enet_deinitialize(); - return JS_UNDEFINED; +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; @@ -118,181 +117,123 @@ wrap: static JSValue peer_get_value(JSContext *ctx, ENetPeer *peer) { - if (!peer->data) { - peer->data = malloc(sizeof(JSValue)); - *(JSValue*)peer->data = JS_NewObjectClass(ctx, enet_peer_class_id); - JS_SetOpaque(*(JSValue*)peer->data, peer); - } - return JS_DupValue(ctx, *(JSValue*)peer->data); + if (!peer->data) { + peer->data = malloc(sizeof(JSValue)); + *(JSValue*)peer->data = JS_NewObjectClass(ctx, enet_peer_class_id); + JS_SetOpaque(*(JSValue*)peer->data, peer); + } + return JS_DupValue(ctx, *(JSValue*)peer->data); } /* 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; - ENetHost *host = JS_GetOpaque(this_val, enet_host_id); - if (!host) { - return JS_EXCEPTION; + 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]); + + ENetEvent event; + while (enet_host_service(host, &event, secs*1000.0f) > 0) { + JSValue event_obj = JS_NewObject(ctx); + JS_SetPropertyStr(ctx, event_obj, "peer", peer_get_value(ctx, event.peer)); + + switch (event.type) { + case ENET_EVENT_TYPE_CONNECT: + JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "connect")); + break; + 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)); + + // 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); + } + enet_packet_destroy(event.packet); + break; + case ENET_EVENT_TYPE_DISCONNECT: + JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "disconnect")); + break; + case ENET_EVENT_TYPE_NONE: + JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "none")); + break; } - // 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); + uncaught_exception(ctx, JS_Call(ctx, callback, JS_UNDEFINED, 1, &event_obj)); + JS_FreeValue(ctx, event_obj); + } - double secs; - JS_ToFloat64(ctx, &secs, argv[1]); - - ENetEvent event; - while (enet_host_service(host, &event, secs*1000.0f) > 0) { - JSValue event_obj = JS_NewObject(ctx); - JS_SetPropertyStr(ctx, event_obj, "peer", peer_get_value(ctx, event.peer)); - - switch (event.type) { - case ENET_EVENT_TYPE_CONNECT: { - JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "connect")); - break; - } - 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, - ""); - - 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; - } - - 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; - case ENET_EVENT_TYPE_NONE: - JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "none")); - break; - } - - // Invoke callback - uncaught_exception(ctx, JS_Call(ctx, callback, JS_UNDEFINED, 1, &event_obj)); - JS_FreeValue(ctx, event_obj); - } - - JS_FreeValue(ctx, callback); - return JS_UNDEFINED; + JS_FreeValue(ctx, callback); + return JS_UNDEFINED; } /* Host connect: client -> connect to server */ -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; - } +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 (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 - } - int port; - JS_ToInt32(ctx, &port, argv[1]); + const char *hostname = JS_ToCString(ctx, argv[0]); + if (!hostname) return JS_EXCEPTION; + int port; + JS_ToInt32(ctx, &port, argv[1]); - ENetAddress address; - enet_address_set_host(&address, hostname); - JS_FreeCString(ctx, hostname); - address.port = port; + ENetAddress address; + enet_address_set_host(&address, hostname); + JS_FreeCString(ctx, hostname); + 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."); - } + ENetPeer *peer = enet_host_connect(host, &address, 2, 0); + if (!peer) return JS_ThrowInternalError(ctx, "No available peers for initiating an ENet connection"); - return peer_get_value(ctx, peer); + return peer_get_value(ctx, peer); } /* Flush queued packets */ -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; - } - enet_host_flush(host); - return JS_UNDEFINED; +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; + 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) { - ENetHost *host = JS_GetOpaque(this_val, enet_host_id); - if (!host) { - return JS_EXCEPTION; - } +/* 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 (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."); - } + if (argc < 1) return JS_ThrowTypeError(ctx, "Expected a string or ArrayBuffer to broadcast"); - // 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)."); - } + const char *data_str = NULL; + size_t data_len = 0; + uint8_t *buf = NULL; - size_t data_len; - const char *data_str = JS_ToCStringLen(ctx, &data_len, json_data); - JS_FreeValue(ctx, json_data); + 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 (!data_str) { - return JS_EXCEPTION; // out of memory - } + 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"); - 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; + enet_host_broadcast(host, 0, packet); + return JS_UNDEFINED; } static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) @@ -308,302 +249,237 @@ 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) { - ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); - if (!peer) { - return JS_EXCEPTION; - } - enet_peer_disconnect(peer, 0); - return JS_UNDEFINED; +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; + 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) { - ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); - if (!peer) { - return JS_EXCEPTION; - } +/* 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 (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."); - } + if (argc < 1) return JS_ThrowTypeError(ctx, "Expected a string or ArrayBuffer to send"); - 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)."); - } + const char *data_str = NULL; + size_t data_len = 0; + uint8_t *buf = NULL; - 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; - } + 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"); + } - // 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."); - } + 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"); - if (enet_peer_send(peer, 0, packet) < 0) { - return JS_ThrowInternalError(ctx, "unable to send packet. send returned error."); - } - return JS_UNDEFINED; + 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) { - ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); - if (!peer) { - return JS_EXCEPTION; - } - enet_peer_disconnect_now(peer, 0); - return JS_UNDEFINED; +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; + 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) { - ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); - if (!peer) { - return JS_EXCEPTION; - } - enet_peer_disconnect_later(peer, 0); - return JS_UNDEFINED; +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; + enet_peer_disconnect_later(peer, 0); + return JS_UNDEFINED; } -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; - } - enet_peer_reset(peer); - return JS_UNDEFINED; +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; + enet_peer_reset(peer); + return JS_UNDEFINED; } -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; - } - enet_peer_ping(peer); - return JS_UNDEFINED; +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; + enet_peer_ping(peer); + return JS_UNDEFINED; } -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; - } +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; - 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"); - } + 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"); - enet_peer_throttle_configure(peer, interval, acceleration, deceleration); - return JS_UNDEFINED; + 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) { - ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); - if (!peer) { - return JS_EXCEPTION; - } +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; - 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"); - } + 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"); - enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max); - return JS_UNDEFINED; + enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max); + return JS_UNDEFINED; } /* Class definitions */ static JSClassDef enet_host = { - "ENetHost", - .finalizer = js_enet_host_finalizer, + "ENetHost", + .finalizer = js_enet_host_finalizer, }; static JSClassDef enet_peer_class = { - "ENetPeer", - .finalizer = js_enet_peer_finalizer, - .gc_mark = js_enet_peer_mark + "ENetPeer", + .finalizer = js_enet_peer_finalizer, + .gc_mark = js_enet_peer_mark }; JSValue js_enet_resolve_hostname(JSContext *js, JSValue self, int argc, JSValue *argv) { - char *hostname = JS_ToCString(js,argv[0]); + 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 */ static const JSCFunctionListEntry js_enet_funcs[] = { - JS_CFUNC_DEF("initialize", 0, js_enet_initialize), - JS_CFUNC_DEF("deinitialize", 0, js_enet_deinitialize), - JS_CFUNC_DEF("create_host", 1, js_enet_host_create), - JS_CFUNC_DEF("resolve_hostname", 1, js_enet_resolve_hostname), + JS_CFUNC_DEF("initialize", 0, js_enet_initialize), + JS_CFUNC_DEF("deinitialize", 0, js_enet_deinitialize), + JS_CFUNC_DEF("create_host", 1, js_enet_host_create), + JS_CFUNC_DEF("resolve_hostname", 1, js_enet_resolve_hostname), }; static const JSCFunctionListEntry js_enet_host_funcs[] = { - JS_CFUNC_DEF("service", 2, js_enet_host_service), - JS_CFUNC_DEF("connect", 2, js_enet_host_connect), - JS_CFUNC_DEF("flush", 0, js_enet_host_flush), - JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast), - JS_CGETSET_DEF("port", js_enet_host_get_port, NULL), - JS_CGETSET_DEF("address", js_enet_host_get_address, NULL), + JS_CFUNC_DEF("service", 2, js_enet_host_service), + JS_CFUNC_DEF("connect", 2, js_enet_host_connect), + JS_CFUNC_DEF("flush", 0, js_enet_host_flush), + JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast), + JS_CGETSET_DEF("port", js_enet_host_get_port, NULL), + 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) { - ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); - if (!peer) { - return JS_EXCEPTION; - } - return JS_NewInt32(ctx, peer->roundTripTime); // RTT in milliseconds +/* 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); } -/* Getter for incomingBandwidth */ -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 +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); } -/* Getter for outgoingBandwidth */ -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 +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); } -/* Getter for lastSendTime */ -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 +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); } -/* Getter for lastReceiveTime */ -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 +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); } -#include // Ensure this is included for INFINITY - -/* Getter for mtu */ -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); - } - return JS_NewInt32(ctx, peer->mtu); +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); + return JS_NewInt32(ctx, peer->mtu); } -/* Getter for outgoingDataTotal */ -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); - } - return JS_NewInt32(ctx, peer->outgoingDataTotal); +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); + return JS_NewInt32(ctx, peer->outgoingDataTotal); } -/* Getter for incomingDataTotal */ -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); - } - return JS_NewInt32(ctx, peer->incomingDataTotal); +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); + return JS_NewInt32(ctx, peer->incomingDataTotal); } -/* Getter for roundTripTimeVariance */ -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); - } - return JS_NewInt32(ctx, peer->roundTripTimeVariance); +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); + return JS_NewInt32(ctx, peer->roundTripTimeVariance); } -/* Getter for packetLoss */ -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 +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); } -/* Getter for state */ -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 +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); + return JS_NewInt32(ctx, peer->state); } -/* Getter for reliableDataInTransit */ -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); - } - return JS_NewInt32(ctx, peer->reliableDataInTransit); +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); + return JS_NewInt32(ctx, peer->reliableDataInTransit); } static JSValue js_enet_peer_get_port(JSContext *js, JSValueConst self) @@ -616,84 +492,78 @@ 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); } static const JSCFunctionListEntry js_enet_peer_funcs[] = { - JS_CFUNC_DEF("send", 1, js_enet_peer_send), - JS_CFUNC_DEF("disconnect", 0, js_enet_peer_disconnect), - JS_CFUNC_DEF("disconnect_now", 0, js_enet_peer_disconnect_now), - JS_CFUNC_DEF("disconnect_later", 0, js_enet_peer_disconnect_later), - JS_CFUNC_DEF("reset", 0, js_enet_peer_reset), - JS_CFUNC_DEF("ping", 0, js_enet_peer_ping), - JS_CFUNC_DEF("throttle_configure",3, js_enet_peer_throttle_configure), - JS_CFUNC_DEF("timeout", 3, js_enet_peer_timeout), - JS_CGETSET_DEF("rtt", js_enet_peer_get_rtt, NULL), - JS_CGETSET_DEF("incoming_bandwidth",js_enet_peer_get_incoming_bandwidth, NULL), - JS_CGETSET_DEF("outgoing_bandwidth",js_enet_peer_get_outgoing_bandwidth, NULL), - JS_CGETSET_DEF("last_send_time", js_enet_peer_get_last_send_time, NULL), - JS_CGETSET_DEF("last_receive_time",js_enet_peer_get_last_receive_time, NULL), - JS_CGETSET_DEF("mtu", js_enet_peer_get_mtu, NULL), - JS_CGETSET_DEF("outgoing_data_total", js_enet_peer_get_outgoing_data_total, NULL), - JS_CGETSET_DEF("incoming_data_total", js_enet_peer_get_incoming_data_total, NULL), - JS_CGETSET_DEF("rtt_variance", js_enet_peer_get_rtt_variance, NULL), - JS_CGETSET_DEF("packet_loss", js_enet_peer_get_packet_loss, NULL), - JS_CGETSET_DEF("state", js_enet_peer_get_state, NULL), - JS_CGETSET_DEF("reliable_data_in_transit", js_enet_peer_get_reliable_data_in_transit, NULL), - JS_CGETSET_DEF("port", js_enet_peer_get_port, NULL), - JS_CGETSET_DEF("address", js_enet_peer_get_address, NULL), + JS_CFUNC_DEF("send", 1, js_enet_peer_send), + JS_CFUNC_DEF("disconnect", 0, js_enet_peer_disconnect), + JS_CFUNC_DEF("disconnect_now", 0, js_enet_peer_disconnect_now), + JS_CFUNC_DEF("disconnect_later", 0, js_enet_peer_disconnect_later), + JS_CFUNC_DEF("reset", 0, js_enet_peer_reset), + JS_CFUNC_DEF("ping", 0, js_enet_peer_ping), + JS_CFUNC_DEF("throttle_configure", 3, js_enet_peer_throttle_configure), + JS_CFUNC_DEF("timeout", 3, js_enet_peer_timeout), + JS_CGETSET_DEF("rtt", js_enet_peer_get_rtt, NULL), + JS_CGETSET_DEF("incoming_bandwidth", js_enet_peer_get_incoming_bandwidth, NULL), + JS_CGETSET_DEF("outgoing_bandwidth", js_enet_peer_get_outgoing_bandwidth, NULL), + JS_CGETSET_DEF("last_send_time", js_enet_peer_get_last_send_time, NULL), + JS_CGETSET_DEF("last_receive_time", js_enet_peer_get_last_receive_time, NULL), + JS_CGETSET_DEF("mtu", js_enet_peer_get_mtu, NULL), + JS_CGETSET_DEF("outgoing_data_total", js_enet_peer_get_outgoing_data_total, NULL), + JS_CGETSET_DEF("incoming_data_total", js_enet_peer_get_incoming_data_total, NULL), + JS_CGETSET_DEF("rtt_variance", js_enet_peer_get_rtt_variance, NULL), + JS_CGETSET_DEF("packet_loss", js_enet_peer_get_packet_loss, NULL), + JS_CGETSET_DEF("state", js_enet_peer_get_state, NULL), + JS_CGETSET_DEF("reliable_data_in_transit", js_enet_peer_get_reliable_data_in_transit, NULL), + JS_CGETSET_DEF("port", js_enet_peer_get_port, NULL), + JS_CGETSET_DEF("address", js_enet_peer_get_address, NULL), }; /* 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 - 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); +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); + 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"); + JSValue global = JS_GetGlobalObject(ctx); + JSValue prosp = JS_GetPropertyStr(ctx, global, "prosperon"); + JSValue c_types = JS_GetPropertyStr(ctx, prosp, "c_types"); - JS_SetPropertyStr(ctx, c_types, "enet_host", JS_DupValue(ctx, host_proto)); - JS_SetPropertyStr(ctx, c_types, "enet_peer", JS_DupValue(ctx, peer_proto)); + JS_SetPropertyStr(ctx, c_types, "enet_host", JS_DupValue(ctx, host_proto)); + JS_SetPropertyStr(ctx, c_types, "enet_peer", JS_DupValue(ctx, peer_proto)); - JS_FreeValue(ctx, c_types); - JS_FreeValue(ctx, prosp); - JS_FreeValue(ctx, global); + JS_FreeValue(ctx, c_types); + 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; + 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) { - return JS_SetModuleExport(ctx, m, "default", js_enet_use(ctx)); +static int js_enet_init(JSContext *ctx, JSModuleDef *m) +{ + return JS_SetModuleExport(ctx, m, "default", js_enet_use(ctx)); } #ifdef JS_SHARED_LIBRARY @@ -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 *m = JS_NewCModule(ctx, module_name, js_enet_init); - if (!m) { - return NULL; - } - JS_AddModuleExport(ctx, m, "default"); - return m; -} +JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m = JS_NewCModule(ctx, module_name, js_enet_init); + if (!m) return NULL; + JS_AddModuleExport(ctx, m, "default"); + return m; +} \ No newline at end of file