UNPKG

acebase-ipc-server

Version:

IPC Server that provides communication between isolated AceBase processes using the same database files, such as local pm2 and cloud-based clusters.

174 lines 8.12 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const server_1 = require("../server"); const http_1 = __importDefault(require("http")); const simple_observable_1 = require("./simple-observable"); const ws_1 = __importDefault(require("ws")); (function start() { return __awaiter(this, void 0, void 0, function* () { // TODO: finish this... const dbname = 'mydb', port = 9163, token = 'ewout', maxPayload = 50; const server = new server_1.AceBaseIPCServer({ port, token, maxPayload }); // dbname, yield server.start(); // Create test clients const n = 3; const clients = new Array(n).fill(0).map((n, i) => { const id = `client${i}`; console.log(`Creating client ${id}`); const ws = new ws_1.default(`ws://localhost:${port}/${dbname}/connect?id=${id}&v=1.0.0&t=${token}`); ws.addEventListener('open', e => console.log(`[${id}] open`)); ws.addEventListener('error', e => { console.error(e); }); ws.addEventListener('message', e => { const msg = e.data.toString(); console.log(`[${id}] message received:`, msg); if (msg.startsWith('welcome:')) { // Parse & use config const config = JSON.parse(msg.slice(8)); console.assert(config.maxPayload === maxPayload, 'we should get the configured payload back'); } else if (msg.startsWith('connect:')) { // Other peer connected console.log(`[${id}] peer connected: ${msg.slice(8)}`); } else if (msg.startsWith('disconnect:')) { // Other peer disconnected console.log(`[${id}] peer disconnected: ${msg.slice(11)}`); } }); const $events = new simple_observable_1.SimpleObservable(observer => { const onMessage = (ev) => __awaiter(this, void 0, void 0, function* () { let msg = ev.data; observer.next({ event: 'message', data: msg }); }); const onEvent = (ev) => { observer.next({ event: ev.type }); }; const onError = (ev) => { observer.next({ event: 'error', data: ev.error }); }; ws.addEventListener('message', onMessage); ws.addEventListener('open', onEvent); ws.addEventListener('close', onEvent); ws.addEventListener('error', onError); return function cleanup() { ws.removeEventListener('message', onMessage); ws.removeEventListener('open', onEvent); ws.removeEventListener('close', onEvent); ws.removeEventListener('error', onError); }; }); /** * Observable for messages received from other peers. Does not include service messages */ const $messages = new simple_observable_1.SimpleObservable(observer => { const onMessage = (ev) => __awaiter(this, void 0, void 0, function* () { let msg = ev.data; if (msg.startsWith('get:')) { // Large message, download const msgId = msg.slice(4); msg = yield fetch('GET', `/${dbname}/receive?id=${id}&msg=${msgId}&t=${token}`); } else if (/^[a-z]+:$/.test(msg)) { // Ignore other service messages return; } observer.next(msg); }); ws.addEventListener('message', onMessage); return () => { ws.removeEventListener('message', onMessage); }; }); return { get id() { return id; }, // ws: ws as WebSocket, send(msg) { return __awaiter(this, void 0, void 0, function* () { if (msg.length > maxPayload) { yield fetch('POST', `/${dbname}/send?id=${id}&t=${token}`, msg); } else { ws.send(msg); } }); }, onMessage: (callback) => { return $messages.subscribe(callback); }, onEvent: (callback) => { return $events.subscribe(ev => { callback(ev.event, ev.data); }); }, close() { ws.close(); } }; }); // wait for all to connect yield Promise.all(clients.map(client => { return new Promise(resolve => { let sub = client.onEvent(event => { if (event === 'open') { sub.unsubscribe(); resolve(); } }); }); })); // Let them all broadcast a hello message clients.forEach((client) => __awaiter(this, void 0, void 0, function* () { client.send(`Hello my name is ${client.id}`); })); // Simple fetch implementation for http GET and POST requests function fetch(method, path, postData) { return __awaiter(this, void 0, void 0, function* () { const options = { hostname: 'localhost', port, path, method, headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData || '') } }; return yield new Promise((resolve, reject) => { const req = http_1.default.request(options, (res) => { // console.log(`STATUS: ${res.statusCode}`); // console.log(`HEADERS: ${JSON.stringify(res.headers)}`); res.setEncoding('utf8'); let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { resolve(data); }); }); req.on('error', (e) => { reject(`problem with request: ${e.message}`); }); // Write data to request body req.write(postData); req.end(); }); }); } }); })(); //# sourceMappingURL=test.js.map