remove actors being created via cmd line args

This commit is contained in:
2025-05-30 18:05:02 -05:00
parent 66591e32b5
commit b71c72db8b
11 changed files with 85 additions and 351 deletions

View File

@@ -1,261 +0,0 @@
var io = use('io')
var util = use('util')
var dumpfolder = ".prosperon";
io.mkdir(dumpfolder)
var Cmdline = {};
Cmdline.cmds = [];
Cmdline.orders = {};
Cmdline.register_cmd = function (flag, fn, doc) {
Cmdline.cmds.push({
flag: flag,
fn: fn,
doc: doc,
});
};
Cmdline.register_order = function (order, fn, doc, usage = "") {
Cmdline.orders[order] = fn;
fn.doc = doc;
fn.usage = `${order} ${usage}`;
};
Cmdline.register_order(
"makedoc",
function() {
var doc = use('doc')
var gs = ['console', 'prosperon', 'actor', 'use']
for (var g of gs)
io.slurpwrite(`.src/docs/api/${g}.md`, doc.writeDocFile(globalThis[g], g))
var coredocs = io.enumerate("scripts/modules", 0)
coredocs = coredocs.filter(x => io.match("**/*.js", x)).map(x => x.name())
var APIPATH = '.src/docs/api/modules/'
for (var m of coredocs) {
var u = use(m)
var path = `${APIPATH}${m}.md`
io.slurpwrite(path, doc.writeDocFile(u, m))
}
var TYPEPATH = '.src/docs/api/types/'
for (var c in prosperon.c_types)
io.slurpwrite(`${TYPEPATH}${c}.md`, doc.writeDocFile(prosperon.c_types[c], c))
var DULLPATH = '.src/docs/dull/'
var mixins = ['Object', 'String', 'Array', 'Map', 'WeakMap', 'Symbol','Set', 'WeakSet', 'ArrayBuffer', 'Function']
for (var m of mixins) {
var path = `${DULLPATH}${m}.md`
io.slurpwrite(path, doc.writeDocFile(globalThis[m].prototype, m))
}
var dullgpath = '.src/docs/dull/globals/'
var globals = ['Object', 'String', 'Array', 'Symbol', 'Number', 'Error','Function', 'Math']
for (var m of globals) {
var path = `${dullgpath}${m}.md`
io.slurpwrite(path, doc.writeDocFile(globalThis[m], m))
}
"Make documentation."
})
Cmdline.register_order(
"play",
function (argv) {
var app
if (io.exists("main.js"))
app = actor.spawn("main.js")
else
app = actor.spawn("nogame.js")
var loop = use('loop')
while(1) loop.step();
},
"Play the game present in this folder.",
);
Cmdline.register_order(
"about",
function (argv) {
if (!argv[0]) {
log.print("About your game");
log.print(`Prosperon version ${prosperon.version}`);
log.print(`Total entities ${ur._list.length}`);
}
switch (argv[0]) {
case "entities":
for (var i of ur._list) log.print(i);
break;
}
},
"Get information about this game.",
);
Cmdline.register_order(
"api",
function (obj) {
var doc = use('doc')
doc.write_modules()
doc.write_c_types()
},
"Print the API for an object as markdown. Give it a file to save the output to.",
"OBJECT",
);
Cmdline.register_order(
"input",
function (pawn) {
use("editor.js");
log.print(`## Input for ${pawn}`);
eval(`log.print(input.print_md_kbm(${pawn}));`);
},
"Print input documentation for a given object as markdown. Give it a file to save the output to",
"OBJECT ?FILE?",
);
Cmdline.print_order = function (fn) {
if (typeof fn === "string") fn = Cmdline.orders[fn];
if (!fn) return;
log.print(`Usage: prosperon ${fn.usage}` + "\n");
log.print(fn.doc + "\n");
};
function parse_args(argv)
{
var args = {};
for (var i = 0; i < argv.length; i++) {
if (argv[i].startsWith("--")) {
var key = argv[i].slice(2);
if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
args[key] = argv[i + 1];
i++; // Skip the value
} else {
args[key] = true; // Flag without value
}
}
}
return args;
}
function unparse_args(args) {
var argv = [];
for (var key in args) {
if (args.hasOwnProperty(key)) {
argv.push("--" + key); // Add the flag with "--" prefix
if (args[key] !== true) {
argv.push(args[key]); // Add the value if it's not a boolean true flag
}
}
}
return argv;
}
Cmdline.register_order(
"spawn",
function(argv) {
prosperon.args = parse_args(argv)
if (!prosperon.args.cwd) prosperon.args.cwd = '.'
io.mount(prosperon.args.cwd)
// Store all remaining non-flag arguments
var remaining_args = []
var skip_next = false
for (var i = 0; i < argv.length; i++) {
if (skip_next) {
skip_next = false
continue
}
if (argv[i].startsWith("--")) {
// Check if this flag has a value
if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
skip_next = true
}
continue
}
remaining_args.push(argv[i])
}
// Add remaining arguments to prosperon.args
prosperon.args.remaining = remaining_args
if (!prosperon.args.program)
os.exit()
},
"Spawn a new prosperon actor.",
"TOPIC"
);
Cmdline.register_order(
"help",
function (order) {
if (!util.isEmpty(order)) {
var orfn = Cmdline.orders[order];
if (!orfn) {
log.warn(`No command named ${order}.`);
return;
}
Cmdline.print_order(orfn);
return;
}
Cmdline.print_order("help");
for (var cmd of Object.keys(Cmdline.orders).sort()) log.print(cmd + "\n");
Cmdline.orders.version();
},
"Give help with a specific command.",
"TOPIC",
);
Cmdline.register_order(
"version",
function () {
log.print(`Prosperon version ${prosperon.version} [${prosperon.revision}]` + "\n");
},
"Display Prosperon info.",
);
function cmd_args(cmds) {
// Remove the leading 'prosperon'
cmds.shift();
// If there are no arguments left, assume we want to spawn main.js
if (!cmds[0]) {
// => effectively do: prosperon spawn --program main.js
cmds.unshift("main.js");
cmds.unshift("--program");
cmds.unshift("spawn");
} else if (!Cmdline.orders[cmds[0]]) {
// If the first token isn't a recognized command, treat it as either
// a directory containing main.js, or a script to run directly.
var arg0 = cmds.shift();
if (io.is_directory(arg0)) {
var script = cmds[0] ? cmds.shift() : "main.js";
cmds.unshift(script);
cmds.unshift("--program");
cmds.unshift(arg0);
cmds.unshift("--cwd");
} else {
cmds.unshift(arg0);
cmds.unshift("--program");
}
cmds.unshift("spawn");
}
Cmdline.orders[cmds[0]](cmds.slice(1));
}
return {
process: cmd_args,
encode: parse_args,
decode: unparse_args,
}

