portal spawning works

This commit is contained in:
2025-03-13 15:21:11 -05:00
parent eb3a41be69
commit 88d5f6455b
7 changed files with 127 additions and 67 deletions

View File

@@ -1,8 +1,6 @@
(function engine() {
prosperon.DOC = Symbol('+documentation+') // Symbol for documentation references
prosperon.id = 'newguy';
var listeners = new Map()
prosperon.on = function(type, callback) {
@@ -26,6 +24,8 @@ prosperon.dispatch = function(type, data) {
var os = use_embed('os')
var js = use_embed('js')
prosperon.on('exit', _ => { console.log('exiting') })
prosperon.on('SIGINT', function() {
os.exit(1)
})
@@ -131,7 +131,10 @@ var res_cache = {}
function console_rec(category, priority, line, file, msg) {
var now = time.now()
return `[${prosperon.id.substring(0,6)}] [${time.text(now, "mb d yyyy h:nn:ss")}] ${file}:${line}: [${category} ${priority}]: ${msg}\n`
var id = prosperon.name ? prosperon.name : prosperon.id
id = id.substring(0,6)
return `[${id}] [${time.text(now, "mb d yyyy h:nn:ss")}] ${file}:${line}: [${category} ${priority}]: ${msg}\n`
}
io.mkdir('.prosperon')
@@ -140,8 +143,6 @@ var logfile = io.open('.prosperon/log.txt')
function pprint(msg, lvl = 0) {
if (!logfile) return
if (typeof msg === "object") msg = JSON.stringify(msg, null, 2)
var file = "nofile"
var line = 0
@@ -524,6 +525,29 @@ var fnname = "doc"
script = `(function ${fnname}() { ${script}; })`
js.eval(DOCPATH, script)()
/*
When handling a message, the message appears like this:
{
type: type of message
- contact: used for contact messages
- stop: used to issue stop command
- etc
reply: ID this message will respond to (callback saved on the actor)
replycc: the actor that is waiting for the reply
target: ID of the actor that's supposed to receive the message. Only added to non direct sends (out of portals)
return: reply ID so the replycc actor can know what callback to send the message to
data: the actual content of the message
}
actors look like
{
id: the GUID of this actor
address: the IP this actor can be found at
port: the port of the IP the actor can be found at
}
*/
var enet = use('enet')
var util = use('util')
var math = use('math')
@@ -531,31 +555,36 @@ var crypto = use('crypto')
var nota = use('nota')
var HEADER = Symbol()
var PEER = Symbol()
var ar = 1 // seconds before reclamation
var ar = 60 // seconds before reclamation
var $actor = {
toString: print_actor
}
function print_actor() {
return json.encode(this.__ACTORDATA__, 1)
}
function json_actor() {
if (!this.__ACTORDATA__.portal) this.__ACTORDATA__.portal = local_portal
return this
function create_actor(data = {}) {
var newactor = Object.create($actor)
Object.defineProperty(data, 'address', {
get: function() { return local_address },
set: function(x) {},
enumerable:true
})
Object.defineProperty(data, 'port', {
get: function() { return local_port },
set: function(x) {},
enumerable:true
})
newactor.__ACTORDATA__ = data
return newactor
}
function create_actor(data) {
return {
__ACTORDATA__: data,
toString: print_actor,
toJSON: json_actor
}
}
var $_ = {
toString: print_actor,
toJSON: json_actor
}
var $_ = create_actor()
$_.random = crypto.random
$_.random[prosperon.DOC] = "returns a number between 0 and 1. There is a 50% chance that the result is less than 0.5."
@@ -571,7 +600,7 @@ globalThis.$_ = $_
var receive_fn = undefined
var greeters = {}
$_.is_actor = function(actor) { return !!actor.__ACTORDATA__ }
$_.is_actor = function(actor) { return actor.__ACTORDATA__ }
function peer_connection(peer) {
return {
@@ -610,19 +639,23 @@ $_.connection = function(callback, actor, config) {
}
$_.connection[prosperon.DOC] = "takes a callback function, an actor object, and a configuration record..."
var peers = {}
var peer_queue = new WeakMap()
var peers = {} // mapping of host to connected peers, so localhost:5678 -> some peer
var id_address = {} // mapping of id to a host, so some guid afnui3289 ... -> localhost:5678
var peer_queue = new WeakMap() // holds messages for peers that have not yet connected
var portal = undefined
var portal_fn
var local_portal
var portal_fn = undefined
var local_address = undefined
var local_port = undefined
$_.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}`)
if (!port) throw new Error("Requires a valid port.")
portal = enet.create_host({address: "any", port})
local_portal = `localhost:${port}`
local_address = 'localhost'
local_port = port
portal_fn = fn
console.log(`I am now ${$_}`)
}
$_.portal[prosperon.DOC] = "starts a public address that performs introduction services..."
@@ -638,24 +671,35 @@ function handle_host(e) {
peer_queue.delete(e.peer)
}
break
case "disconnect":
peer_queue.delete(e.peer)
for (var id in peers) if (peers[id] === e.peer) delete peers[id]
console.log('portal got disconnect')
break
case "receive":
handle_message(e.data)
// if e.data has a replycc, but it has no address, associate it with this peer
var 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
}
handle_message(data)
break
}
}
var contactor = undefined
$_.contact = function(callback, record) {
var sendto = { __ACTORDATA__: {address: record.address, port: record.port} }
$_.send(create_actor({
$_.send({
__ACTORDATA__: {
address: record.address,
port: record.port
}), record, callback)
}
}, record, callback)
}
$_.contact[prosperon.DOC] = "The contact function sends a message to a portal..."
@@ -712,8 +756,11 @@ $_.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 (actor.__ACTORDATA__.id === prosperon.id) {
if (receive_fn)
receive_fn(message.data)
return
}
@@ -748,19 +795,20 @@ $_.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]) {
if (actor[HEADER] && actor[HEADER].replycc) {
var header = actor[HEADER]
console.log(`replying to a message: ${json.encode(header)}`)
if (!actor.__ACTORDATA__) actor.__ACTORDATA__ = {}
actor.__ACTORDATA__.id = header.replycc
if (!header.replycc || !$_.is_actor(header.replycc)) throw new Error(`Supplied actor had a return, but it's not a valid actor! ${json.encode(actor[HEADER])}`);
var header = actor[HEADER]
actor = header.replycc
send.return = header.reply
}
if (reply) {
var id = util.guid()
replies[id] = reply
send.reply = id
send.replycc = prosperon.id
send.reply = id // the reply function to hit, local to this actor
send.replycc = $_ // the actor itself
}
actor_send(actor, send)
@@ -773,13 +821,11 @@ cmd.process(prosperon.argv)
if (!prosperon.args.id) prosperon.id = util.guid()
else prosperon.id = prosperon.args.id
$_.__ACTORDATA__ = {id: prosperon.id}
$_.toJSON = json_actor
$_.toSring = print_actor
$_.__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} }
if (prosperon.args.root) root = json.decode(prosperon.args.root)
else root = $_
os.mailbox_start(prosperon.id)
@@ -789,6 +835,7 @@ if (prosperon.args.program) actor.spawn(prosperon.args.program)
var unneeded_timer = $_.delay($_.stop, ar)
function destroyself() {
console.log(`Got the message to destroy self.`)
if (overling) actor_send(overling, { type: "stopped", id: prosperon.id })
os.exit(0)
}
@@ -805,6 +852,7 @@ function handle_actor_disconnect(id) {
}
function handle_message(msg) {
if (msg instanceof ArrayBuffer)
msg = nota.decode(msg)
if (msg.target) {
@@ -816,7 +864,6 @@ function handle_message(msg) {
unneeded_timer()
switch (msg.type) {
case "user":
console.log(`handling message ${json.encode(msg)}`)
var letter = msg.data
delete msg.data
letter[HEADER] = msg
@@ -828,6 +875,7 @@ function handle_message(msg) {
delete replies[msg.return]
return
}
if (receive_fn)
receive_fn(letter)
break
@@ -854,7 +902,6 @@ function handle_message(msg) {
case "greet":
var greeter = greeters[msg.id]
console.log(`got a greet from message ${json.encode(msg)}`)
if (greeter) greeter({type: "actor_started", actor: create_actor(msg)})
}
unneeded_timer = $_.delay(unneeded_fn, unneeded_time)

View File

@@ -7676,13 +7676,16 @@ static void signal_handler(int sig) {
}
if (!str) return;
// script_evalf("prosperon.dispatch('%s')", str);
JSContext *js = SDL_GetTLS(&js_id);
printf("dispatching to js %p\n", js);
script_evalf(js, "prosperon.dispatch('%s')", str);
}
static void exit_handler()
{
// script_evalf("prosperon.dispatch('exit')");
// script_stop();
JSContext *js = SDL_GetTLS(&js_id);
script_evalf(js, "prosperon.dispatch('exit')");
}
#include "monocypher.h"

View File

@@ -5,6 +5,7 @@
#include <SDL3/SDL.h>
extern SDL_TLSID on_exception;
extern SDL_TLSID js_id;
void script_startup(int argc, char **argv);
void script_stop(JSContext*);

View File

@@ -4,7 +4,10 @@ function contact_fn(actor,reason) {
if (actor) {
console.log(`Got an actor: ${json.encode(actor)}`)
$_.send(actor, {greet: "Hello!"})
$_.send(actor, {greet: "Hello!"}, e => {
console.log(`Got the response ${json.encode(e)}. Goodbye!`);
$_.stop()
})
}
else
console.log(`Did not get an actor: ${json.encode(reason)}`)
@@ -17,7 +20,7 @@ $_.contact(contact_fn,
password: "abc123"
});
$_.contact(contact_fn, {
/*$_.contact(contact_fn, {
address: "localhost",
port: 5678,
password: "123abc"
@@ -29,3 +32,4 @@ $_.contact(contact_fn, {
})
*/

View File

@@ -1,6 +1,6 @@
var os = use('os')
console.log("START")
$_.delay(_ => {
$_.start(e => {
switch(e.type) {
case "actor_started":
@@ -12,5 +12,7 @@ $_.start(e => {
$_.couple(e.actor)
$_.stop(e.actor)
$_.stop()
}
}, "tests/underling.js");
}, 3)

View File

@@ -8,3 +8,9 @@ $_.portal(e => {
else
$_.send(e, $_)
}, 5678);
$_.receiver(e => {
console.log(`Got message: ${json.encode(e)}`)
$_.send(e, {greet: "Hello back!"})
$_.delay(_ => $_.stop(), 0.2)
})

View File

@@ -4,11 +4,8 @@ var os = use('os')
var children = []
$_.start(e => {
console.log('Portal actor finished starting.')
children.push(e.actor)
$_.start(e => {
children.push(e.actor)
console.log('Contact actor finished starting.')
}, "tests/contact.js")
}, "tests/portal.js")
os.createprocess(["./prosperon", "tests/portal.js"])
$_.delay(_ => {
os.createprocess(["./prosperon", "tests/contact.js"])
}, 0.2)