initial misty implementation
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m50s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m50s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
This commit is contained in:
@@ -519,6 +519,62 @@ var fnname = "doc"
|
|||||||
script = `(function ${fnname}() { ${script}; })`
|
script = `(function ${fnname}() { ${script}; })`
|
||||||
js.eval(DOCPATH, script)()
|
js.eval(DOCPATH, script)()
|
||||||
|
|
||||||
|
var enet = use('enet')
|
||||||
|
|
||||||
|
var $_ = {}
|
||||||
|
|
||||||
|
var host = enet.create_host()
|
||||||
|
$_.host = host
|
||||||
|
|
||||||
|
console.log(`made a host with port ${host.port()}`)
|
||||||
|
|
||||||
|
globalThis.$_ = $_
|
||||||
|
|
||||||
|
var portal = undefined
|
||||||
|
|
||||||
|
var receive_fn = undefined;
|
||||||
|
|
||||||
|
$_.contact = function(callback, record)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.connection = function(callback, actor, config)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.portal = function(fn, port)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.receiver = function(fn)
|
||||||
|
{
|
||||||
|
receive_fn = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.start = function(cb, prg, arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.stop = function(actor)
|
||||||
|
{
|
||||||
|
if (!actor)
|
||||||
|
os.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.unneeded = function(fn, seconds)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.delay = function(fn, seconds)
|
||||||
|
{
|
||||||
|
var id = os.addtimer(fn, seconds);
|
||||||
|
return function() { os.removetimer(id); }
|
||||||
|
}
|
||||||
|
|
||||||
use('cmd')(prosperon.argv)
|
use('cmd')(prosperon.argv)
|
||||||
|
|
||||||
})()
|
})()
|
||||||
|
|||||||
@@ -165,6 +165,47 @@ Cmdline.print_order = function (fn) {
|
|||||||
console.print(fn.doc + "\n");
|
console.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmdline.register_order(
|
||||||
|
"spawn",
|
||||||
|
function(argv) {
|
||||||
|
var args = parse_args(argv)
|
||||||
|
console.log(json.encode(args));
|
||||||
|
if (!args.program)
|
||||||
|
os.exit()
|
||||||
|
|
||||||
|
console.log(`going to connect to ${args.overling}`)
|
||||||
|
if (args.overling) {
|
||||||
|
// connect to the port
|
||||||
|
$_.host.connect("localhost", args.overling);
|
||||||
|
console.log("CONNECTING TO " + args.overling);
|
||||||
|
while(1) {
|
||||||
|
os.waitevent(_ => {}, 0.016)
|
||||||
|
$_.host.service(e => { console.log(json.encode(e)) }, 0.016)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawn_root(args.program)
|
||||||
|
},
|
||||||
|
"Spawn a new prosperon actor.",
|
||||||
|
"TOPIC"
|
||||||
|
);
|
||||||
|
|
||||||
Cmdline.register_order(
|
Cmdline.register_order(
|
||||||
"help",
|
"help",
|
||||||
function (order) {
|
function (order) {
|
||||||
|
|||||||
107
source/jsffi.c
107
source/jsffi.c
@@ -28,6 +28,8 @@
|
|||||||
#include "cgltf.h"
|
#include "cgltf.h"
|
||||||
#include "physfs.h"
|
#include "physfs.h"
|
||||||
|
|
||||||
|
void gui_input(SDL_Event *e);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
@@ -55,6 +57,7 @@ typedef struct rtree rtree;
|
|||||||
#include <SDL3/SDL_loadso.h>
|
#include <SDL3/SDL_loadso.h>
|
||||||
#include <SDL3/SDL_cpuinfo.h>
|
#include <SDL3/SDL_cpuinfo.h>
|
||||||
|
|
||||||
|
static Uint32 timer_cb_event;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <Accelerate/Accelerate.h>
|
#include <Accelerate/Accelerate.h>
|
||||||
@@ -7132,6 +7135,86 @@ JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
|||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSC_CCALL(os_createprocess,
|
||||||
|
int ac = JS_ArrayLength(js,argv[0]);
|
||||||
|
const char *args[ac+1];
|
||||||
|
for (int i = 0; i < ac; i++) {
|
||||||
|
JSValue astr = JS_GetPropertyUint32(js,argv[0],i);
|
||||||
|
args[i] = JS_ToCString(js,astr);
|
||||||
|
JS_FreeValue(js,astr);
|
||||||
|
}
|
||||||
|
|
||||||
|
args[ac] = NULL;
|
||||||
|
|
||||||
|
SDL_Process *actor = SDL_CreateProcess(args, 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < ac; i++)
|
||||||
|
JS_FreeCString(js,args[i]);
|
||||||
|
|
||||||
|
if (!actor)
|
||||||
|
return JS_ThrowReferenceError(js, "Unable to create process: %s\n", SDL_GetError());
|
||||||
|
)
|
||||||
|
|
||||||
|
struct { SDL_TimerID key; JSValue *value; } *timer_hash = NULL;
|
||||||
|
|
||||||
|
Uint64 os_timer_cb(JSValue *fn, SDL_TimerID id, Uint64 delay)
|
||||||
|
{
|
||||||
|
SDL_UserEvent event;
|
||||||
|
SDL_zero(event);
|
||||||
|
event.type = timer_cb_event;
|
||||||
|
event.data1 = fn;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
hmdel(timer_hash, id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSC_CCALL(os_addtimer,
|
||||||
|
JSValue *fn = malloc(sizeof(*fn));
|
||||||
|
*fn = JS_DupValue(js,argv[0]);
|
||||||
|
double secs;
|
||||||
|
JS_ToFloat64(js, &secs, argv[1]);
|
||||||
|
|
||||||
|
SDL_TimerID id = SDL_AddTimerNS(secs*1000000000.0f, os_timer_cb, fn);
|
||||||
|
|
||||||
|
hmput(timer_hash, id, fn);
|
||||||
|
|
||||||
|
return JS_NewUint32(js,id);
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(os_removetimer,
|
||||||
|
SDL_TimerID id;
|
||||||
|
JS_ToUint32(js,&id, argv[0]);
|
||||||
|
int rm = SDL_RemoveTimer(id);
|
||||||
|
if (!rm) return JS_ThrowReferenceError(js,"Could not remove timer id %u: %s\n", id, SDL_GetError());
|
||||||
|
JSValue *fn = hmget(timer_hash, id);
|
||||||
|
if (fn != -1) {
|
||||||
|
JS_FreeValue(js, *fn);
|
||||||
|
free(fn);
|
||||||
|
hmdel(timer_hash, id);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(os_waitevent,
|
||||||
|
SDL_Event event;
|
||||||
|
double secs;
|
||||||
|
JS_ToFloat64(js, &secs, argv[1]);
|
||||||
|
while (SDL_WaitEventTimeout(&event, secs*1000.0f)) {
|
||||||
|
if (event.type == timer_cb_event) {
|
||||||
|
JSValue *fn = event.user.data1;
|
||||||
|
JSValue ret = JS_Call(js, *fn, JS_UNDEFINED, 0, NULL);
|
||||||
|
JS_FreeValue(js,*fn);
|
||||||
|
free(fn);
|
||||||
|
uncaught_exception(js,ret);
|
||||||
|
} else {
|
||||||
|
gui_input(&event);
|
||||||
|
JSValue e = event2js(js,event);
|
||||||
|
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
||||||
|
uncaught_exception(js,ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JS_UNDEFINED;
|
||||||
|
)
|
||||||
|
|
||||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||||
MIST_FUNC_DEF(os, make_transform, 0),
|
MIST_FUNC_DEF(os, make_transform, 0),
|
||||||
MIST_FUNC_DEF(os, clean_transforms, 0),
|
MIST_FUNC_DEF(os, clean_transforms, 0),
|
||||||
@@ -7167,7 +7250,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||||||
|
|
||||||
// dangerous ones that need disabled for shipping
|
// dangerous ones that need disabled for shipping
|
||||||
MIST_FUNC_DEF(os, env, 1),
|
MIST_FUNC_DEF(os, env, 1),
|
||||||
MIST_FUNC_DEF(os, system, 1),
|
MIST_FUNC_DEF(os, system, 1),
|
||||||
|
MIST_FUNC_DEF(os, createprocess, 0),
|
||||||
|
MIST_FUNC_DEF(os, addtimer, 2),
|
||||||
|
MIST_FUNC_DEF(os, removetimer, 1),
|
||||||
|
MIST_FUNC_DEF(os, waitevent, 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
JSC_CCALL(js_dump_class, return js_get_object_class_distribution(js))
|
JSC_CCALL(js_dump_class, return js_get_object_class_distribution(js))
|
||||||
@@ -7239,14 +7326,19 @@ static const JSCFunctionListEntry js_video_funcs[] = {
|
|||||||
MIST_FUNC_DEF(os, make_video, 1),
|
MIST_FUNC_DEF(os, make_video, 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
void gui_input(SDL_Event *e);
|
|
||||||
// Polls and handles all input events
|
// Polls and handles all input events
|
||||||
JSValue js_os_engine_input(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
JSValue js_os_engine_input(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
#ifndef NEDITOR
|
if (event.type == timer_cb_event) {
|
||||||
|
JSValue *fn = event.user.data1;
|
||||||
|
JSValue ret = JS_Call(js, *fn, JS_UNDEFINED, 0, NULL);
|
||||||
|
JS_FreeValue(js,*fn);
|
||||||
|
uncaught_exception(js,ret);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
gui_input(&event);
|
gui_input(&event);
|
||||||
#endif
|
|
||||||
JSValue e = event2js(js,event);
|
JSValue e = event2js(js,event);
|
||||||
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
||||||
uncaught_exception(js,ret);
|
uncaught_exception(js,ret);
|
||||||
@@ -7555,6 +7647,7 @@ static void signal_handler(int sig) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!str) return;
|
if (!str) return;
|
||||||
|
|
||||||
script_evalf("prosperon.dispatch('%s')", str);
|
script_evalf("prosperon.dispatch('%s')", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7655,6 +7748,8 @@ void ffi_load(JSContext *js, int argc, char **argv) {
|
|||||||
QJSCLASSPREP_FUNCS(datastream);
|
QJSCLASSPREP_FUNCS(datastream);
|
||||||
QJSCLASSPREP_FUNCS(timer);
|
QJSCLASSPREP_FUNCS(timer);
|
||||||
|
|
||||||
|
timer_cb_event = SDL_RegisterEvents(1);
|
||||||
|
|
||||||
JS_SetPropertyStr(js, globalThis, "use_dyn", JS_NewCFunction(js,js_os_use_dyn,"use_dyn", 1));
|
JS_SetPropertyStr(js, globalThis, "use_dyn", JS_NewCFunction(js,js_os_use_dyn,"use_dyn", 1));
|
||||||
JS_SetPropertyStr(js, globalThis, "use_embed", JS_NewCFunction(js,js_os_use_embed,"use_embed", 1));
|
JS_SetPropertyStr(js, globalThis, "use_embed", JS_NewCFunction(js,js_os_use_embed,"use_embed", 1));
|
||||||
|
|
||||||
@@ -7793,5 +7888,7 @@ void ffi_load(JSContext *js, int argc, char **argv) {
|
|||||||
idx_buffer = JS_UNDEFINED;
|
idx_buffer = JS_UNDEFINED;
|
||||||
cycle_fn = JS_UNDEFINED;
|
cycle_fn = JS_UNDEFINED;
|
||||||
|
|
||||||
JS_FreeValue(js,globalThis);
|
JS_FreeValue(js,globalThis);
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_EVENTS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,25 +40,34 @@ static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val,
|
|||||||
|
|
||||||
/* Host creation */
|
/* Host creation */
|
||||||
static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val,
|
static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val,
|
||||||
int argc, JSValueConst *argv) {
|
int argc, JSValueConst *argv) {
|
||||||
ENetHost *host;
|
ENetHost *host;
|
||||||
ENetAddress address;
|
ENetAddress address;
|
||||||
JSValue obj;
|
JSValue obj;
|
||||||
|
|
||||||
|
// Default configuration matching the JavaScript object
|
||||||
|
size_t peer_count = 32; // peer_count: 32
|
||||||
|
size_t channel_limit = 0; // channel_limit: 0
|
||||||
|
enet_uint32 incoming_bandwidth = 0; // incoming_bandwidth: 0
|
||||||
|
enet_uint32 outgoing_bandwidth = 0; // outgoing_bandwidth: 0
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
// Create client-like host, unbound
|
// Create client-like host with port 0 and "any" address
|
||||||
host = enet_host_create(NULL, 32, 2, 0, 0);
|
address.host = ENET_HOST_ANY;
|
||||||
|
address.port = 0;
|
||||||
|
host = enet_host_create(&address, peer_count, channel_limit,
|
||||||
|
incoming_bandwidth, outgoing_bandwidth);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return JS_ThrowInternalError(ctx, "Failed to create ENet host (null address).");
|
return JS_ThrowInternalError(ctx, "Failed to create ENet host (any address).");
|
||||||
}
|
}
|
||||||
goto RET;
|
goto RET;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If arg is provided, interpret as "ip:port" for server
|
// If argument is provided, interpret as "ip:port" for server
|
||||||
const char *address_str = JS_ToCString(ctx, argv[0]);
|
const char *address_str = JS_ToCString(ctx, argv[0]);
|
||||||
if (!address_str) {
|
if (!address_str)
|
||||||
return JS_EXCEPTION; // memory or conversion error
|
return JS_EXCEPTION; // memory or conversion error
|
||||||
}
|
|
||||||
char ip[64];
|
char ip[64];
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
@@ -68,14 +77,20 @@ static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val,
|
|||||||
}
|
}
|
||||||
JS_FreeCString(ctx, address_str);
|
JS_FreeCString(ctx, address_str);
|
||||||
|
|
||||||
int err = enet_address_set_host_ip(&address, ip);
|
if (strcmp(ip, "any") == 0)
|
||||||
if (err != 0) {
|
address.host = ENET_HOST_ANY;
|
||||||
return JS_ThrowInternalError(ctx, "Failed to set host IP from %s. Error %d.", ip, err);
|
else if (strcmp(ip, "broadcast"))
|
||||||
|
address.host = ENET_HOST_BROADCAST;
|
||||||
|
else {
|
||||||
|
int err = enet_address_set_host_ip(&address, ip);
|
||||||
|
if (err != 0) {
|
||||||
|
return JS_ThrowInternalError(ctx, "Failed to set host IP from %s. Error %d.", ip, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
address.port = port;
|
address.port = port;
|
||||||
|
|
||||||
// Create server host with max 32 clients, 2 channels
|
// Create host with specified configuration
|
||||||
host = enet_host_create(&address, 32, 2, 0, 0);
|
host = enet_host_create(&address, peer_count, channel_limit, incoming_bandwidth, outgoing_bandwidth);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return JS_ThrowInternalError(ctx, "Failed to create ENet host.");
|
return JS_ThrowInternalError(ctx, "Failed to create ENet host.");
|
||||||
}
|
}
|
||||||
@@ -93,6 +108,7 @@ RET:
|
|||||||
/* Host service: poll for events */
|
/* Host service: poll for events */
|
||||||
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
||||||
int argc, JSValueConst *argv) {
|
int argc, JSValueConst *argv) {
|
||||||
|
|
||||||
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
@@ -105,14 +121,11 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
|
|||||||
JSValue callback = argv[0];
|
JSValue callback = argv[0];
|
||||||
JS_DupValue(ctx, callback);
|
JS_DupValue(ctx, callback);
|
||||||
|
|
||||||
// Optional timeout
|
double secs;
|
||||||
int timeout = 0;
|
JS_ToFloat64(ctx, &secs, argv[1]);
|
||||||
if (argc > 1) {
|
|
||||||
JS_ToInt32(ctx, &timeout, argv[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
while (enet_host_service(host, &event, timeout) > 0) {
|
while (enet_host_service(host, &event, secs*1000.0f) > 0) {
|
||||||
JSValue event_obj = JS_NewObject(ctx);
|
JSValue event_obj = JS_NewObject(ctx);
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
@@ -273,6 +286,20 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val,
|
|||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
ENetHost *host = JS_GetOpaque(self, enet_host_id);
|
||||||
|
if (!host) return JS_EXCEPTION;
|
||||||
|
return JS_NewInt32(js, host->address.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue js_enet_host_get_address(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
ENetHost *host = JS_GetOpaque(self, enet_host_id);
|
||||||
|
if (!host) return JS_EXCEPTION;
|
||||||
|
return JS_NewInt32(js, host->address.host);
|
||||||
|
}
|
||||||
|
|
||||||
/* Peer-level operations */
|
/* Peer-level operations */
|
||||||
static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val,
|
static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val,
|
||||||
int argc, JSValueConst *argv) {
|
int argc, JSValueConst *argv) {
|
||||||
@@ -429,6 +456,8 @@ static const JSCFunctionListEntry js_enet_host_funcs[] = {
|
|||||||
JS_CFUNC_DEF("connect", 2, js_enet_host_connect),
|
JS_CFUNC_DEF("connect", 2, js_enet_host_connect),
|
||||||
JS_CFUNC_DEF("flush", 0, js_enet_host_flush),
|
JS_CFUNC_DEF("flush", 0, js_enet_host_flush),
|
||||||
JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast),
|
JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast),
|
||||||
|
JS_CFUNC_DEF("port", 0, js_enet_host_get_port),
|
||||||
|
JS_CFUNC_DEF("address", 0, js_enet_host_get_address),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JSCFunctionListEntry js_enet_peer_funcs[] = {
|
static const JSCFunctionListEntry js_enet_peer_funcs[] = {
|
||||||
|
|||||||
9
tests/overling.js
Normal file
9
tests/overling.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
var os = use('os')
|
||||||
|
|
||||||
|
var newguy = os.createprocess(["./prosperon", "spawn", "--program", "spawn2.js", "--overling", $_.host.port()])
|
||||||
|
var hang = 0.016
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
os.waitevent(_ => {}, hang)
|
||||||
|
$_.host.service(e => {console.log(json.encode(e))}, hang)
|
||||||
|
}
|
||||||
5
tests/underling.js
Normal file
5
tests/underling.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
var os = use('os')
|
||||||
|
|
||||||
|
console.log("Created underling")
|
||||||
|
|
||||||
|
os.exit()
|
||||||
Reference in New Issue
Block a user