add return to callback send

This commit is contained in:
2025-03-09 10:18:43 -05:00
parent 69df7302d5
commit d56c983e01
10 changed files with 356 additions and 302 deletions

View File

@@ -233,10 +233,10 @@ tests = [
'spawn_actor',
'empty',
'nota',
'enet',
'wota',
'portalspawner',
'overling'
'overling',
'send'
]
foreach file : tests

View File

@@ -1,6 +1,8 @@
(function engine() {
prosperon.DOC = Symbol('+documentation+') // Symbol for documentation references
prosperon.id = 'newguy';
var listeners = new Map()
prosperon.on = function(type, callback) {
@@ -127,7 +129,7 @@ function bare_load(file) {
var res_cache = {}
function console_rec(category, priority, line, file, msg) {
return `${file}:${line}: [${category} ${priority}]: ${msg}\n`
return `[${prosperon.id.substring(0,6)}] ${file}:${line}: [${category} ${priority}]: ${msg}\n`
}
io.mkdir('.prosperon')
@@ -522,11 +524,33 @@ js.eval(DOCPATH, script)()
var enet = use('enet')
var util = use('util')
var math = use('math')
var crypto = use('crypto')
var REPLY = Symbol()
var REPLYCC = Symbol()
var ACTORID = Symbol()
var PEER = Symbol()
var ar = 5 // seconds before reclamation
/*
When an actor object like $_ is passed to another machine or function, it appears like this
id: local to the machine. Currently, the local port it is listening on
address: the IP address of the portal that connects it, if set
port: the public port of the portal that connects it, if set
There is a map of actor.id -> peer, so messages can be sent.
*/
/*
Each actor has an id. When an actor object is received, that is essentially just an id. The method to reach the id is in routing tables local to the actor that has obtained the object. If actor.id === prosperon.id, it's localhost.
Currently, each actor has an enet peer, so we're focused on that. Eventually, there might also be a thread local mailbox.
*/
var $_ = {}
$_.random = math.rand
$_.random = crypto.random;
$_.clock = function(fn)
{
return os.now()
@@ -536,7 +560,7 @@ var underlings = new Set()
var overling = undefined
var host = enet.create_host({
address:"127.0.0.1", // or any address like "x.x.x.x", or "broadcast" for 255.255.255.255 and "any" for o0
address:"127.0.0.1",
port:0,
channels:0,
incoming_bandwidth:0,
@@ -545,12 +569,16 @@ var host = enet.create_host({
globalThis.$_ = $_
var portal = undefined
var receive_fn
var peers = {} // mapping of guids to peers
var greeters = {} // mapping of underling guids to their system callback functions
var peer2id = new WeakMap() // local bound peers to relevant id
$_.connection = function(callback, actor, config) {
var peer = actor.peer;
var peer = peers[actor.id]
if (!peer) throw new Error(`Cannot get information from actor ${json.encode(actor)}`)
callback({
latency: peer.rtt,
bandwidth: {
@@ -574,28 +602,51 @@ $_.connection = function(callback, actor, config) {
};
var portal = undefined
var pppfn
$_.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.");
$_.start(e => {
switch(e.type) {
case "actor_started":
portal = e.actor
break
}
portal = e
}, undefined, {
port
});
portal = enet.create_host({
address: "any", // any can connect
port,
})
pppfn = fn
}
function portal_fn(e)
{
switch (e.type) {
case "connect":
console.log('portal got connect')
break
case "disconnect":
console.log('portal got disconnect')
break
case "receive":
pppfn(e.data)
break
}
}
var peer2contact = new WeakMap()
$_.contact = function(callback, record)
{
if (!callback) throw new Error('Contact requires a callback function')
console.log(`connecting to ${json.encode(record)}`)
host.connect(record.address, record.port)
var peer = host.connect(record.address, record.port)
peer2contact.set(peer, {
callback,
record
})
}
$_.receiver = function(fn)
@@ -603,17 +654,15 @@ $_.receiver = function(fn)
receive_fn = fn;
}
var greeters = {}
$_.start = function(cb, prg, arg)
{
var guid = util.guid()
greeters[guid] = cb
var id = util.guid()
greeters[id] = cb
var argv = [
"./prosperon",
"spawn",
"--overling", host.port,
"--guid", guid,
"--id", id,
]
if (prg)
@@ -623,7 +672,6 @@ $_.start = function(cb, prg, arg)
argv = argv.concat(cmd.encode(arg))
os.createprocess(argv)
guid2actor.set(guid, {peer:undefined, guid:guid})
}
$_.stop = function(actor)
@@ -631,7 +679,7 @@ $_.stop = function(actor)
if (!actor)
destroyself()
send_system(actor, {type:"stop"})
actor_send(actor, {type:"stop"})
}
var unneeded_fn = $_.stop
@@ -650,96 +698,168 @@ $_.delay = function(fn, seconds)
return function() { os.removetimer(id); }
}
var guid2actor = new Map()
// Set of actor guids
var couplings = new Set()
$_.couple = function(actor)
{
couplings.add(actor)
couplings.add(actor.id)
}
function send_system(actor, message)
// Shuffles the message to the actor with whatever means available
function actor_send(actor, message)
{
actor.peer.send({
type:"system",
data:message
})
if (typeof message !== 'object')
throw new Error('Must send an object record.')
console.log(`Getting peer for ${actor.id}`)
var peer = peers[actor.id]
if (!peer) throw new Error(`Could not send message to actor.`)
console.log(`sending message ${json.encode(message)} to ${json.encode(actor)}`)
peer.send(message)
}
$_.send = function(actor, message, receive)
// Map of reply IDs to functions
var replies = {}
// Map of a message object to a peer for replying directly
var reply_cc = new WeakMap()
$_.send = function(actor, message, reply)
{
if (typeof message !== 'object')
throw new Error('Must send an object record.')
actor.peer.send({ // right now only peers so this works
console.log(`sending to ${json.encode(actor)} ...`)
var send = {
type:"user",
data: message
})
}
if (actor[REPLYCC]) {
console.log(`replying to a message: ${json.encode(actor)}`)
console.log(`replycc and reply are ${actor[REPLYCC]} and ${actor[REPLY]}`)
actor.id = actor[REPLYCC]
send.return = actor[REPLY]
} else if (peers[actor.id]) {
} else
throw new Error(`Could not send message to actor.`)
if (reply) {
var id = util.guid()
replies[id] = reply
send.reply = id
}
actor_send(actor, send)
}
var cmd = use('cmd')
cmd.process(prosperon.argv)
if (!prosperon.args.id)
prosperon.id = util.guid()
else
prosperon.id = prosperon.args.id;
if (prosperon.args.overling)
host.connect("localhost", prosperon.args.overling)
if (prosperon.args.program)
actor.spawn(prosperon.args.program)
if (!prosperon.args.guid)
prosperon.guid = util.guid()
else
prosperon.guid = prosperon.args.guid;
var ar = 5 // seconds before reclamation
var unneeded_timer = $_.delay($_.stop, ar)
function destroyself()
{
host.broadcast({type:"system", data:{
type:"disconnect"
}})
host.flush()
console.log('got the message to destroy')
os.exit(0)
}
function handle_actor_disconnect(actor)
function handle_actor_disconnect(id)
{
if (couplings.has(actor))
if (couplings.has(id))
$_.stop()
guid2actor.delete(actor.guid)
guid2actor.delete(actor.peer)
delete peers[id]
delete greeters[id]
}
function handle_system(e)
function handle_message(e)
{
var msg = e.data.data
switch(msg.type) {
case "disconnect":
handle_actor_disconnect(guid2actor.get(e.peer))
console.log(`handling message ${json.encode(e)}`)
switch (e.data.type) {
case "user":
if (e.data.return) {
console.log(`Message has a return address.`)
var fn = replies[e.data.return]
if (!fn)
throw new Error(`Could not find return function for message ${e.data.return}`)
fn(e.data)
delete replies[e.data.return]
return
}
if (receive_fn) {
if (e.data.reply) {
// Doing this here because there is no way for an actor to reply to the message if it doesn't get it in the first place
e.data.data[REPLYCC] = peer2id.get(e.peer)
e.data.data[REPLY] = e.data.reply
console.log(`set replycc and reply to ${e.data.data[REPLYCC]} and ${e.data.data[REPLY]}`)
}
receive_fn(e.data.data)
}
break
case "greet":
peers[e.data.id] = e.peer;
peer2id.set(e.peer, e.data.id);
console.log(`Registered a peer with ${e.data.id}`)
var greeter = greeters[e.data.id]
if (!greeter) return; //throw new Error(`No greeter registered for greet message id ${e.data.id}`)
greeter({
type: "actor_started",
actor: { id: e.data.id }
})
break
case "stop":
destroyself()
break
case "greet":
if (greeters[msg.guid]) {
var actor = guid2actor.get(msg.guid)
if (!actor) throw new Error(`No registered actor for guid ${msg.guid}`)
actor.peer = e.peer
guid2actor.set(e.peer, actor)
greeters[msg.guid]({
type: "actor_started",
actor
})
}
case "contact":
if (pppfn) pppfn(e.data)
break
}
}
var hang = 0.016
function handle_connect(e)
{
console.log(`message arrived at ${host.address}:${host.port} from somebody ... ${e.peer.address}:${e.peer.port}`)
var contact = peer2contact.get(e.peer)
if (contact) {
// We have successfully made contact. now send the request.
e.peer.send({
type: "contact",
data: contact.record
})
return
}
// For a local greet
e.peer.send({
type:"greet",
id: prosperon.id
})
}
var hang = 0.001
while (1) {
os.waitevent(e => {
unneeded_timer()
@@ -750,35 +870,26 @@ while (1) {
unneeded_timer()
switch(e.type) {
case "connect":
console.log(`message arrived at ${host.address}:${host.port} from somebody ... ${e.peer.address}:${e.peer.port}`)
e.peer.send({
type:"system",
data: {
type:"greet",
guid: prosperon.guid
}
})
break;
handle_connect(e);
break;
case "receive":
if (e.data.type === "system")
handle_system(e)
else if(receive_fn)
receive_fn(e.data.data)
else
console.log(`Got a messge but no receiver is registered.`)
handle_message(e)
break;
case "disconnect":
greeters[guid2actor.get(e.peer).guid]({
var id = peer2id(e.peer)
greeters[id]({
type: "actor_stopped"
})
handle_actor_disconnect(guid2actor.get(e.peer))
break
});
handle_actor_disconnect(id);
break;
}
unneeded_timer = $_.delay(unneeded_fn, unneeded_time)
}, hang);
if (portal)
portal.service(portal_fn, hang)
}
})()

View File

@@ -57,6 +57,8 @@ typedef struct rtree rtree;
#include <SDL3/SDL_loadso.h>
#include <SDL3/SDL_cpuinfo.h>
int randombytes(void *buf, size_t n);
static Uint32 timer_cb_event;
#ifdef __APPLE__
@@ -5747,8 +5749,7 @@ static const JSCFunctionListEntry js_input_funcs[] = {
JSC_CCALL(os_guid,
SDL_GUID guid;
for (int i = 0; i < 16; i++)
guid.data[i] = rand() % 256;
randombytes(guid.data, 16);
char guid_str[33];
@@ -7657,6 +7658,84 @@ static void exit_handler()
#include "monocypher.h"
// randombytes.c - Minimal cross-platform CSPRNG shim (single file)
/*
Usage:
#include "randombytes.c"
int main() {
uint8_t buffer[32];
if (randombytes(buffer, sizeof(buffer)) != 0) {
// handle error
}
// buffer now has 32 cryptographically secure random bytes
}
*/
#include <stdint.h>
#include <stddef.h>
#if defined(_WIN32)
// ------- Windows: use BCryptGenRandom -------
#include <windows.h>
#include <bcrypt.h>
int randombytes(void *buf, size_t n) {
NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
return (status == 0) ? 0 : -1;
}
#elif defined(__linux__)
// ------- Linux: try getrandom, fall back to /dev/urandom -------
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <errno.h>
// If we have a new enough libc and kernel, getrandom is available.
// Otherwise, well do a /dev/urandom fallback.
#include <sys/stat.h>
static int randombytes_fallback(void *buf, size_t n) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) return -1;
ssize_t r = read(fd, buf, n);
close(fd);
return (r == (ssize_t)n) ? 0 : -1;
}
int randombytes(void *buf, size_t n) {
#ifdef SYS_getrandom
// Try getrandom(2) if available
ssize_t ret = syscall(SYS_getrandom, buf, n, 0);
if (ret < 0) {
// If getrandom is not supported or fails, fall back
if (errno == ENOSYS) {
return randombytes_fallback(buf, n);
}
return -1;
}
return (ret == (ssize_t)n) ? 0 : -1;
#else
// getrandom not available, just fallback
return randombytes_fallback(buf, n);
#endif
}
#else
// ------- Other Unix: read from /dev/urandom -------
#include <fcntl.h>
#include <unistd.h>
int randombytes(void *buf, size_t n) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) return -1;
ssize_t r = read(fd, buf, n);
close(fd);
return (r == (ssize_t)n) ? 0 : -1;
}
#endif
static inline void to_hex(const uint8_t *in, size_t in_len, char *out)
{
static const char hexchars[] = "0123456789abcdef";
@@ -7721,8 +7800,8 @@ JSC_CCALL(crypto_keypair,
uint8_t public[32];
uint8_t private[32];
for (int i = 0; i < 32; i++)
private[i] = (uint8_t)rand();
randombytes(private,32);
private[0] &= 248;
private[31] &= 127;
@@ -7768,9 +7847,27 @@ JSC_CCALL(crypto_shared,
ret = crypto2js(js, shared);
})
JSC_CCALL(crypto_random,
{
// 1) Pull 64 bits of cryptographically secure randomness
uint64_t r;
if (randombytes(&r, sizeof(r)) != 0) {
// If something fails (extremely rare), throw an error
return JS_ThrowInternalError(js, "crypto.random: unable to get random bytes");
}
// 2) Convert r to a double in the range [0,1).
// We divide by (UINT64_MAX + 1.0) to ensure we never produce exactly 1.0.
double val = (double)r / ((double)UINT64_MAX + 1.0);
// 3) Return that as a JavaScript number
ret = JS_NewFloat64(js, val);
})
static const JSCFunctionListEntry js_crypto_funcs[] = {
MIST_FUNC_DEF(crypto, keypair, 0),
MIST_FUNC_DEF(crypto, shared, 1),
MIST_FUNC_DEF(crypto, random, 0),
};
MISTUSE(io)

View File

@@ -3,9 +3,10 @@
#include <enet/enet.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "script.h"
#define countof(a) (sizeof(a)/sizeof(*(a)))
static JSClassID enet_host_id;
@@ -53,7 +54,7 @@ static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val,
JSValue obj;
// Default parameters (if not provided by user)
size_t peer_count = 32;
size_t peer_count = 1000;
size_t channel_limit = 0;
enet_uint32 incoming_bandwidth = 0;
enet_uint32 outgoing_bandwidth = 0;
@@ -217,18 +218,17 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
printf("INVALID JSON!\n");
enet_packet_destroy(event.packet);
JS_FreeValue(ctx, event_obj);
JS_FreeValue(ctx, callback);
return JS_ThrowTypeError(ctx, "Received invalid JSON (parse error).");
uncaught_exception(ctx, packet_data);
continue;
}
if (!JS_IsObject(packet_data)) {
// It might be a string/number/array/... -> we want only a plain object
JS_FreeValue(ctx, event_obj);
JS_FreeValue(ctx, callback);
JS_FreeValue(ctx, packet_data);
enet_packet_destroy(event.packet);
return JS_ThrowTypeError(ctx,
"Received data is not an object (must send a plain object).");
uncaught_exception(ctx, JS_ThrowTypeError(ctx, "Received data is not an object (must send a plain object)."));
continue;
}
JS_SetPropertyStr(ctx, event_obj, "data", packet_data);
@@ -244,7 +244,7 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val,
}
// Invoke callback
JS_Call(ctx, callback, JS_UNDEFINED, 1, &event_obj);
uncaught_exception(ctx, JS_Call(ctx, callback, JS_UNDEFINED, 1, &event_obj));
JS_FreeValue(ctx, event_obj);
}
@@ -278,7 +278,7 @@ static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val,
ENetPeer *peer = enet_host_connect(host, &address, 2, 0);
if (!peer) {
return JS_ThrowInternalError(ctx, "Failed to initiate connection.");
return JS_ThrowInternalError(ctx, "No available peers for initiating an ENet connection.");
}
return peer_get_value(ctx, peer);
@@ -346,9 +346,22 @@ static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self, int argc,
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);
ENetHost *me = JS_GetOpaque(self, enet_host_id);
if (!me) return JS_EXCEPTION;
uint32_t host = ntohl(me->address.host);
if (host == 0x7F000001)
return JS_NewString(js, "localhost");
char ip_str[16]; // Enough space for "255.255.255.255" + null terminator
snprintf(ip_str, sizeof(ip_str), "%u.%u.%u.%u",
(host >> 24) & 0xFF,
(host >> 16) & 0xFF,
(host >> 8) & 0xFF,
host & 0xFF);
return JS_NewString(js, ip_str);
}
/* Peer-level operations */
@@ -399,7 +412,7 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val,
}
if (enet_peer_send(peer, 0, packet) < 0) {
return JS_ThrowInternalError(ctx, "enet_peer_send returned error.");
return JS_ThrowInternalError(ctx, "unable to send packet. send returned error.");
}
return JS_UNDEFINED;
}

View File

@@ -1,6 +1,7 @@
// Test to connect to a portal
$_.contact((actor, reason) => {
}, {
address: "localhost",
port: 5678,

View File

@@ -1,191 +0,0 @@
var os = use('os');
var enet = use('enet');
var json = use('json'); // Some QuickJS environments need this import for JSON
////////////////////////////////////////////////////////////////////////////////
// 1. Initialization
////////////////////////////////////////////////////////////////////////////////
// Make sure ENet is initialized before we do anything else
enet.initialize();
////////////////////////////////////////////////////////////////////////////////
// 2. "Framework": test runner & polling helper
////////////////////////////////////////////////////////////////////////////////
let results = [];
/**
* Simple test runner. Each test is given a name and a function.
* If the function throws an Error, the test is marked failed.
*/
function runTest(testName, testFunc) {
console.log(`=== Running Test: ${testName} ===`);
try {
testFunc();
results.push({ testName, passed: true });
} catch (err) {
console.log(`Test "${testName}" failed: ${err}`);
results.push({ testName, passed: false, error: err });
}
}
/**
* runSteps polls both client and server for `steps` iterations,
* each iteration calling service() with a small timeout. Any events
* are captured and returned in arrays for further inspection.
*
* @param {Object} client - the client ENet host
* @param {Object} server - the server ENet host
* @param {number} steps - how many iterations to process
* @param {boolean} printEvents - whether to log events to console
* @param {number} timeout - milliseconds to pass to service()
* @returns { clientEvents, serverEvents } arrays of all events captured
*/
function runSteps(client, server, steps = 5, printEvents = false, timeout = 10) {
let clientEvents = [];
let serverEvents = [];
for (let i = 0; i < steps; i++) {
// Poll the client
client.service((evt) => {
if (evt) {
clientEvents.push(evt);
if (printEvents) {
console.log("client:" + json.encode(evt));
}
}
}, timeout);
// Poll the server
server.service((evt) => {
if (evt) {
serverEvents.push(evt);
if (printEvents) {
console.log("server:" + json.encode(evt));
}
}
}, timeout);
}
return { clientEvents, serverEvents };
}
////////////////////////////////////////////////////////////////////////////////
// 3. Actual Tests
////////////////////////////////////////////////////////////////////////////////
let serverHost = null;
let clientHost = null;
let clientPeer = null;
runTest("Create Server", () => {
// Bind on 127.0.0.1:12345
serverHost = enet.create_host("127.0.0.1:12345");
if (!serverHost) {
throw new Error("Failed to create server host");
}
});
runTest("Create Client", () => {
clientHost = enet.create_host();
if (!clientHost) {
throw new Error("Failed to create client host");
}
});
runTest("Connect Client to Server", () => {
clientPeer = clientHost.connect("127.0.0.1", 12345);
if (!clientPeer) {
throw new Error("Failed to create client->server peer");
}
// Poll both sides for a few steps so the connection can succeed
const { clientEvents, serverEvents } = runSteps(clientHost, serverHost, 5, true);
// Verify the server got a 'connect' event
let connectEvent = serverEvents.find(evt => evt.type === "connect");
if (!connectEvent) {
throw new Error("Server did not receive a connect event");
}
});
runTest("Send Data from Client to Server", () => {
// Send some JSON object from client -> server
clientPeer.send({ hello: "HELLO" });
// Process for a few steps so the data actually arrives
const { clientEvents, serverEvents } = runSteps(clientHost, serverHost, 5, true);
// The server should get a 'receive' event
let receiveEvent = serverEvents.find(evt => evt.type === "receive");
if (!receiveEvent) {
throw new Error("Server did not receive data from the client");
}
// Check the payload
if (!receiveEvent.data || receiveEvent.data.hello !== "HELLO") {
throw new Error(`Server got unexpected data: ${JSON.stringify(receiveEvent.data)}`);
}
});
runTest("Broadcast from Server to Client", () => {
// The server broadcasts a JSON string
serverHost.broadcast({ broadcast: "HelloAll" });
// Let data flow
const { clientEvents, serverEvents } = runSteps(clientHost, serverHost, 5, true);
// Client should get a 'receive' event with broadcast data
let broadcastEvent = clientEvents.find(evt => evt.type === "receive");
if (!broadcastEvent) {
throw new Error("Client did not receive broadcast data");
}
// The broadcastEvent.data should be an object with broadcast="HelloAll"
if (!broadcastEvent.data || broadcastEvent.data.broadcast !== "HelloAll") {
throw new Error(`Client received unexpected broadcast: ${JSON.stringify(broadcastEvent.data)}`);
}
});
runTest("Disconnect Client", () => {
// Disconnect from the client side
clientPeer.disconnect();
// Let both sides see the disconnect
const { clientEvents, serverEvents } = runSteps(clientHost, serverHost, 5, true);
// The server should eventually get a "disconnect"
let disconnectEvent = serverEvents.find(evt => evt.type === "disconnect");
if (!disconnectEvent) {
throw new Error("Server never received a disconnect event");
}
});
runTest("Deinitialize ENet", () => {
enet.deinitialize();
});
////////////////////////////////////////////////////////////////////////////////
// 4. Print Summary & Exit
////////////////////////////////////////////////////////////////////////////////
console.log("\n=== Test Summary ===");
let passedCount = 0;
results.forEach(({ testName, passed, error }, idx) => {
console.log(`Test ${idx + 1}: ${testName} - ${passed ? "PASSED" : "FAILED"}`);
if (!passed && error) {
console.log(" Reason:", error);
}
if (passed) passedCount++;
});
console.log(`\nResult: ${passedCount}/${results.length} tests passed`);
if (passedCount < results.length) {
console.log("Overall: FAILED");
os.exit(1);
} else {
console.log("Overall: PASSED");
os.exit(0);
}

View File

@@ -4,6 +4,7 @@ $_.start(e => {
switch(e.type) {
case "actor_started":
console.log(`parent got system level actor_started msg`)
console.log(json.encode(e))
$_.connection(e => console.log(json.encode(e)), e.actor) // get connection info
$_.send(e.actor, {message: "Hello!"})
@@ -16,5 +17,3 @@ $_.start(e => {
$_.couple(e.actor)
}
}, "tests/underling.js");

View File

@@ -3,7 +3,13 @@
var password = "abc123"
$_.portal(e => {
console.log(`received a message for contact: ${json.encode(e)}`)
console.log(`got message with password ${e.password}`)
if (e.password !== password)
throw new Error("Password does not match.");
console.log(`passwords matched.`)
$_.send(e, {
actor: $_
});
}, 5678);

9
tests/reply.js Normal file
View File

@@ -0,0 +1,9 @@
var os = use('os')
$_.receiver(e => {
console.log(`Got a message: ${json.encode(e)}`)
$_.send(e, {
message: "Good to go."
})
})

9
tests/send.js Normal file
View File

@@ -0,0 +1,9 @@
var os = use('os')
$_.start(e => {
console.log(json.encode(e.actor))
$_.send(e.actor, { message: "Hello! Good to go?" }, msg => {
console.log(`Original sender got message back: ${json.encode(msg)}. Stopping!`)
$_.stop()
})
}, "tests/reply.js")