"use strict"; function App() { this._on_output = null; this._send_queue = []; return this; } App.prototype.readOutput = function(callback) { this._on_output = callback; } App.prototype.makeFunction = function(api) { let self = this; let result = function() { let message = {action: api[0]}; for (let i = 1; i < api.length; i++) { message[api[i]] = arguments[i - 1]; } self.send(message); }; Object.defineProperty(result, 'name', {value: api[0], writable: false}); return result; } App.prototype.send = function(message) { if (message) { this._send_queue.push(message); } if (this._on_output) { this._send_queue.forEach(message => this._on_output(message)); this._send_queue = []; } } function socket(request, response, client) { var process; var options = {}; var credentials = auth.query(request.headers); response.onClose = async function() { if (process && process.task) { process.task.kill(); } } response.onError = async function(error) { if (process && process.task) { process.task.kill(); } } response.onMessage = async function(event) { if (event.opCode == 0x1 || event.opCode == 0x2) { var message; try { message = JSON.parse(event.data); } catch (error) { print("ERROR", error, event.data, event.data.length, event.opCode); return; } if (message.action == "hello") { var packageOwner; var packageName; var blobId; var match; var parentApp; if (match = /^\/([&%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(message.path)) { blobId = match[1]; } else if (match = /^\/\~([^\/]+)\/([^\/]+)\/$/.exec(message.path)) { var user = match[1]; var path = match[2]; blobId = await new Database(user).get('path:' + path); if (!blobId) { response.send(JSON.stringify({action: "error", error: message.path + ' not found'}), 0x1); return; } if (user != 'core') { var coreId = await new Database('core').get('path:' + path); parentApp = { path: '/~core/' + path + '/', id: coreId, }; } } response.send(JSON.stringify({ action: "session", credentials: credentials, parentApp: parentApp, id: blobId, }), 0x1); options.api = message.api || []; options.credentials = credentials; var sessionId = makeSessionId(); if (blobId) { process = await getSessionProcessBlob(blobId, sessionId, options); } if (process) { process.app.readOutput(function(message) { response.send(JSON.stringify(message), 0x1); }); process.app.send(); } var ping = function() { var now = Date.now(); var again = true; if (now - process.lastActive < process.timeout) { // Active. } else if (process.lastPing > process.lastActive) { // We lost them. if (process.task) { process.task.kill(); } again = false; } else { // Idle. Ping them. response.send("", 0x9); process.lastPing = now; } if (again) { setTimeout(ping, process.timeout); } } if (process && process.timeout > 0) { setTimeout(ping, process.timeout); } } else if (message.action == 'enableStats') { process.stats = message.enabled; if (!gStatsTimer) { sendStats(); gStatsTimer = true; } } else { if (process && process.eventHandlers['message']) { await invoke(process.eventHandlers['message'], [message]); } } } else if (event.opCode == 0x8) { // Close. if (process && process.task) { process.task.kill(); } response.send(event.data, 0x8); } else if (event.opCode == 0xa) { // PONG } if (process) { process.lastActive = Date.now(); } } } exports.socket = socket;