coupling
Some checks failed
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Successful in 1m13s
Build and Deploy / build-windows (CLANG64) (push) Failing after 14m3s
Some checks failed
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Successful in 1m13s
Build and Deploy / build-windows (CLANG64) (push) Failing after 14m3s
This commit is contained in:
@@ -524,6 +524,9 @@ var util = use('util')
|
||||
|
||||
var $_ = {}
|
||||
|
||||
var underlings = new Set()
|
||||
var overling = undefined
|
||||
|
||||
var host = enet.create_host()
|
||||
$_.host = host
|
||||
|
||||
@@ -540,11 +543,31 @@ $_.contact = function(callback, record)
|
||||
|
||||
}
|
||||
|
||||
$_.connection = function(callback, actor, config)
|
||||
{
|
||||
|
||||
}
|
||||
$_.connection = function(callback, actor, config) {
|
||||
var peer = actor.peer;
|
||||
callback({
|
||||
latency: peer.rtt,
|
||||
bandwidth: {
|
||||
incoming: peer.incoming_bandwidth,
|
||||
outgoing: peer.outgoing_bandwidth
|
||||
},
|
||||
activity: {
|
||||
last_sent: peer.last_send_time,
|
||||
last_received: peer.last_receive_time,
|
||||
},
|
||||
mtu: peer.mtu,
|
||||
data: {
|
||||
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
|
||||
});
|
||||
};
|
||||
|
||||
var portal = undefined
|
||||
$_.portal = function(fn, port)
|
||||
{
|
||||
|
||||
@@ -555,19 +578,21 @@ $_.receiver = function(fn)
|
||||
receive_fn = fn;
|
||||
}
|
||||
|
||||
var underlings = {}
|
||||
var greeters = {}
|
||||
|
||||
$_.start = function(cb, prg, arg)
|
||||
{
|
||||
var guid = util.guid()
|
||||
underlings[guid] = cb
|
||||
greeters[guid] = cb
|
||||
os.createprocess(["./prosperon", "spawn", "--program", prg, "--overling", $_.host.port(), "--guid", guid])
|
||||
guid2actor.set(guid, {peer:undefined, guid:guid})
|
||||
}
|
||||
|
||||
$_.stop = function(actor)
|
||||
{
|
||||
if (!actor)
|
||||
if (!actor) {
|
||||
os.exit(0)
|
||||
}
|
||||
|
||||
actor.peer.send({
|
||||
type:"stop",
|
||||
@@ -585,17 +610,45 @@ $_.delay = function(fn, seconds)
|
||||
return function() { os.removetimer(id); }
|
||||
}
|
||||
|
||||
var guid2actor = new Map()
|
||||
|
||||
var couplings = new Set()
|
||||
|
||||
$_.couple = function(actor)
|
||||
{
|
||||
couplings.add(actor)
|
||||
}
|
||||
|
||||
use('cmd')(prosperon.argv)
|
||||
|
||||
if (prosperon.overling)
|
||||
$_.host.connect("localhost", args.overling)
|
||||
|
||||
if (prosperon.program)
|
||||
actor.spawn(prosperon.program)
|
||||
|
||||
if (!prosperon.guid) prosperon.guid = util.guid()
|
||||
|
||||
var ar = 60 // seconds before reclamation
|
||||
|
||||
var unneeded_timer = $_.delay($_.stop, ar)
|
||||
|
||||
function handle_receive(e)
|
||||
{
|
||||
var data = e.data
|
||||
switch(data.type) {
|
||||
case "greet":
|
||||
if (underlings[data.guid]) underlings[data.guid]({
|
||||
if (greeters[data.guid]) {
|
||||
var actor = guid2actor.get(data.guid)
|
||||
if (!actor) throw new Error(`No registered actor for guid ${data.guid}`)
|
||||
actor.peer = e.peer
|
||||
guid2actor.set(e.peer, actor)
|
||||
greeters[data.guid]({
|
||||
type: "greet",
|
||||
data: {peer:e.peer}
|
||||
data: actor
|
||||
})
|
||||
greeters[data.guid] = undefined
|
||||
}
|
||||
break
|
||||
case "stop":
|
||||
console.log("STOPPING!")
|
||||
@@ -603,10 +656,25 @@ function handle_receive(e)
|
||||
}
|
||||
}
|
||||
|
||||
function handle_actor_disconnect(actor)
|
||||
{
|
||||
console.log(`actor ${json.encode(actor)} disconnected`)
|
||||
guid2actor.delete(actor.guid)
|
||||
guid2actor.delete(actor.peer)
|
||||
if (couplings.has(actor)) {
|
||||
console.log(`I was connected to it, so I'm dying`)
|
||||
$_.stop()
|
||||
}
|
||||
}
|
||||
|
||||
var hang = 0.016
|
||||
while (1) {
|
||||
os.waitevent(_ => {}, hang)
|
||||
os.waitevent(e => {
|
||||
unneeded_timer()
|
||||
unneded_timer = $_.delay($_.stop, ar)
|
||||
}, hang)
|
||||
host.service(e => {
|
||||
unneeded_timer()
|
||||
switch(e.type) {
|
||||
case "connect":
|
||||
console.log(`connected. sending greet with guid ${prosperon.guid} to peer ${e.peer}`)
|
||||
@@ -621,9 +689,10 @@ while (1) {
|
||||
break;
|
||||
|
||||
case "disconnect":
|
||||
console.log(`this peer left: ${e.peer}`)
|
||||
handle_actor_disconnect(guid2actor.get(e.peer))
|
||||
break
|
||||
}
|
||||
unneeded_timer = $_.delay($_.stop, ar)
|
||||
}, hang);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,28 +64,14 @@ Cmdline.register_order(
|
||||
"Make documentation."
|
||||
})
|
||||
|
||||
function spawn_root(script)
|
||||
{
|
||||
return actor.spawn(script, {}, function(underling, msg) {
|
||||
if (msg.message !== "created") return;
|
||||
Object.defineProperty(underling, 'then', {
|
||||
configurable:false,
|
||||
writable:false,
|
||||
value:function() {
|
||||
os.exit(0);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
Cmdline.register_order(
|
||||
"play",
|
||||
function (argv) {
|
||||
var app
|
||||
if (io.exists("main.js"))
|
||||
app = spawn_root("main.js")
|
||||
app = actor.spawn("main.js")
|
||||
else
|
||||
app = spawn_root("nogame.js")
|
||||
app = actor.spawn("nogame.js")
|
||||
|
||||
// rm actor so it can't be tampered
|
||||
globalThis.actor = undefined
|
||||
@@ -135,28 +121,6 @@ Cmdline.register_order(
|
||||
"OBJECT ?FILE?",
|
||||
);
|
||||
|
||||
Cmdline.register_order(
|
||||
"run",
|
||||
function (script) {
|
||||
var s = os.now()
|
||||
script = script.join(" ");
|
||||
if (!script) {
|
||||
console.print("Need something to run.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
spawn_root(script)
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
os.exit(1);
|
||||
}
|
||||
},
|
||||
"Run a given script. SCRIPT can be the script itself, or a file containing the script",
|
||||
"SCRIPT",
|
||||
);
|
||||
|
||||
Cmdline.orders.script = Cmdline.orders.run;
|
||||
|
||||
Cmdline.print_order = function (fn) {
|
||||
if (typeof fn === "string") fn = Cmdline.orders[fn];
|
||||
|
||||
@@ -185,17 +149,13 @@ function parse_args(argv)
|
||||
Cmdline.register_order(
|
||||
"spawn",
|
||||
function(argv) {
|
||||
var args = parse_args(argv)
|
||||
console.log(json.encode(args));
|
||||
prosperon.args = parse_args(argv)
|
||||
if (!args.program)
|
||||
os.exit()
|
||||
|
||||
prosperon.guid = args.guid
|
||||
console.log(`going to connect to ${args.overling}`)
|
||||
if (args.overling)
|
||||
$_.host.connect("localhost", args.overling);
|
||||
|
||||
// spawn_root(args.program)
|
||||
prosperon.guid = prosperon.args.guid
|
||||
prosperon.overling = prosperon.args.overling
|
||||
prosperon.program = args.program
|
||||
},
|
||||
"Spawn a new prosperon actor.",
|
||||
"TOPIC"
|
||||
@@ -236,11 +196,16 @@ Cmdline.register_order(
|
||||
|
||||
function cmd_args(cmds) {
|
||||
cmds.shift()
|
||||
if (cmds.length === 0) cmds[0] = "play";
|
||||
if (cmds.length === 0) {
|
||||
cmds[0] = "spawn";
|
||||
cmds[1] = "--program"
|
||||
cmds[2] = "main.js"
|
||||
}
|
||||
else if (!Cmdline.orders[cmds[0]]) {
|
||||
// assume it's a script
|
||||
cmds[1] = cmds[0]
|
||||
cmds[0] = "run"
|
||||
cmds[2] = cmds[0]
|
||||
cmds[1] = "--program"
|
||||
cmds[0] = "spawn"
|
||||
}
|
||||
|
||||
Cmdline.orders[cmds[0]](cmds.slice(1));
|
||||
|
||||
@@ -5746,17 +5746,15 @@ static const JSCFunctionListEntry js_input_funcs[] = {
|
||||
};
|
||||
|
||||
JSC_CCALL(os_guid,
|
||||
char guid[33];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int r = rand();
|
||||
for (int j = 0; j < 8; j++) {
|
||||
guid[i*8+j] = "0123456789abcdef"[r%16];
|
||||
r /= 16;
|
||||
}
|
||||
}
|
||||
SDL_GUID guid;
|
||||
for (int i = 0; i < 16; i++)
|
||||
guid.data[i] = rand() % 256;
|
||||
|
||||
guid[32] = 0;
|
||||
return JS_NewString(js,guid);
|
||||
char guid_str[33];
|
||||
|
||||
SDL_GUIDToString(guid, guid_str, 33);
|
||||
|
||||
return JS_NewString(js,guid_str);
|
||||
)
|
||||
|
||||
JSC_SCALL(os_openurl,
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define countof(a) (sizeof(a)/sizeof(*(a)))
|
||||
|
||||
static JSClassID enet_host_id;
|
||||
@@ -17,10 +19,16 @@ static void js_enet_host_finalizer(JSRuntime *rt, JSValue val) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// No explicit cleanup needed for ENetPeer itself
|
||||
(void)peer;
|
||||
JS_FreeValueRT(rt, *(JSValue*)peer->data);
|
||||
free(peer->data);
|
||||
}
|
||||
|
||||
/* ENet init/deinit */
|
||||
@@ -105,6 +113,16 @@ RET:
|
||||
return obj;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Host service: poll for events */
|
||||
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv) {
|
||||
@@ -127,9 +145,8 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||
ENetEvent event;
|
||||
while (enet_host_service(host, &event, secs*1000.0f) > 0) {
|
||||
JSValue event_obj = JS_NewObject(ctx);
|
||||
JSValue peer_obj = JS_NewObjectClass(ctx, enet_peer_class_id);
|
||||
JS_SetOpaque(peer_obj, event.peer);
|
||||
JS_SetPropertyStr(ctx, event_obj, "peer", peer_obj);
|
||||
printf("hit from peer with js value %p\n", event.peer->data);
|
||||
JS_SetPropertyStr(ctx, event_obj, "peer", peer_get_value(ctx, event.peer));
|
||||
|
||||
switch (event.type) {
|
||||
case ENET_EVENT_TYPE_CONNECT: {
|
||||
@@ -221,12 +238,7 @@ static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_ThrowInternalError(ctx, "Failed to initiate connection.");
|
||||
}
|
||||
|
||||
JSValue peer_obj = JS_NewObjectClass(ctx, enet_peer_class_id);
|
||||
if (JS_IsException(peer_obj)) {
|
||||
return peer_obj;
|
||||
}
|
||||
JS_SetOpaque(peer_obj, peer);
|
||||
return peer_obj;
|
||||
return peer_get_value(ctx, peer);
|
||||
}
|
||||
|
||||
/* Flush queued packets */
|
||||
@@ -438,6 +450,7 @@ static JSClassDef enet_host = {
|
||||
static JSClassDef enet_peer_class = {
|
||||
"ENetPeer",
|
||||
.finalizer = js_enet_peer_finalizer,
|
||||
.gc_mark = js_enet_peer_mark
|
||||
};
|
||||
|
||||
/* Function lists */
|
||||
@@ -456,6 +469,122 @@ static const JSCFunctionListEntry js_enet_host_funcs[] = {
|
||||
JS_CFUNC_DEF("address", 0, js_enet_host_get_address),
|
||||
};
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
#include <math.h> // 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 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 const JSCFunctionListEntry js_enet_peer_funcs[] = {
|
||||
JS_CFUNC_DEF("send", 1, js_enet_peer_send),
|
||||
JS_CFUNC_DEF("disconnect", 0, js_enet_peer_disconnect),
|
||||
@@ -465,6 +594,18 @@ 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),
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
var os = use('os')
|
||||
|
||||
var guy
|
||||
|
||||
$_.start(e => {
|
||||
console.log("Got a message: " + json.encode(e))
|
||||
switch(e.type) {
|
||||
case "greet":
|
||||
$_.connection(e => console.log(json.encode(e)), e.data)
|
||||
$_.delay(_ => {
|
||||
console.log(`sending stop message to ${json.encode(e.data)}`)
|
||||
$_.stop(e.data)
|
||||
}, 1);
|
||||
$_.couple(e.data)
|
||||
}
|
||||
console.log(json.encode(e))
|
||||
}, "tests/underling.js");
|
||||
|
||||
$_.contact((actor, reason) => {
|
||||
}, {
|
||||
address: "localhost",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user