|
|
|
|
@@ -1,17 +1,21 @@
|
|
|
|
|
(function engine() {
|
|
|
|
|
// Hidden vars (os, actorsym, init, core_path) come from env
|
|
|
|
|
var ACTORDATA = actorsym
|
|
|
|
|
var SYSYM = '__SYSTEM__'
|
|
|
|
|
|
|
|
|
|
var _cell = {}
|
|
|
|
|
var need_stop = false
|
|
|
|
|
|
|
|
|
|
var dylib_ext
|
|
|
|
|
|
|
|
|
|
switch(os.platform()) {
|
|
|
|
|
case 'Windows': dylib_ext = '.dll'; break;
|
|
|
|
|
case 'macOS': dylib_ext = '.dylib'; break;
|
|
|
|
|
case 'Linux': dylib_ext = '.so'; break;
|
|
|
|
|
}
|
|
|
|
|
var cases = {
|
|
|
|
|
Windows: '.dll',
|
|
|
|
|
macOS: '.dylib',
|
|
|
|
|
Linux: '.so'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print(os.platform())
|
|
|
|
|
|
|
|
|
|
dylib_ext = cases[os.platform()]
|
|
|
|
|
|
|
|
|
|
var MOD_EXT = '.cm'
|
|
|
|
|
var ACTOR_EXT = '.ce'
|
|
|
|
|
@@ -51,14 +55,16 @@ var fd = use_embed('fd')
|
|
|
|
|
// Get the shop path from HOME environment
|
|
|
|
|
var home = os.getenv('HOME') || os.getenv('USERPROFILE')
|
|
|
|
|
if (!home) {
|
|
|
|
|
throw Error('Could not determine home directory')
|
|
|
|
|
os.print('Could not determine home directory\n')
|
|
|
|
|
os.exit(1)
|
|
|
|
|
}
|
|
|
|
|
var shop_path = home + '/.cell'
|
|
|
|
|
var packages_path = shop_path + '/packages'
|
|
|
|
|
var core_path = packages_path + '/core'
|
|
|
|
|
|
|
|
|
|
if (!fd.is_dir(core_path)) {
|
|
|
|
|
throw Error('Cell shop not found at ' + shop_path + '. Run "cell install" to set up.')
|
|
|
|
|
os.print('Cell shop not found at ' + shop_path + '. Run "cell install" to set up.\n')
|
|
|
|
|
os.exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var use_cache = {}
|
|
|
|
|
@@ -79,7 +85,7 @@ function use_core(path) {
|
|
|
|
|
var script_blob = fd.slurp(file_path)
|
|
|
|
|
var script = text(script_blob)
|
|
|
|
|
var mod = `(function setup_module(use){${script}})`
|
|
|
|
|
var fn = js.eval('core:' + path, mod)
|
|
|
|
|
var fn = mach_eval('core:' + path, mod)
|
|
|
|
|
var result = call(fn,sym, [use_core])
|
|
|
|
|
use_cache[cache_key] = result;
|
|
|
|
|
return result;
|
|
|
|
|
@@ -133,32 +139,27 @@ function log(name, args) {
|
|
|
|
|
var caller = caller_data(1)
|
|
|
|
|
var msg = args[0]
|
|
|
|
|
|
|
|
|
|
switch(name) {
|
|
|
|
|
case 'console':
|
|
|
|
|
os.print(console_rec(caller.line, caller.file, msg))
|
|
|
|
|
break
|
|
|
|
|
case 'error':
|
|
|
|
|
msg = msg ?? Error()
|
|
|
|
|
if (is_proto(msg, Error))
|
|
|
|
|
msg = msg.name + ": " + msg.message + "\n" + msg.stack
|
|
|
|
|
os.print(console_rec(caller.line, caller.file, msg))
|
|
|
|
|
break
|
|
|
|
|
case 'system':
|
|
|
|
|
msg = "[SYSTEM] " + msg
|
|
|
|
|
os.print(console_rec(caller.line, caller.file, msg))
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
log.console(`unknown log type: ${name}`)
|
|
|
|
|
break
|
|
|
|
|
if (name == 'console') {
|
|
|
|
|
os.print(console_rec(caller.line, caller.file, msg))
|
|
|
|
|
} else if (name == 'error') {
|
|
|
|
|
if (msg == null) msg = Error()
|
|
|
|
|
if (is_proto(msg, Error))
|
|
|
|
|
msg = msg.name + ": " + msg.message + "\n" + msg.stack
|
|
|
|
|
os.print(console_rec(caller.line, caller.file, msg))
|
|
|
|
|
} else if (name == 'system') {
|
|
|
|
|
msg = "[SYSTEM] " + msg
|
|
|
|
|
os.print(console_rec(caller.line, caller.file, msg))
|
|
|
|
|
} else {
|
|
|
|
|
log.console(`unknown log type: ${name}`)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function disrupt(err)
|
|
|
|
|
function actor_die(err)
|
|
|
|
|
{
|
|
|
|
|
if (is_function(err.toString)) {
|
|
|
|
|
os.print(err.toString())
|
|
|
|
|
os.print("\n")
|
|
|
|
|
os.print(err.stack)
|
|
|
|
|
if (err && is_function(err.toString)) {
|
|
|
|
|
os.print(err.toString())
|
|
|
|
|
os.print("\n")
|
|
|
|
|
if (err.stack) os.print(err.stack)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (overling) {
|
|
|
|
|
@@ -185,14 +186,14 @@ function disrupt(err)
|
|
|
|
|
log.console(err.stack)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
actor_mod.disrupt()
|
|
|
|
|
actor_mod["disrupt"]()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
actor_mod.on_exception(disrupt)
|
|
|
|
|
actor_mod.on_exception(actor_die)
|
|
|
|
|
|
|
|
|
|
_cell.args = init ?? {}
|
|
|
|
|
_cell.args = init != null ? init : {}
|
|
|
|
|
_cell.id = "newguy"
|
|
|
|
|
|
|
|
|
|
function create_actor(desc = {id:guid()}) {
|
|
|
|
|
@@ -241,11 +242,15 @@ os.runtime_env = runtime_env
|
|
|
|
|
|
|
|
|
|
$_.time_limit = function(requestor, seconds)
|
|
|
|
|
{
|
|
|
|
|
if (!pronto.is_requestor(requestor))
|
|
|
|
|
throw Error('time_limit: first argument must be a requestor');
|
|
|
|
|
if (!is_number(seconds) || seconds <= 0)
|
|
|
|
|
throw Error('time_limit: seconds must be a positive number');
|
|
|
|
|
|
|
|
|
|
if (!pronto.is_requestor(requestor)) {
|
|
|
|
|
log.error('time_limit: first argument must be a requestor')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
if (!is_number(seconds) || seconds <= 0) {
|
|
|
|
|
log.error('time_limit: seconds must be a positive number')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return function time_limit_requestor(callback, value) {
|
|
|
|
|
pronto.check_callback(callback, 'time_limit')
|
|
|
|
|
var finished = false
|
|
|
|
|
@@ -260,7 +265,14 @@ $_.time_limit = function(requestor, seconds)
|
|
|
|
|
timer_cancel = null
|
|
|
|
|
}
|
|
|
|
|
if (requestor_cancel) {
|
|
|
|
|
try { pronto.requestor_cancel(reason) } catch (_) {}
|
|
|
|
|
requestor_cancel(reason)
|
|
|
|
|
requestor_cancel = null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function safe_cancel_requestor(reason) {
|
|
|
|
|
if (requestor_cancel) {
|
|
|
|
|
requestor_cancel(reason)
|
|
|
|
|
requestor_cancel = null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -268,15 +280,12 @@ $_.time_limit = function(requestor, seconds)
|
|
|
|
|
timer_cancel = $_.delay(function() {
|
|
|
|
|
if (finished) return
|
|
|
|
|
def reason = make_reason(factory, 'Timeout.', seconds)
|
|
|
|
|
if (requestor_cancel) {
|
|
|
|
|
try { requestor_cancel(reason) } catch (_) {}
|
|
|
|
|
requestor_cancel = null
|
|
|
|
|
}
|
|
|
|
|
safe_cancel_requestor(reason)
|
|
|
|
|
finished = true
|
|
|
|
|
callback(null, reason)
|
|
|
|
|
}, seconds)
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
function do_request() {
|
|
|
|
|
requestor_cancel = requestor(function(val, reason) {
|
|
|
|
|
if (finished) return
|
|
|
|
|
finished = true
|
|
|
|
|
@@ -286,16 +295,14 @@ $_.time_limit = function(requestor, seconds)
|
|
|
|
|
}
|
|
|
|
|
callback(val, reason)
|
|
|
|
|
}, value)
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
cancel(ex)
|
|
|
|
|
callback(null, ex)
|
|
|
|
|
} disruption {
|
|
|
|
|
cancel(Error('requestor failed'))
|
|
|
|
|
callback(null, Error('requestor failed'))
|
|
|
|
|
}
|
|
|
|
|
do_request()
|
|
|
|
|
|
|
|
|
|
return function(reason) {
|
|
|
|
|
if (requestor_cancel) {
|
|
|
|
|
try { requestor_cancel(reason) } catch (_) {}
|
|
|
|
|
requestor_cancel = null
|
|
|
|
|
}
|
|
|
|
|
safe_cancel_requestor(reason)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -408,52 +415,54 @@ var portal_fn = null
|
|
|
|
|
|
|
|
|
|
// takes a function input value that will eventually be called with the current time in number form.
|
|
|
|
|
$_.portal = function(fn, port) {
|
|
|
|
|
if (portal) throw Error(`Already started a portal listening on ${portal.port}`)
|
|
|
|
|
if (!port) throw Error("Requires a valid port.")
|
|
|
|
|
if (portal) {
|
|
|
|
|
log.error(`Already started a portal listening on ${portal.port}`)
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
if (!port) {
|
|
|
|
|
log.error("Requires a valid port.")
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
log.system(`starting a portal on port ${port}`)
|
|
|
|
|
portal = enet.create_host({address: "any", port})
|
|
|
|
|
portal_fn = fn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handle_host(e) {
|
|
|
|
|
switch (e.type) {
|
|
|
|
|
case "connect":
|
|
|
|
|
log.system(`connected a new peer: ${e.peer.address}:${e.peer.port}`)
|
|
|
|
|
peers[`${e.peer.address}:${e.peer.port}`] = e.peer
|
|
|
|
|
var queue = peer_queue.get(e.peer)
|
|
|
|
|
if (queue) {
|
|
|
|
|
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg)))
|
|
|
|
|
log.system(`sent ${msg} out of queue`)
|
|
|
|
|
peer_queue.delete(e.peer)
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
case "disconnect":
|
|
|
|
|
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
|
|
|
|
|
var queue = peer_queue.get(e.peer)
|
|
|
|
|
if (queue) {
|
|
|
|
|
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg)))
|
|
|
|
|
log.system(`sent ${msg} out of queue`)
|
|
|
|
|
peer_queue.delete(e.peer)
|
|
|
|
|
arrfor(array(peers), function(id, index) {
|
|
|
|
|
if (peers[id] == e.peer) delete peers[id]
|
|
|
|
|
}
|
|
|
|
|
} else if (e.type == "disconnect") {
|
|
|
|
|
peer_queue.delete(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)
|
|
|
|
|
} else if (e.type == "receive") {
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
function populate_actor_addresses(obj) {
|
|
|
|
|
if (!is_object(obj)) return
|
|
|
|
|
if (obj[ACTORDATA] && !obj[ACTORDATA].address) {
|
|
|
|
|
obj[ACTORDATA].address = e.peer.address
|
|
|
|
|
obj[ACTORDATA].port = e.peer.port
|
|
|
|
|
}
|
|
|
|
|
arrfor(array(obj), function(key, index) {
|
|
|
|
|
if (key in obj)
|
|
|
|
|
populate_actor_addresses(obj[key])
|
|
|
|
|
})
|
|
|
|
|
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port)
|
|
|
|
|
break
|
|
|
|
|
case "receive":
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
function populate_actor_addresses(obj) {
|
|
|
|
|
if (!is_object(obj)) return
|
|
|
|
|
if (obj[ACTORDATA] && !obj[ACTORDATA].address) {
|
|
|
|
|
obj[ACTORDATA].address = e.peer.address
|
|
|
|
|
obj[ACTORDATA].port = e.peer.port
|
|
|
|
|
}
|
|
|
|
|
arrfor(array(obj), function(key, index) {
|
|
|
|
|
if (key in obj)
|
|
|
|
|
populate_actor_addresses(obj[key])
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
if (data.data) populate_actor_addresses(data.data)
|
|
|
|
|
turn(data)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if (data.data) populate_actor_addresses(data.data)
|
|
|
|
|
turn(data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -487,10 +496,14 @@ $_.stop = function stop(actor) {
|
|
|
|
|
need_stop = true
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!is_actor(actor))
|
|
|
|
|
throw Error('Can only call stop on an actor.')
|
|
|
|
|
if (is_null(underlings[actor[ACTORDATA].id]))
|
|
|
|
|
throw Error('Can only call stop on an underling or self.')
|
|
|
|
|
if (!is_actor(actor)) {
|
|
|
|
|
log.error('Can only call stop on an actor.')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
if (is_null(underlings[actor[ACTORDATA].id])) {
|
|
|
|
|
log.error('Can only call stop on an underling or self.')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sys_msg(actor, {kind:"stop"})
|
|
|
|
|
}
|
|
|
|
|
@@ -527,20 +540,22 @@ function actor_prep(actor, send) {
|
|
|
|
|
|
|
|
|
|
// Send a message immediately without queuing
|
|
|
|
|
function actor_send_immediate(actor, send) {
|
|
|
|
|
try {
|
|
|
|
|
actor_send(actor, send);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
log.error("Failed to send immediate message:", err);
|
|
|
|
|
}
|
|
|
|
|
actor_send(actor, send)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function actor_send(actor, message) {
|
|
|
|
|
if (actor[HEADER] && !actor[HEADER].replycc) // attempting to respond to a message but sender is not expecting; silently drop
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if (!is_actor(actor) && !is_actor(actor.replycc)) throw Error(`Must send to an actor object. Attempted send to ${actor}`)
|
|
|
|
|
|
|
|
|
|
if (!is_object(message)) throw Error('Must send an object record.')
|
|
|
|
|
if (!is_actor(actor) && !is_actor(actor.replycc)) {
|
|
|
|
|
log.error(`Must send to an actor object. Attempted send to ${actor}`)
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_object(message)) {
|
|
|
|
|
log.error('Must send an object record.')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// message to self
|
|
|
|
|
if (actor[ACTORDATA].id == _cell.id) {
|
|
|
|
|
@@ -583,12 +598,10 @@ function actor_send(actor, message) {
|
|
|
|
|
// Holds all messages queued during the current turn.
|
|
|
|
|
var message_queue = []
|
|
|
|
|
|
|
|
|
|
var need_stop = false
|
|
|
|
|
|
|
|
|
|
function send_messages() {
|
|
|
|
|
function send_messages() {
|
|
|
|
|
// if we've been flagged to stop, bail out before doing anything
|
|
|
|
|
if (need_stop) {
|
|
|
|
|
disrupt()
|
|
|
|
|
actor_die()
|
|
|
|
|
message_queue = []
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
@@ -608,19 +621,26 @@ var need_stop = false
|
|
|
|
|
var replies = {}
|
|
|
|
|
|
|
|
|
|
function send(actor, message, reply) {
|
|
|
|
|
if (!is_object(actor))
|
|
|
|
|
throw Error(`Must send to an actor object. Provided: ${actor}`);
|
|
|
|
|
if (!is_object(actor)) {
|
|
|
|
|
log.error(`Must send to an actor object. Provided: ${actor}`)
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_object(message))
|
|
|
|
|
throw Error('Message must be an object')
|
|
|
|
|
if (!is_object(message)) {
|
|
|
|
|
log.error('Message must be an object')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
var send_msg = {type:"user", data: message}
|
|
|
|
|
var target = actor
|
|
|
|
|
|
|
|
|
|
if (actor[HEADER] && actor[HEADER].replycc) {
|
|
|
|
|
var header = actor[HEADER]
|
|
|
|
|
if (!header.replycc || !is_actor(header.replycc))
|
|
|
|
|
throw Error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`)
|
|
|
|
|
if (!header.replycc || !is_actor(header.replycc)) {
|
|
|
|
|
log.error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`)
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
actor = header.replycc
|
|
|
|
|
target = header.replycc
|
|
|
|
|
send_msg.return = header.reply
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -638,7 +658,7 @@ function send(actor, message, reply) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Instead of sending immediately, queue it
|
|
|
|
|
actor_prep(actor, send_msg);
|
|
|
|
|
actor_prep(target, send_msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stone(send)
|
|
|
|
|
@@ -669,7 +689,7 @@ overling = _cell.args.overling
|
|
|
|
|
$_.overling = overling
|
|
|
|
|
|
|
|
|
|
root = _cell.args.root
|
|
|
|
|
root ??= $_.self
|
|
|
|
|
if (root == null) root = $_.self
|
|
|
|
|
|
|
|
|
|
if (overling) {
|
|
|
|
|
$_.couple(overling) // auto couple to overling
|
|
|
|
|
@@ -705,36 +725,35 @@ function handle_actor_disconnect(id) {
|
|
|
|
|
delete greeters[id]
|
|
|
|
|
}
|
|
|
|
|
log.system(`actor ${id} disconnected`)
|
|
|
|
|
if (!is_null(couplings[id])) disrupt("coupled actor died") // couplings now disrupts instead of stop
|
|
|
|
|
if (!is_null(couplings[id])) actor_die("coupled actor died") // couplings now disrupts instead of stop
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handle_sysym(msg)
|
|
|
|
|
{
|
|
|
|
|
var from
|
|
|
|
|
switch(msg.kind) {
|
|
|
|
|
case 'stop':
|
|
|
|
|
disrupt("got stop message")
|
|
|
|
|
break
|
|
|
|
|
case 'underling':
|
|
|
|
|
from = msg.from
|
|
|
|
|
var greeter = greeters[from[ACTORDATA].id]
|
|
|
|
|
if (greeter) greeter(msg.message)
|
|
|
|
|
if (msg.message.type == 'disrupt')
|
|
|
|
|
delete underlings[from[ACTORDATA].id]
|
|
|
|
|
break
|
|
|
|
|
case 'contact':
|
|
|
|
|
if (portal_fn) {
|
|
|
|
|
var letter2 = msg.data
|
|
|
|
|
letter2[HEADER] = msg
|
|
|
|
|
delete msg.data
|
|
|
|
|
portal_fn(letter2)
|
|
|
|
|
} else throw Error('Got a contact message, but no portal is established.')
|
|
|
|
|
break
|
|
|
|
|
case 'couple': // from must be notified when we die
|
|
|
|
|
from = msg.from
|
|
|
|
|
underlings[from[ACTORDATA].id] = true
|
|
|
|
|
log.system(`actor ${from} is coupled to me`)
|
|
|
|
|
break
|
|
|
|
|
if (msg.kind == 'stop') {
|
|
|
|
|
actor_die("got stop message")
|
|
|
|
|
} else if (msg.kind == 'underling') {
|
|
|
|
|
from = msg.from
|
|
|
|
|
var greeter = greeters[from[ACTORDATA].id]
|
|
|
|
|
if (greeter) greeter(msg.message)
|
|
|
|
|
if (msg.message.type == 'disrupt')
|
|
|
|
|
delete underlings[from[ACTORDATA].id]
|
|
|
|
|
} else if (msg.kind == 'contact') {
|
|
|
|
|
if (portal_fn) {
|
|
|
|
|
var letter2 = msg.data
|
|
|
|
|
letter2[HEADER] = msg
|
|
|
|
|
delete msg.data
|
|
|
|
|
portal_fn(letter2)
|
|
|
|
|
} else {
|
|
|
|
|
log.error('Got a contact message, but no portal is established.')
|
|
|
|
|
disrupt
|
|
|
|
|
}
|
|
|
|
|
} else if (msg.kind == 'couple') {
|
|
|
|
|
// from must be notified when we die
|
|
|
|
|
from = msg.from
|
|
|
|
|
underlings[from[ACTORDATA].id] = true
|
|
|
|
|
log.system(`actor ${from} is coupled to me`)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -744,30 +763,27 @@ function handle_message(msg) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (msg.type) {
|
|
|
|
|
case "user":
|
|
|
|
|
var letter = msg.data // what the sender really sent
|
|
|
|
|
_ObjectDefineProperty(letter, HEADER, {
|
|
|
|
|
value: msg, enumerable: false
|
|
|
|
|
})
|
|
|
|
|
_ObjectDefineProperty(letter, ACTORDATA, { // this is so is_actor == true
|
|
|
|
|
value: { reply: msg.reply }, enumerable: false
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (msg.return) {
|
|
|
|
|
var fn = replies[msg.return]
|
|
|
|
|
if (fn) fn(letter)
|
|
|
|
|
delete replies[msg.return]
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (receive_fn) receive_fn(letter)
|
|
|
|
|
if (msg.type == "user") {
|
|
|
|
|
var letter = msg.data // what the sender really sent
|
|
|
|
|
_ObjectDefineProperty(letter, HEADER, {
|
|
|
|
|
value: msg, enumerable: false
|
|
|
|
|
})
|
|
|
|
|
_ObjectDefineProperty(letter, ACTORDATA, { // this is so is_actor == true
|
|
|
|
|
value: { reply: msg.reply }, enumerable: false
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (msg.return) {
|
|
|
|
|
var fn = replies[msg.return]
|
|
|
|
|
if (fn) fn(letter)
|
|
|
|
|
delete replies[msg.return]
|
|
|
|
|
return
|
|
|
|
|
case "stopped":
|
|
|
|
|
handle_actor_disconnect(msg.id)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (receive_fn) receive_fn(letter)
|
|
|
|
|
} else if (msg.type == "stopped") {
|
|
|
|
|
handle_actor_disconnect(msg.id)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function enet_check()
|
|
|
|
|
{
|
|
|
|
|
@@ -792,8 +808,10 @@ if (!locator) {
|
|
|
|
|
locator = shop.resolve_locator(_cell.args.program + ".ce", pkg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!locator)
|
|
|
|
|
throw Error(`Main program ${_cell.args.program} could not be found`)
|
|
|
|
|
if (!locator) {
|
|
|
|
|
os.print(`Main program ${_cell.args.program} could not be found\n`)
|
|
|
|
|
os.exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$_.clock(_ => {
|
|
|
|
|
// Get capabilities for the main program
|
|
|
|
|
@@ -818,7 +836,6 @@ $_.clock(_ => {
|
|
|
|
|
var val = call(locator.symbol, null, [_cell.args.arg, use_fn, env])
|
|
|
|
|
|
|
|
|
|
if (val)
|
|
|
|
|
throw Error('Program must not return anything');
|
|
|
|
|
log.error('Program must not return anything')
|
|
|
|
|
disrupt
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
})()
|