From 6812d3edbca37cf7944c74514653f5cdff5c2028 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 23 Feb 2026 18:09:35 -0600 Subject: [PATCH] enet portal works --- {net => internal}/enet.c | 212 ++++++++++++++++----------------------- internal/engine.cm | 67 +++++++------ meson.build | 2 +- tests/guid.cm | 3 +- tests/portal_actor.ce | 4 +- 5 files changed, 130 insertions(+), 158 deletions(-) rename {net => internal}/enet.c (72%) diff --git a/net/enet.c b/internal/enet.c similarity index 72% rename from net/enet.c rename to internal/enet.c index e2654ea6..4278e56b 100644 --- a/net/enet.c +++ b/internal/enet.c @@ -14,17 +14,13 @@ static void js_enet_host_finalizer(JSRuntime *rt, JSValue val) if (host) enet_host_destroy(host); } -//static void js_enet_peer_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) -//{ -// ENetPeer *peer = JS_GetOpaque(val, enet_peer_class_id); -// 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); + if (peer && peer->data) { + JS_FreeValueRT(rt, *(JSValue*)peer->data); + free(peer->data); + } } // Initialize the ENet library. Must be called before using any ENet functionality. @@ -34,8 +30,7 @@ static JSValue js_enet_initialize(JSContext *ctx, JSValueConst this_val, int arg return JS_NULL; } -// Deinitialize the ENet library, cleaning up all resources. Call this when you no longer -// need any ENet functionality. +// Deinitialize the ENet library, cleaning up all resources. static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { enet_deinitialize(); @@ -43,14 +38,7 @@ static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val, int a } // Create an ENet host for either a client-like unbound host or a server bound to a specific -// address and port: -// -// - If no argument is provided, creates an unbound "client-like" host with default settings -// (maximum 32 peers, 2 channels, unlimited bandwidth). -// - If you pass an "ip:port" string (e.g. "127.0.0.1:7777"), it creates a server bound to -// that address. The server supports up to 32 peers, 2 channels, and unlimited bandwidth. -// -// Throws an error if host creation fails for any reason. +// address and port. static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { ENetHost *host; @@ -132,68 +120,75 @@ static JSValue peer_get_value(JSContext *ctx, ENetPeer *peer) return JS_DupValue(ctx, *(JSValue*)peer->data); } -// Poll for and process any available network events (connect, receive, disconnect, or none) -// from this host, calling the provided callback for each event. This function loops until -// no more events are available in the current timeframe. -// -// :param callback: A function called once for each available event, receiving an event -// object as its single argument. -// :param timeout: (optional) Timeout in milliseconds. Defaults to 0 (non-blocking). -// :return: None +// Poll for and process any available network events from this host, +// calling the provided callback for each event. 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 (argc < 1 || !JS_IsFunction(argv[0])) return JS_RaiseDisrupt(ctx, "Expected a callback function as first argument"); + if (argc < 1 || !JS_IsFunction(argv[0])) + return JS_RaiseDisrupt(ctx, "Expected a callback function as first argument"); - double secs; - JS_ToFloat64(ctx, &secs, argv[1]); + enet_uint32 timeout_ms = 0; + if (argc >= 2 && !JS_IsNull(argv[1])) { + double secs = 0; + JS_ToFloat64(ctx, &secs, argv[1]); + if (secs > 0) timeout_ms = (enet_uint32)(secs * 1000.0); + } + + JS_FRAME(ctx); + JSGCRef event_ref = { .val = JS_NULL, .prev = NULL }; + JS_PushGCRef(ctx, &event_ref); 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)); + while (enet_host_service(host, &event, timeout_ms) > 0) { + event_ref.val = JS_NewObject(ctx); + + JSValue peer_val = peer_get_value(ctx, event.peer); + JS_SetPropertyStr(ctx, event_ref.val, "peer", peer_val); switch (event.type) { - case ENET_EVENT_TYPE_CONNECT: - JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "connect")); + case ENET_EVENT_TYPE_CONNECT: { + JSValue type_str = JS_NewString(ctx, "connect"); + JS_SetPropertyStr(ctx, event_ref.val, "type", type_str); 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 + } + case ENET_EVENT_TYPE_RECEIVE: { + JSValue type_str = JS_NewString(ctx, "receive"); + JS_SetPropertyStr(ctx, event_ref.val, "type", type_str); + JS_SetPropertyStr(ctx, event_ref.val, "channelID", JS_NewInt32(ctx, event.channelID)); if (event.packet->dataLength > 0) { JSValue data_val = js_new_blob_stoned_copy(ctx, event.packet->data, event.packet->dataLength); - JS_SetPropertyStr(ctx, event_obj, "data", data_val); + JS_SetPropertyStr(ctx, event_ref.val, "data", data_val); } enet_packet_destroy(event.packet); break; - case ENET_EVENT_TYPE_DISCONNECT: - JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "disconnect")); + } + case ENET_EVENT_TYPE_DISCONNECT: { + JSValue type_str = JS_NewString(ctx, "disconnect"); + JS_SetPropertyStr(ctx, event_ref.val, "type", type_str); break; - case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: - JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "disconnect_timeout")); + } + case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: { + JSValue type_str = JS_NewString(ctx, "disconnect_timeout"); + JS_SetPropertyStr(ctx, event_ref.val, "type", type_str); break; - case ENET_EVENT_TYPE_NONE: - JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "none")); + } + case ENET_EVENT_TYPE_NONE: { + JSValue type_str = JS_NewString(ctx, "none"); + JS_SetPropertyStr(ctx, event_ref.val, "type", type_str); break; + } } - // TODO: raise exception? - JS_FreeValue(ctx, event_obj); + JS_FreeValue(ctx, JS_Call(ctx, argv[0], JS_NULL, 1, &event_ref.val)); } - return JS_NULL; + JS_RETURN_NULL(); } -// Initiate a connection from this host to a remote server. Throws an error if the -// connection cannot be started. -// -// :param hostname: The hostname or IP address of the remote server (e.g. "example.com" or "127.0.0.1"). -// :param port: The port number to connect to. -// :return: An ENetPeer object representing the connection. +// Initiate a connection from this host to a remote 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); @@ -218,8 +213,6 @@ static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val, int a } // Flush all pending outgoing packets for this host immediately. -// -// :return: None static JSValue js_enet_host_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { ENetHost *host = JS_GetOpaque(this_val, enet_host_id); @@ -228,16 +221,13 @@ static JSValue js_enet_host_flush(JSContext *ctx, JSValueConst this_val, int arg return JS_NULL; } -// Broadcast a string or ArrayBuffer to all connected peers on channel 0. -// -// :param data: A string or ArrayBuffer to broadcast to all peers. -// :return: None +// Broadcast a string or blob to all connected peers on channel 0. 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_RaiseDisrupt(ctx, "Expected a string or ArrayBuffer to broadcast"); + if (argc < 1) return JS_RaiseDisrupt(ctx, "Expected a string or blob to broadcast"); const char *data_str = NULL; size_t data_len = 0; @@ -246,11 +236,11 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int if (JS_IsText(argv[0])) { data_str = JS_ToCStringLen(ctx, &data_len, argv[0]); if (!data_str) return JS_EXCEPTION; - } else if (js_is_blob(ctx,argv[0])) { + } else if (js_is_blob(ctx, argv[0])) { buf = js_get_blob_data(ctx, &data_len, argv[0]); if (!buf) return JS_EXCEPTION; } else { - return JS_RaiseDisrupt(ctx, "broadcast() only accepts a string or ArrayBuffer"); + return JS_RaiseDisrupt(ctx, "broadcast() only accepts a string or blob"); } ENetPacket *packet = enet_packet_create(data_str ? (const void*)data_str : (const void*)buf, data_len, ENET_PACKET_FLAG_RELIABLE); @@ -261,30 +251,25 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int return JS_NULL; } -static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) +// Host property getters +static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self) { ENetHost *host = JS_GetOpaque(self, enet_host_id); if (!host) return JS_EXCEPTION; return JS_NewInt32(js, host->address.port); } -static JSValue js_enet_host_get_address(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) +static JSValue js_enet_host_get_address(JSContext *js, JSValueConst self) { ENetHost *me = JS_GetOpaque(self, enet_host_id); if (!me) return JS_EXCEPTION; - char ip_str[128]; if (enet_address_get_host_ip(&me->address, ip_str, sizeof(ip_str)) != 0) return JS_NULL; - return JS_NewString(js, ip_str); } // Peer-level operations -// Request a graceful disconnection from this peer. The connection will close after -// pending data is sent. -// -// :return: None 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); @@ -293,16 +278,12 @@ static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val, in return JS_NULL; } -// Send a string or ArrayBuffer to this peer on channel 0. -// -// :param data: A string or ArrayBuffer to send. -// :return: None 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_RaiseDisrupt(ctx, "Expected a string or ArrayBuffer to send"); + if (argc < 1) return JS_RaiseDisrupt(ctx, "Expected a string or blob to send"); const char *data_str = NULL; size_t data_len = 0; @@ -311,11 +292,11 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc if (JS_IsText(argv[0])) { data_str = JS_ToCStringLen(ctx, &data_len, argv[0]); if (!data_str) return JS_EXCEPTION; - } else if (js_is_blob(ctx,argv[0])) { + } else if (js_is_blob(ctx, argv[0])) { buf = js_get_blob_data(ctx, &data_len, argv[0]); if (!buf) return JS_EXCEPTION; } else { - return JS_RaiseDisrupt(ctx, "send() only accepts a string or ArrayBuffer"); + return JS_RaiseDisrupt(ctx, "send() only accepts a string or blob"); } ENetPacket *packet = enet_packet_create(data_str ? (const void*)data_str : (const void*)buf, data_len, ENET_PACKET_FLAG_RELIABLE); @@ -326,9 +307,6 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc return JS_NULL; } -// Immediately terminate the connection to this peer, discarding any pending data. -// -// :return: None 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); @@ -337,9 +315,6 @@ static JSValue js_enet_peer_disconnect_now(JSContext *ctx, JSValueConst this_val return JS_NULL; } -// Request a disconnection from this peer after all queued packets are sent. -// -// :return: None 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); @@ -348,9 +323,6 @@ static JSValue js_enet_peer_disconnect_later(JSContext *ctx, JSValueConst this_v return JS_NULL; } -// Reset this peer's connection, immediately dropping it and clearing its internal state. -// -// :return: None 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); @@ -359,9 +331,6 @@ static JSValue js_enet_peer_reset(JSContext *ctx, JSValueConst this_val, int arg return JS_NULL; } -// Send a ping request to this peer to measure latency. -// -// :return: None 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); @@ -370,13 +339,6 @@ static JSValue js_enet_peer_ping(JSContext *ctx, JSValueConst this_val, int argc return JS_NULL; } -// Configure the throttling behavior for this peer, controlling how ENet adjusts its sending -// rate based on packet loss or congestion. -// -// :param interval: The interval (ms) between throttle adjustments. -// :param acceleration: The factor to increase sending speed when conditions improve. -// :param deceleration: The factor to decrease sending speed when conditions worsen. -// :return: None 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); @@ -412,12 +374,10 @@ static JSClassDef enet_host = { static JSClassDef enet_peer_class = { "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) +static JSValue js_enet_resolve_hostname(JSContext *js, JSValue self, int argc, JSValue *argv) { - // TODO: implement const char *hostname = JS_ToCString(js, argv[0]); JS_FreeCString(js, hostname); return JS_NULL; @@ -435,18 +395,19 @@ static const JSCFunctionListEntry js_enet_host_funcs[] = { 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_CFUNC0_DEF("port", js_enet_host_get_port), + JS_CFUNC0_DEF("address", js_enet_host_get_address), }; -static JSValue js_enet_peer_get_rtt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +// Peer property getters (zero-arg methods) +static JSValue js_enet_peer_get_rtt(JSContext *ctx, JSValueConst this_val) { ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); if (!peer) return JS_EXCEPTION; return JS_NewInt32(ctx, peer->roundTripTime); } -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) { ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); if (!peer) return JS_EXCEPTION; @@ -454,7 +415,7 @@ static JSValue js_enet_peer_get_incoming_bandwidth(JSContext *ctx, JSValueConst return JS_NewInt32(ctx, peer->incomingBandwidth); } -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) { ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); if (!peer) return JS_EXCEPTION; @@ -462,14 +423,14 @@ static JSValue js_enet_peer_get_outgoing_bandwidth(JSContext *ctx, JSValueConst return JS_NewInt32(ctx, peer->outgoingBandwidth); } -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) { ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); if (!peer) return JS_EXCEPTION; return JS_NewInt32(ctx, peer->lastSendTime); } -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) { ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); if (!peer) return JS_EXCEPTION; @@ -528,16 +489,17 @@ static JSValue js_enet_peer_get_reliable_data_in_transit(JSContext *ctx, JSValue static JSValue js_enet_peer_get_port(JSContext *js, JSValueConst self) { ENetPeer *peer = JS_GetOpaque(self, enet_peer_class_id); + if (!peer) return JS_EXCEPTION; return JS_NewUint32(js, peer->address.port); } static JSValue js_enet_peer_get_address(JSContext *js, JSValueConst self) { ENetPeer *peer = JS_GetOpaque(self, enet_peer_class_id); + if (!peer) return JS_EXCEPTION; char ip_str[128]; if (enet_address_get_host_ip(&peer->address, ip_str, sizeof(ip_str)) != 0) return JS_NULL; - return JS_NewString(js, ip_str); } @@ -550,24 +512,26 @@ static const JSCFunctionListEntry js_enet_peer_funcs[] = { 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_CFUNC0_DEF("rtt", js_enet_peer_get_rtt), + JS_CFUNC0_DEF("incoming_bandwidth", js_enet_peer_get_incoming_bandwidth), + JS_CFUNC0_DEF("outgoing_bandwidth", js_enet_peer_get_outgoing_bandwidth), + JS_CFUNC0_DEF("last_send_time", js_enet_peer_get_last_send_time), + JS_CFUNC0_DEF("last_receive_time", js_enet_peer_get_last_receive_time), + JS_CFUNC0_DEF("mtu", js_enet_peer_get_mtu), + JS_CFUNC0_DEF("outgoing_data_total", js_enet_peer_get_outgoing_data_total), + JS_CFUNC0_DEF("incoming_data_total", js_enet_peer_get_incoming_data_total), + JS_CFUNC0_DEF("rtt_variance", js_enet_peer_get_rtt_variance), + JS_CFUNC0_DEF("packet_loss", js_enet_peer_get_packet_loss), + JS_CFUNC0_DEF("state", js_enet_peer_get_state), + JS_CFUNC0_DEF("reliable_data_in_transit", js_enet_peer_get_reliable_data_in_transit), + JS_CFUNC0_DEF("port", js_enet_peer_get_port), + JS_CFUNC0_DEF("address", js_enet_peer_get_address), }; -JSValue js_core_enet_use(JSContext *ctx) +JSValue js_core_internal_enet_use(JSContext *ctx) { + enet_initialize(); + JS_FRAME(ctx); JS_NewClassID(&enet_host_id); diff --git a/internal/engine.cm b/internal/engine.cm index 3caf2e88..d1e02b17 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -1143,6 +1143,8 @@ var root = null var receive_fn = null var greeters = {} // Router functions for when messages are received for a specific actor +var enet = use_core('internal/enet') + var peers = {} var id_address = {} var peer_queue = {} @@ -1151,24 +1153,24 @@ var portal_fn = null function peer_connection(peer) { return { - latency: peer.rtt, + latency: peer.rtt(), bandwidth: { - incoming: peer.incoming_bandwidth, - outgoing: peer.outgoing_bandwidth + incoming: peer.incoming_bandwidth(), + outgoing: peer.outgoing_bandwidth() }, activity: { - last_sent: peer.last_send_time, - last_received: peer.last_receive_time + last_sent: peer.last_send_time(), + last_received: peer.last_receive_time() }, - mtu: peer.mtu, + mtu: peer.mtu(), data: { - incoming_total: peer.incoming_data_total, - outgoing_total: peer.outgoing_data_total, - reliable_in_transit: peer.reliable_data_in_transit + incoming_total: peer.incoming_data_total(), + outgoing_total: peer.outgoing_data_total(), + reliable_in_transit: peer.reliable_data_in_transit() }, - latency_variance: peer.rtt_variance, - packet_loss: peer.packet_loss, - state: peer.state + latency_variance: peer.rtt_variance(), + packet_loss: peer.packet_loss(), + state: peer.state() } } @@ -1190,7 +1192,7 @@ $_.connection = function(callback, actor, config) { // takes a function input value that will eventually be called with the current time in number form. $_.portal = function(fn, port) { if (portal) { - log.error(`Already started a portal listening on ${portal.port}`) + log.error(`Already started a portal listening on ${portal.port()}`) disrupt } if (!port) { @@ -1200,43 +1202,49 @@ $_.portal = function(fn, port) { log.system(`starting a portal on port ${port}`) portal = enet.create_host({address: "any", port}) portal_fn = fn + enet_check() } function handle_host(e) { var queue = null var data = null + var addr = null + var port = null if (e.type == "connect") { - log.system(`connected a new peer: ${e.peer.address}:${e.peer.port}`) - peers[`${e.peer.address}:${e.peer.port}`] = e.peer - queue = peer_queue.get(e.peer) + addr = e.peer.address() + port = e.peer.port() + log.system(`connected a new peer: ${addr}:${port}`) + peers[`${addr}:${port}`] = e.peer + queue = peer_queue[e.peer] if (queue) { arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg))) log.system(`sent queue out of queue`) - peer_queue.delete(e.peer) + delete peer_queue[e.peer] } } else if (e.type == "disconnect") { - peer_queue.delete(e.peer) + delete peer_queue[e.peer] arrfor(array(peers), function(id, index) { if (peers[id] == e.peer) delete peers[id] }) - log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port) + log.system('portal got disconnect from ' + e.peer.address() + ":" + e.peer.port()) } else if (e.type == "receive") { data = nota.decode(e.data) if (data.replycc && !data.replycc.address) { - data.replycc[ACTORDATA].address = e.peer.address - data.replycc[ACTORDATA].port = e.peer.port + data.replycc[ACTORDATA].address = e.peer.address() + data.replycc[ACTORDATA].port = e.peer.port() } if (data.data) populate_actor_addresses(data.data, e) - turn(data) + handle_message(data) + send_messages() } } function populate_actor_addresses(obj, e) { if (!is_object(obj)) return if (obj[ACTORDATA] && !obj[ACTORDATA].address) { - obj[ACTORDATA].address = e.peer.address - obj[ACTORDATA].port = e.peer.port + obj[ACTORDATA].address = e.peer.address() + obj[ACTORDATA].port = e.peer.port() } arrfor(array(obj), function(key, index) { if (key in obj) @@ -1307,8 +1315,6 @@ $_.delay = function delay(fn, seconds) { return function() { actor_mod.removetimer(id) } } -var enet = use_core('enet') - // causes this actor to stop when another actor stops. var couplings = {} $_.couple = function couple(actor) { @@ -1368,7 +1374,8 @@ function actor_send(actor, message) { if (!portal) { log.system(`creating a contactor ...`) portal = enet.create_host({address:"any"}) - log.system(`allowing contact to port ${portal.port}`) + log.system(`allowing contact to port ${portal.port()}`) + enet_check() } log.system(`no peer! connecting to ${actor[ACTORDATA].address}:${actor[ACTORDATA].port}`) peer = portal.connect(actor[ACTORDATA].address, actor[ACTORDATA].port) @@ -1564,7 +1571,7 @@ function handle_message(msg) { var fn = null if (msg[SYSYM]) { - handle_sysym(msg[SYSYM], msg.from) + handle_sysym(msg[SYSYM]) return } @@ -1596,7 +1603,7 @@ function enet_check() $_.delay(enet_check, ENETSERVICE); } -// enet_check(); +// enet_check started on demand when $portal() is called // Finally, run the program actor_mod.setname(_cell.args.program) @@ -1747,8 +1754,6 @@ $_.clock(_ => { } env.args = _cell.args.arg env.log = log - os.print(`[debug] env keys: ${text(array(env), ',')}\n`) - os.print(`[debug] $stop in env: ${text(env['$stop'] != null)}\n`) env = stone(env) var native_build = null diff --git a/meson.build b/meson.build index b5d76015..29221512 100644 --- a/meson.build +++ b/meson.build @@ -82,7 +82,7 @@ scripts = [ 'internal/os.c', 'internal/fd.c', 'net/http.c', - 'net/enet.c', + 'internal/enet.c', 'archive/miniz.c', 'source/cJSON.c' ] diff --git a/tests/guid.cm b/tests/guid.cm index 3833204a..8e3fe453 100644 --- a/tests/guid.cm +++ b/tests/guid.cm @@ -1,10 +1,11 @@ var blob = use('blob') var time = use('time') +var random = use('random').random_fit return { test_guid: function() { var st = time.number() - var guid = blob(256, $random_fit) + var guid = blob(256, random) stone(guid) var btime = time.number()-st st = time.number() diff --git a/tests/portal_actor.ce b/tests/portal_actor.ce index 0eb7e3ea..441f37a5 100644 --- a/tests/portal_actor.ce +++ b/tests/portal_actor.ce @@ -10,5 +10,7 @@ $portal(e => { $receiver(e => { log.console(`Got message: ${e}`) send(e, {greet: "Hello back!"}) - $delay(_ => $stop(), 0.2) }) + +// stop after portal is confirmed working +var _t = $delay(_ => $stop(), 0.5)