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
This commit is contained in:
Cory McWilliams 2022-08-13 18:58:06 +00:00
parent 41590921c3
commit d70dba021a
3 changed files with 71 additions and 28 deletions

View File

@ -1,7 +1,10 @@
import * as auth from './auth.js'; import * as auth from './auth.js';
import * as core from './core.js'; import * as core from './core.js';
var gSessionIndex = 0; let g_next_id = 1;
let g_calls = {};
let gSessionIndex = 0;
function makeSessionId() { function makeSessionId() {
return (gSessionIndex++).toString(); return (gSessionIndex++).toString();
@ -19,31 +22,45 @@ App.prototype.readOutput = function(callback) {
App.prototype.makeFunction = function(api) { App.prototype.makeFunction = function(api) {
let self = this; let self = this;
let result = function() { let id = g_next_id++;
let message = {action: api[0]}; while (!id || g_calls[id]) {
for (let i = 1; i < api.length; i++) { id = g_next_id++;
message[api[i]] = arguments[i - 1];
} }
let promise = new Promise(function(resolve, reject) {
g_calls[id] = {resolve: resolve, reject: reject};
});
let result = function() {
let message = {
message: 'tfrpc',
method: api[0],
params: [...arguments],
id: id,
};
self.send(message); self.send(message);
return promise;
}; };
Object.defineProperty(result, 'name', {value: api[0], writable: false}); Object.defineProperty(result, 'name', {value: api[0], writable: false});
return result; return result;
} }
App.prototype.send = function(message) { App.prototype.send = function(message) {
if (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); this._send_queue.push(message);
} }
if (this._on_output) { }
this._send_queue.forEach(message => this._on_output(message)); if (message && this._on_output) {
this._send_queue = []; this._on_output(message);
} }
} }
function socket(request, response, client) { function socket(request, response, client) {
var process; let process;
var options = {}; let options = {};
var credentials = auth.query(request.headers); let credentials = auth.query(request.headers);
response.onClose = async function() { response.onClose = async function() {
if (process && process.task) { if (process && process.task) {
@ -59,7 +76,7 @@ function socket(request, response, client) {
response.onMessage = async function(event) { response.onMessage = async function(event) {
if (event.opCode == 0x1 || event.opCode == 0x2) { if (event.opCode == 0x1 || event.opCode == 0x2) {
var message; let message;
try { try {
message = JSON.parse(event.data); message = JSON.parse(event.data);
} catch (error) { } catch (error) {
@ -67,11 +84,11 @@ function socket(request, response, client) {
return; return;
} }
if (message.action == "hello") { if (message.action == "hello") {
var packageOwner; let packageOwner;
var packageName; let packageName;
var blobId; let blobId;
var match; let match;
var parentApp; let parentApp;
if (match = /^\/([&%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(message.path)) { if (match = /^\/([&%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(message.path)) {
blobId = match[1]; blobId = match[1];
} else if (match = /^\/\~([^\/]+)\/([^\/]+)\/$/.exec(message.path)) { } else if (match = /^\/\~([^\/]+)\/([^\/]+)\/$/.exec(message.path)) {
@ -83,7 +100,7 @@ function socket(request, response, client) {
return; return;
} }
if (packageOwner != 'core') { if (packageOwner != 'core') {
var coreId = await new Database('core').get('path:' + packageName); let coreId = await new Database('core').get('path:' + packageName);
parentApp = { parentApp = {
path: '/~core/' + packageName + '/', path: '/~core/' + packageName + '/',
id: coreId, id: coreId,
@ -101,7 +118,7 @@ function socket(request, response, client) {
options.credentials = credentials; options.credentials = credentials;
options.packageOwner = packageOwner; options.packageOwner = packageOwner;
options.packageName = packageName; options.packageName = packageName;
var sessionId = makeSessionId(); let sessionId = makeSessionId();
if (blobId) { if (blobId) {
process = await core.getSessionProcessBlob(blobId, sessionId, options); process = await core.getSessionProcessBlob(blobId, sessionId, options);
} }
@ -112,9 +129,9 @@ function socket(request, response, client) {
process.app.send(); process.app.send();
} }
var ping = function() { let ping = function() {
var now = Date.now(); let now = Date.now();
var again = true; let again = true;
if (now - process.lastActive < process.timeout) { if (now - process.lastActive < process.timeout) {
// Active. // Active.
} else if (process.lastPing > process.lastActive) { } else if (process.lastPing > process.lastActive) {
@ -143,6 +160,15 @@ function socket(request, response, client) {
} }
} else if (message.action == 'permission') { } else if (message.action == 'permission') {
core.setPermission(process, message.id, message.granted); 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 { } else {
if (process && process.eventHandlers['message']) { if (process && process.eventHandlers['message']) {
await core.invoke(process.eventHandlers['message'], [message]); await core.invoke(process.eventHandlers['message'], [message]);

View File

@ -438,7 +438,7 @@ function api_localStorageSet(key, value) {
} }
function api_localStorageGet(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) { function api_requestPermission(permission, id) {
@ -594,10 +594,24 @@ function receive(message) {
} }
timeseries.append(now, message.stats[key]); timeseries.append(now, message.stats[key]);
} }
} else if (message && message.action) { } else if (message &&
let api = k_api[message.action]; message.message === 'tfrpc' &&
message.method) {
let api = k_api[message.method];
if (api) { 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,
});
});
} }
} }
} }

View File

@ -14,6 +14,9 @@ if (k_is_browser) {
function make_rpc(target, prop, receiver) { function make_rpc(target, prop, receiver) {
return function() { return function() {
let id = g_next_id++; let id = g_next_id++;
while (!id || g_calls[id]) {
id = g_next_id++;
}
let promise = new Promise(function(resolve, reject) { let promise = new Promise(function(resolve, reject) {
g_calls[id] = {resolve: resolve, reject: reject}; g_calls[id] = {resolve: resolve, reject: reject};
}); });