Merge branch 'fix_missing_stop'

This commit is contained in:
2026-02-23 18:09:41 -06:00
5 changed files with 130 additions and 158 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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'
]

View File

@@ -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()

View File

@@ -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)