bootstrap
This commit is contained in:
@@ -6,17 +6,13 @@ var SYSYM = '__SYSTEM__'
|
||||
var _cell = {}
|
||||
var need_stop = false
|
||||
|
||||
var dylib_ext
|
||||
|
||||
var cases = {
|
||||
Windows: '.dll',
|
||||
macOS: '.dylib',
|
||||
Linux: '.so'
|
||||
}
|
||||
|
||||
print(os.platform())
|
||||
|
||||
dylib_ext = cases[os.platform()]
|
||||
var dylib_ext = cases[os.platform()]
|
||||
|
||||
var MOD_EXT = '.cm'
|
||||
var ACTOR_EXT = '.ce'
|
||||
@@ -67,11 +63,14 @@ function use_core(path) {
|
||||
return use_cache[cache_key]
|
||||
|
||||
var sym = use_embed(replace(path, '/', '_'))
|
||||
var result = null
|
||||
var script = null
|
||||
var ast = null
|
||||
|
||||
// Check for pre-compiled .mach file first
|
||||
var mach_path = core_path + '/' + path + '.mach'
|
||||
if (fd.is_file(mach_path)) {
|
||||
var result = mach_load(fd.slurp(mach_path), {use: use_core})
|
||||
result = mach_load(fd.slurp(mach_path), {use: use_core})
|
||||
use_cache[cache_key] = result
|
||||
return result
|
||||
}
|
||||
@@ -79,9 +78,9 @@ function use_core(path) {
|
||||
// Fall back to source .cm file — compile at runtime
|
||||
var file_path = core_path + '/' + path + MOD_EXT
|
||||
if (fd.is_file(file_path)) {
|
||||
var script = text(fd.slurp(file_path))
|
||||
var ast = analyze(script, file_path)
|
||||
var result = run_ast_fn('core:' + path, ast, {use: use_core})
|
||||
script = text(fd.slurp(file_path))
|
||||
ast = analyze(script, file_path)
|
||||
result = run_ast_fn('core:' + path, ast, {use: use_core})
|
||||
use_cache[cache_key] = result
|
||||
return result
|
||||
}
|
||||
@@ -108,21 +107,24 @@ function is_actor(value) {
|
||||
var ENETSERVICE = 0.1
|
||||
var REPLYTIMEOUT = 60 // seconds before replies are ignored
|
||||
|
||||
function caller_data(depth = 0)
|
||||
function caller_data(depth)
|
||||
{
|
||||
var _depth = depth == null ? 0 : depth
|
||||
var file = "nofile"
|
||||
var line = 0
|
||||
|
||||
var caller = array(Error().stack, "\n")[1+depth]
|
||||
var md = null
|
||||
var m = null
|
||||
|
||||
var caller = array(Error().stack, "\n")[1+_depth]
|
||||
if (caller) {
|
||||
var md = extract(caller, /\((.*)\:/)
|
||||
var m = md ? md[1] : "SCRIPT"
|
||||
md = extract(caller, /\((.*)\:/)
|
||||
m = md ? md[1] : "SCRIPT"
|
||||
if (m) file = m
|
||||
md = extract(caller, /\:(\d*)\)/)
|
||||
m = md ? md[1] : 0
|
||||
if (m) line = m
|
||||
}
|
||||
|
||||
|
||||
return {file,line}
|
||||
}
|
||||
|
||||
@@ -152,6 +154,9 @@ function log(name, args) {
|
||||
|
||||
function actor_die(err)
|
||||
{
|
||||
var reason = null
|
||||
var unders = null
|
||||
|
||||
if (err && is_function(err.toString)) {
|
||||
os.print(err.toString())
|
||||
os.print("\n")
|
||||
@@ -161,14 +166,14 @@ function actor_die(err)
|
||||
if (overling) {
|
||||
if (err) {
|
||||
// with an err, this is a forceful disrupt
|
||||
var reason = (is_proto(err, Error)) ? err.stack : err
|
||||
reason = (is_proto(err, Error)) ? err.stack : err
|
||||
report_to_overling({type:'disrupt', reason})
|
||||
} else
|
||||
report_to_overling({type:'stop'})
|
||||
}
|
||||
|
||||
if (underlings) {
|
||||
var unders = array(underlings)
|
||||
unders = array(underlings)
|
||||
arrfor(unders, function(id, index) {
|
||||
log.console(`calling on ${id} to disrupt too`)
|
||||
$_.stop(create_actor({id}))
|
||||
@@ -192,9 +197,10 @@ function actor_die(err)
|
||||
_cell.args = init != null ? init : {}
|
||||
_cell.id = "newguy"
|
||||
|
||||
function create_actor(desc = {id:guid()}) {
|
||||
function create_actor(desc) {
|
||||
var _desc = desc == null ? {id:guid()} : desc
|
||||
var actor = {}
|
||||
actor[ACTORDATA] = desc
|
||||
actor[ACTORDATA] = _desc
|
||||
return actor
|
||||
}
|
||||
|
||||
@@ -343,9 +349,10 @@ REPLYTIMEOUT = config.reply_timeout
|
||||
}
|
||||
*/
|
||||
|
||||
function guid(bits = 256)
|
||||
function guid(bits)
|
||||
{
|
||||
var guid = blob(bits, os.random)
|
||||
var _bits = bits == null ? 256 : bits
|
||||
var guid = blob(_bits, os.random)
|
||||
stone(guid)
|
||||
return text(guid,'h')
|
||||
}
|
||||
@@ -427,13 +434,16 @@ $_.portal = function(fn, port) {
|
||||
}
|
||||
|
||||
function handle_host(e) {
|
||||
var queue = null
|
||||
var data = 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
|
||||
var queue = peer_queue.get(e.peer)
|
||||
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`)
|
||||
log.system(`sent queue out of queue`)
|
||||
peer_queue.delete(e.peer)
|
||||
}
|
||||
} else if (e.type == "disconnect") {
|
||||
@@ -443,27 +453,28 @@ function handle_host(e) {
|
||||
})
|
||||
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port)
|
||||
} else if (e.type == "receive") {
|
||||
var data = nota.decode(e.data)
|
||||
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)
|
||||
if (data.data) populate_actor_addresses(data.data, e)
|
||||
turn(data)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
arrfor(array(obj), function(key, index) {
|
||||
if (key in obj)
|
||||
populate_actor_addresses(obj[key], e)
|
||||
})
|
||||
}
|
||||
|
||||
// takes a callback function, an actor object, and a configuration record for getting information about the status of a connection to the actor. The configuration record is used to request the sort of information that needs to be communicated. This can include latency, bandwidth, activity, congestion, cost, partitions. The callback is given a record containing the requested information.
|
||||
$_.contact = function(callback, record) {
|
||||
send(create_actor(record), record, callback)
|
||||
@@ -512,12 +523,13 @@ $_.unneeded = function unneeded(fn, seconds) {
|
||||
}
|
||||
|
||||
// schedules the invocation of a function after a specified amount of time.
|
||||
$_.delay = function delay(fn, seconds = 0) {
|
||||
$_.delay = function delay(fn, seconds) {
|
||||
var _seconds = seconds == null ? 0 : seconds
|
||||
function delay_turn() {
|
||||
fn()
|
||||
send_messages()
|
||||
}
|
||||
var id = actor_mod.delay(delay_turn, seconds)
|
||||
var id = actor_mod.delay(delay_turn, _seconds)
|
||||
return function() { actor_mod.removetimer(id) }
|
||||
}
|
||||
|
||||
@@ -542,6 +554,9 @@ function actor_send_immediate(actor, send) {
|
||||
}
|
||||
|
||||
function actor_send(actor, message) {
|
||||
var wota_blob = null
|
||||
var peer = null
|
||||
|
||||
if (actor[HEADER] && !actor[HEADER].replycc) // attempting to respond to a message but sender is not expecting; silently drop
|
||||
return
|
||||
|
||||
@@ -560,22 +575,21 @@ function actor_send(actor, message) {
|
||||
if (receive_fn) receive_fn(message.data)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// message to actor in same flock
|
||||
if (actor[ACTORDATA].id && actor_mod.mailbox_exist(actor[ACTORDATA].id)) {
|
||||
var wota_blob = wota.encode(message)
|
||||
// log.console(`sending wota blob of ${length(wota_blob)/8} bytes`)
|
||||
wota_blob = wota.encode(message)
|
||||
actor_mod.mailbox_push(actor[ACTORDATA].id, wota_blob)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (actor[ACTORDATA].address) {
|
||||
if (actor[ACTORDATA].id)
|
||||
message.target = actor[ACTORDATA].id
|
||||
else
|
||||
message.type = "contact"
|
||||
|
||||
var peer = peers[actor[ACTORDATA].address + ":" + actor[ACTORDATA].port]
|
||||
|
||||
peer = peers[actor[ACTORDATA].address + ":" + actor[ACTORDATA].port]
|
||||
if (!peer) {
|
||||
if (!portal) {
|
||||
log.system(`creating a contactor ...`)
|
||||
@@ -619,6 +633,11 @@ function send_messages() {
|
||||
var replies = {}
|
||||
|
||||
function send(actor, message, reply) {
|
||||
var send_msg = null
|
||||
var target = null
|
||||
var header = null
|
||||
var id = null
|
||||
|
||||
if (!is_object(actor)) {
|
||||
log.error(`Must send to an actor object. Provided: ${actor}`)
|
||||
disrupt
|
||||
@@ -628,11 +647,11 @@ function send(actor, message, reply) {
|
||||
log.error('Message must be an object')
|
||||
disrupt
|
||||
}
|
||||
var send_msg = {type:"user", data: message}
|
||||
var target = actor
|
||||
send_msg = {type:"user", data: message}
|
||||
target = actor
|
||||
|
||||
if (actor[HEADER] && actor[HEADER].replycc) {
|
||||
var header = actor[HEADER]
|
||||
header = 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
|
||||
@@ -643,7 +662,7 @@ function send(actor, message, reply) {
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
var id = guid()
|
||||
id = guid()
|
||||
replies[id] = reply
|
||||
$_.delay(_ => {
|
||||
if (replies[id]) {
|
||||
@@ -728,18 +747,21 @@ function handle_actor_disconnect(id) {
|
||||
|
||||
function handle_sysym(msg)
|
||||
{
|
||||
var from
|
||||
var from = null
|
||||
var greeter = null
|
||||
var letter2 = null
|
||||
|
||||
if (msg.kind == 'stop') {
|
||||
actor_die("got stop message")
|
||||
} else if (msg.kind == 'underling') {
|
||||
from = msg.from
|
||||
var greeter = greeters[from[ACTORDATA].id]
|
||||
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 = msg.data
|
||||
letter2[HEADER] = msg
|
||||
delete msg.data
|
||||
portal_fn(letter2)
|
||||
@@ -756,13 +778,16 @@ function handle_sysym(msg)
|
||||
}
|
||||
|
||||
function handle_message(msg) {
|
||||
var letter = null
|
||||
var fn = null
|
||||
|
||||
if (msg[SYSYM]) {
|
||||
handle_sysym(msg[SYSYM], msg.from)
|
||||
return
|
||||
}
|
||||
|
||||
if (msg.type == "user") {
|
||||
var letter = msg.data // what the sender really sent
|
||||
letter = msg.data // what the sender really sent
|
||||
_ObjectDefineProperty(letter, HEADER, {
|
||||
value: msg, enumerable: false
|
||||
})
|
||||
@@ -771,7 +796,7 @@ function handle_message(msg) {
|
||||
})
|
||||
|
||||
if (msg.return) {
|
||||
var fn = replies[msg.return]
|
||||
fn = replies[msg.return]
|
||||
if (fn) fn(letter)
|
||||
delete replies[msg.return]
|
||||
return
|
||||
@@ -801,14 +826,16 @@ var package = use_core('package')
|
||||
|
||||
// Find the .ce file
|
||||
var prog_path = prog + ".ce"
|
||||
var pkg_dir = null
|
||||
var core_dir = null
|
||||
if (!fd.is_file(prog_path)) {
|
||||
var pkg_dir = package.find_package_dir(prog_path)
|
||||
pkg_dir = package.find_package_dir(prog_path)
|
||||
if (pkg_dir)
|
||||
prog_path = pkg_dir + '/' + prog + '.ce'
|
||||
}
|
||||
if (!fd.is_file(prog_path)) {
|
||||
// Check core packages
|
||||
var core_dir = core_path
|
||||
core_dir = core_path
|
||||
prog_path = core_dir + '/' + prog + '.ce'
|
||||
}
|
||||
if (!fd.is_file(prog_path)) {
|
||||
@@ -824,9 +851,11 @@ $_.clock(_ => {
|
||||
var env = {}
|
||||
arrfor(array(runtime_env), function(k) { env[k] = runtime_env[k] })
|
||||
var _ki = 0
|
||||
var inj = null
|
||||
var key = null
|
||||
while (_ki < length(inject)) {
|
||||
var inj = inject[_ki]
|
||||
var key = inj
|
||||
inj = inject[_ki]
|
||||
key = inj
|
||||
if (key && key[0] == '$') key = text(key, 1)
|
||||
if (key == 'fd') env['$fd'] = fd
|
||||
else env['$' + key] = $_[key]
|
||||
|
||||
Reference in New Issue
Block a user