View File

@@ -1,6 +1,6 @@
(function engine() {
globalThis.cell = prosperon
cell.DOC = cell.hidden.DOCSYM
globalThis.cell = prosperon
cell.DOC = cell.hidden.DOCSYM
var MOD_EXT = '.cm'
var ACTOR_EXT = '.ce'
@@ -24,7 +24,10 @@ function caller_data(depth = 0)
return {file,line}
}
cell.args = cell.hidden.init
cell.args ??= {}
cell.id ??= "newguy"
function console_rec(line, file, msg) {
return `[${cell.id.slice(0,5)}] [${file}:${line}]: ${msg}\n`
@@ -90,6 +93,17 @@ var nota = hidden.nota
delete cell.hidden
var os = use_embed('os')
os.on = function(e)
{
log.console(JSON.stringify(e))
log.error(e)
disrupt()
}
var js = use_embed('js')
var io = use_embed('io')
@@ -123,6 +137,8 @@ var fnname = "base"
script = `(function ${fnname}() { ${script}; })`
js.eval(BASEPATH, script)()
var inProgress = {}
var loadingStack = []
@@ -438,18 +454,22 @@ $_.receiver = function receiver(fn) {
}
$_.receiver[cell.DOC] = "registers a function that will receive all messages..."
$_.start = function start(cb, prg, arg) {
$_.start = function start(cb, program, arg) {
if (dying) {
log.warn(`Cannot start an underling in the same turn as we're stopping`)
return
}
var id = util.guid()
var startup = {
id,
overling: $_,
root,
arg,
program
}
greeters[id] = cb
var argv = ["./cell", "spawn", "--id", id, "--overling", json.encode($_), "--root", json.encode(root)]
if (prg) argv = argv.concat(['--program', prg])
if (arg) argv = argv.concat(cmd.encode(arg))
underlings.add(id)
actor_mod.createactor(argv)
actor_mod.createactor(startup)
}
$_.start[cell.DOC] = "The start function creates a new actor..."
@@ -489,6 +509,13 @@ $_.couple = function couple(actor) {
}
$_.couple[cell.DOC] = "causes this actor to stop when another actor stops."
function disrupt()
{
dying = true
if (overling) actor_prep(overling, {type:'disrupt', actor: $_})
actor_mod.destroy()
}
function actor_prep(actor, send) {
message_queue.push({actor,send});
}
@@ -593,9 +620,6 @@ Object.defineProperty(globalThis, 'send', {
enumerable: true
});
var cmd = use('cmd')
cmd.process(cell.argv.slice())
if (!cell.args.id) cell.id = util.guid()
else cell.id = cell.args.id
@@ -617,10 +641,9 @@ function turn(msg)
actor_mod.register_actor(cell.id, turn, cell.args.main)
if (cell.args.overling) overling = json.decode(cell.args.overling)
if (cell.args.root) root = json.decode(cell.args.root)
else root = $_
overling = cell.args.overling
root = cell.args.root
root ??= $_
if (overling) actor_prep(overling, {type:'greet', actor: $_})
@@ -628,10 +651,11 @@ if (!cell.args.program)
os.exit(1)
function destroyself() {
log.spam(`Got the message to destroy self.`)
dying = true
for (var i of underlings)
$_.stop(create_actor({id:i}))
if (overling) actor_prep(overling, {type:'stop', actor: $_})
actor_mod.destroy()
}
@@ -729,8 +753,8 @@ if (progDir && progDir !== '.') {
}
var progContent = io.slurp(prog)
var prog_script = `(function ${cell.args.program.name()}_start($_) { ${progContent} })`
var val = js.eval(cell.args.program, prog_script)($_)
var prog_script = `(function ${cell.args.program.name()}_start($_, arg) { ${progContent} })`
var val = js.eval(cell.args.program, prog_script)($_, )
if (val)
throw new Error('Program must not return anything');

View File

@@ -224,11 +224,10 @@ int prosperon_mount_core(void)
return ret;
}
cell_rt *create_actor(int argc, char **argv, void (*hook)(JSContext*))
cell_rt *create_actor(void *wota, void (*hook)(JSContext*))
{
cell_rt *actor = calloc(sizeof(*actor), 1);
actor->cmd.argc = argc;
actor->cmd.argv = argv;
actor->init_wota = wota;
actor->cycle_fn = JS_UNDEFINED;
actor->idx_buffer = JS_UNDEFINED;
actor->message_handle = JS_UNDEFINED;
@@ -714,9 +713,8 @@ void script_startup(cell_rt *prt, void (*hook)(JSContext*))
data[stat.filesize] = 0;
/* Call hook function if provided before evaluating engine */
if (hook) {
if (hook)
hook(js);
}
/* Called with actor->mutex locked by create_actor(). */
JSValue v = JS_Eval(js, data, (size_t)stat.filesize, ENGINE, JS_EVAL_FLAG_STRICT);
@@ -1559,10 +1557,14 @@ int main(int argc, char **argv)
/* Create the initial actor from the main command line. */
/* Adjust argc and argv to skip --profile if present */
int actor_argc = argc - (script_start - 1);
char **actor_argv = argv + (script_start - 1);
actor_argv[0] = argv[0]; // Keep the program name
create_actor(actor_argc, actor_argv, NULL);
WotaBuffer startwota;
wota_buffer_init(&startwota, 5);
wota_write_record(&startwota, 1);
wota_write_text(&startwota, "program");
wota_write_text(&startwota, actor_argv[1]); // program name
create_actor(startwota.data,NULL); // this can fall off because the actor takes care of freeing the wota data
/* Start the thread that pumps ready actors, one per logical core. */
for (int i = 0; i < cores; i++) {

View File

@@ -29,19 +29,15 @@ typedef struct {
MODULEFN fn;
} ModuleEntry;
typedef struct {
int argc;
char **argv;
} cmdargs;
typedef struct cell_rt {
cmdargs cmd;
JSContext *context;
JSValue cycle_fn;
JSValue idx_buffer;
JSValue on_exception;
JSValue message_handle;
JSValue unneeded;
void *init_wota;
ModuleEntry *module_registry;
JSValue *js_swapchains;
@@ -78,7 +74,7 @@ typedef struct cell_rt {
extern SDL_ThreadID main_thread;
extern SDL_TLSID prosperon_id;
cell_rt *create_actor(int argc, char **argv, void (*hook)(JSContext*));
cell_rt *create_actor(void *wota, void (*hook)(JSContext*));
const char *register_actor(const char *id, cell_rt *actor, int mainthread);
void actor_free(cell_rt *actor);
const char *send_message(const char *id, void *msg);

View File

@@ -1525,6 +1525,7 @@ JSC_CCALL(os_value_id,
#include "qjs_crypto.h"
#include "qjs_time.h"
#include "qjs_http.h"
#include "qjs_wota.h"
//JSValue js_imgui_use(JSContext *js);
#define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use}
@@ -1606,11 +1607,6 @@ void ffi_load(JSContext *js)
JS_FreeValue(js,jsnumber);
JS_FreeValue(js,number_proto);
JSValue args = JS_NewArray(js);
for (int i = 0; i < rt->cmd.argc; i++)
JS_SetPropertyUint32(js,args, i, JS_NewString(js,rt->cmd.argv[i]));
JS_SetPropertyStr(js,prosp,"argv", args);
//JS_SetPropertyStr(js,prosp, "version", JS_NewString(js,CELL_VERSION));
//JS_SetPropertyStr(js,prosp,"revision",JS_NewString(js,CELL_COMMIT));
@@ -1630,6 +1626,12 @@ void ffi_load(JSContext *js)
JS_SetPropertyStr(js, prosp, "hidden", hidden_fn);
if (rt->init_wota) {
JS_SetPropertyStr(js, hidden_fn, "init", wota2value(js, rt->init_wota));
// init wota can now be freed
free(rt->init_wota);
}
JS_FreeValue(js,globalThis);
cell_rt *actor = JS_GetContextOpaque(js);

View File

@@ -77,19 +77,8 @@ JSValue actor2js(JSContext *js, cell_rt *actor)
}
JSC_CCALL(os_createactor,
int margc = JS_ArrayLength(js, argv[0]);
char **margv = malloc(margc*sizeof(char*));
for (int i = 0; i < margc; i++) {
JSValue val = JS_GetPropertyUint32(js, argv[0], i);
const char *cstr = JS_ToCString(js,val);
margv[i] = strdup(cstr);
JS_FreeCString(js,cstr);
JS_FreeValue(js,val);
}
create_actor(margc, margv, NULL);
void *startup = value2wota(js, argv[0], JS_UNDEFINED);
create_actor(startup, NULL);
)
JSC_CCALL(os_mailbox_push,

View File

@@ -14,10 +14,6 @@
#include <string.h>
#include "qjs_sdl.h"
// External function declarations
extern cell_rt *create_actor(int argc, char **argv, void (*hook)(JSContext *));
extern const char *register_actor(const char *id, cell_rt *rt, int main_thread);
// SDL Window free function
void SDL_Window_free(JSRuntime *rt, SDL_Window *w)
{
@@ -1799,6 +1795,8 @@ static void video_actor_hook(JSContext *js) {
JS_FreeValue(js, prosperon);
}
#include "qjs_wota.h"
JSValue js_sdl_video_use(JSContext *js) {
if (!SDL_Init(SDL_INIT_VIDEO))
return JS_ThrowInternalError(js, "Unable to initialize video subsystem: %s", SDL_GetError());
@@ -1807,18 +1805,15 @@ JSValue js_sdl_video_use(JSContext *js) {
char id[64];
snprintf(id, sizeof(id), "video_%llu", (unsigned long long)SDL_GetTicks());
// Prepare argv for create_actor
// We need to create the actor on the main thread
const char *argv[] = {
"./prosperon",
"spawn",
"--id", id,
"--program", "_sdl_video.js",
"--main", "1"
};
int argc = 8;
JSValue startup = JS_NewObject(js);
JS_SetPropertyStr(js,startup, "id", JS_NewStringLen(js,id,64));
JS_SetPropertyStr(js,startup, "program", JS_NewString(js,"_sdl_video.js"));
JS_SetPropertyStr(js,startup,"main",JS_NewBool(js,1));
// Create the actor with the hook to set up endowments
cell_rt *actor = create_actor(argc, (char**)argv, video_actor_hook);
void *wota = value2wota(js,startup, JS_UNDEFINED);
JS_FreeValue(js,startup);
cell_rt *actor = create_actor(wota, video_actor_hook);
return actor2js(js,actor);
}

View File

@@ -1,13 +1,8 @@
$_.start(e => {
switch(e.type) {
case "actor_started":
log.console(json.encode(e))
$_.connection(e => log.console(json.encode(e)), e.actor) // get connection info
}, "underling", ['stop'])
send(e.actor, {message: "Hello!"})
$_.couple(e.actor)
$_.start(e => {
}, "underling", ['disrupt'])
$_.stop(e.actor)
}
}, "tests/underling");
$_.start(e => {
}, "underling", ['kill'])

View File

@@ -1,4 +1,3 @@
// bunnymark
var render = use('render')
var os = use('os')
var actor = use('actor')

View File

@@ -1,12 +1,2 @@
function spawnem()
{
for (var i = 0; i < 10; i++)
$_.start(_ => {}, "tests/spawnee")
}
with ([1,2,3]) {
log.console(toString())
}
$_.delay(spawnem, 3)
for (var i = 0; i < 10; i++)
$_.start(_ => {}, "spawnee")

View File

@@ -1,4 +1,7 @@
var os = use('os')
switch(arg[0]) {
case
}
$_.receiver(e => {
log.console(`got message: ${json.encode(e)}`)