From d70dba021a6db08232cf4bf4a0c2746f9ba066ef Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sat, 13 Aug 2022 18:58:06 +0000 Subject: [PATCH] Do app -> client communication more like tfrpc so that it's easier to get responses. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3956 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- core/app.js | 74 ++++++++++++++++++++++++++++++++++---------------- core/client.js | 22 ++++++++++++--- core/tfrpc.js | 3 ++ 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/core/app.js b/core/app.js index b61a3e39..36eb3991 100644 --- a/core/app.js +++ b/core/app.js @@ -1,7 +1,10 @@ import * as auth from './auth.js'; import * as core from './core.js'; -var gSessionIndex = 0; +let g_next_id = 1; +let g_calls = {}; + +let gSessionIndex = 0; function makeSessionId() { return (gSessionIndex++).toString(); @@ -19,31 +22,45 @@ App.prototype.readOutput = function(callback) { App.prototype.makeFunction = function(api) { let self = this; + let id = g_next_id++; + while (!id || g_calls[id]) { + id = g_next_id++; + } + let promise = new Promise(function(resolve, reject) { + g_calls[id] = {resolve: resolve, reject: reject}; + }); let result = function() { - let message = {action: api[0]}; - for (let i = 1; i < api.length; i++) { - message[api[i]] = arguments[i - 1]; - } + let message = { + message: 'tfrpc', + method: api[0], + params: [...arguments], + id: id, + }; self.send(message); + return promise; }; 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._send_queue) { + if (this._on_output) { + this._send_queue.forEach(x => this._on_output(x)); + this._send_queue = null; + } else if (message) { + this._send_queue.push(message); + } } - if (this._on_output) { - this._send_queue.forEach(message => this._on_output(message)); - this._send_queue = []; + if (message && this._on_output) { + this._on_output(message); } } function socket(request, response, client) { - var process; - var options = {}; - var credentials = auth.query(request.headers); + let process; + let options = {}; + let credentials = auth.query(request.headers); response.onClose = async function() { if (process && process.task) { @@ -59,7 +76,7 @@ function socket(request, response, client) { response.onMessage = async function(event) { if (event.opCode == 0x1 || event.opCode == 0x2) { - var message; + let message; try { message = JSON.parse(event.data); } catch (error) { @@ -67,11 +84,11 @@ function socket(request, response, client) { return; } if (message.action == "hello") { - var packageOwner; - var packageName; - var blobId; - var match; - var parentApp; + let packageOwner; + let packageName; + let blobId; + let match; + let parentApp; if (match = /^\/([&%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(message.path)) { blobId = match[1]; } else if (match = /^\/\~([^\/]+)\/([^\/]+)\/$/.exec(message.path)) { @@ -83,7 +100,7 @@ function socket(request, response, client) { return; } if (packageOwner != 'core') { - var coreId = await new Database('core').get('path:' + packageName); + let coreId = await new Database('core').get('path:' + packageName); parentApp = { path: '/~core/' + packageName + '/', id: coreId, @@ -101,7 +118,7 @@ function socket(request, response, client) { options.credentials = credentials; options.packageOwner = packageOwner; options.packageName = packageName; - var sessionId = makeSessionId(); + let sessionId = makeSessionId(); if (blobId) { process = await core.getSessionProcessBlob(blobId, sessionId, options); } @@ -112,9 +129,9 @@ function socket(request, response, client) { process.app.send(); } - var ping = function() { - var now = Date.now(); - var again = true; + let ping = function() { + let now = Date.now(); + let again = true; if (now - process.lastActive < process.timeout) { // Active. } else if (process.lastPing > process.lastActive) { @@ -143,6 +160,15 @@ function socket(request, response, client) { } } else if (message.action == 'permission') { core.setPermission(process, message.id, message.granted); + } else if (message.message == 'tfrpc') { + if (message.id && g_calls[message.id]) { + if (message.error !== undefined) { + g_calls[message.id].reject(message.error); + } else { + g_calls[message.id].resolve(message.result); + } + delete g_calls[message.id]; + } } else { if (process && process.eventHandlers['message']) { await core.invoke(process.eventHandlers['message'], [message]); diff --git a/core/client.js b/core/client.js index 7213da2d..153a78f0 100644 --- a/core/client.js +++ b/core/client.js @@ -438,7 +438,7 @@ function api_localStorageSet(key, value) { } function api_localStorageGet(key, value) { - send({message: 'localStorage', key: key, value: window.localStorage.getItem('app:' + key)}); + return window.localStorage.getItem('app:' + key); } function api_requestPermission(permission, id) { @@ -594,10 +594,24 @@ function receive(message) { } timeseries.append(now, message.stats[key]); } - } else if (message && message.action) { - let api = k_api[message.action]; + } else if (message && + message.message === 'tfrpc' && + message.method) { + let api = k_api[message.method]; if (api) { - api.func(...api.args.map(x => message[x])); + Promise.resolve(api.func(...message.params)).then(function(result) { + send({ + message: 'tfrpc', + id: message.id, + result: result, + }); + }).catch(function(error) { + send({ + message: 'tfrpc', + id: message.id, + error: error, + }); + }); } } } diff --git a/core/tfrpc.js b/core/tfrpc.js index d422477c..d187db4d 100644 --- a/core/tfrpc.js +++ b/core/tfrpc.js @@ -14,6 +14,9 @@ if (k_is_browser) { function make_rpc(target, prop, receiver) { return function() { let id = g_next_id++; + while (!id || g_calls[id]) { + id = g_next_id++; + } let promise = new Promise(function(resolve, reject) { g_calls[id] = {resolve: resolve, reject: reject}; });