All checks were successful
Build Tilde Friends / Build-All (push) Successful in 31m35s
149 lines
3.0 KiB
JavaScript
149 lines
3.0 KiB
JavaScript
/**
|
|
* \file
|
|
* \defgroup tfrpc Tilde Friends RPC.
|
|
* Tilde Friends RPC.
|
|
* @{
|
|
*/
|
|
|
|
/** Whether this module is being run in a web browser. */
|
|
const k_is_browser = get_is_browser();
|
|
/** Registered methods. */
|
|
let g_api = {};
|
|
/** The next method identifier. */
|
|
let g_next_id = 1;
|
|
/** Identifiers of pending calls. */
|
|
let g_calls = {};
|
|
|
|
/**
|
|
* TODOC
|
|
* @returns
|
|
*/
|
|
function get_is_browser() {
|
|
try {
|
|
return window !== undefined && console !== undefined;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** \cond */
|
|
if (k_is_browser) {
|
|
print = console.log;
|
|
}
|
|
|
|
if (k_is_browser) {
|
|
window.addEventListener('message', function (event) {
|
|
call_rpc(event.data);
|
|
});
|
|
} else {
|
|
core.register('message', function (message) {
|
|
call_rpc(message?.message);
|
|
});
|
|
}
|
|
|
|
export let rpc = new Proxy({}, {get: make_rpc});
|
|
/** \endcond */
|
|
|
|
/**
|
|
* Make a function to invoke a remote procedure.
|
|
* @param target The target.
|
|
* @param prop The name of the function.
|
|
* @param receiver The receiver.
|
|
* @return A function.
|
|
*/
|
|
function make_rpc(target, prop, receiver) {
|
|
return function () {
|
|
let id = g_next_id++;
|
|
while (!id || g_calls[id] !== undefined) {
|
|
id = g_next_id++;
|
|
}
|
|
let promise = new Promise(function (resolve, reject) {
|
|
g_calls[id] = {resolve: resolve, reject: reject};
|
|
});
|
|
if (k_is_browser) {
|
|
window.parent.postMessage(
|
|
{message: 'tfrpc', method: prop, params: [...arguments], id: id},
|
|
'*'
|
|
);
|
|
return promise;
|
|
} else {
|
|
return app
|
|
.postMessage({
|
|
message: 'tfrpc',
|
|
method: prop,
|
|
params: [...arguments],
|
|
id: id,
|
|
})
|
|
.then((x) => promise);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Send a response.
|
|
* @param response The response.
|
|
*/
|
|
function send(response) {
|
|
if (k_is_browser) {
|
|
window.parent.postMessage(response, '*');
|
|
} else {
|
|
app.postMessage(response);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke a remote procedure.
|
|
* @param message An object describing the call.
|
|
*/
|
|
function call_rpc(message) {
|
|
if (message && message.message === 'tfrpc') {
|
|
let id = message.id;
|
|
if (message.method) {
|
|
let method = g_api[message.method];
|
|
if (method) {
|
|
try {
|
|
Promise.resolve(method(...message.params))
|
|
.then(function (result) {
|
|
send({message: 'tfrpc', id: id, result: result});
|
|
})
|
|
.catch(function (error) {
|
|
send({message: 'tfrpc', id: id, error: error});
|
|
});
|
|
} catch (error) {
|
|
send({message: 'tfrpc', id: id, error: error});
|
|
}
|
|
} else {
|
|
send({
|
|
message: 'tfrpc',
|
|
id: id,
|
|
error: `Method '${message.method}' not found.`,
|
|
});
|
|
}
|
|
} else if (message.error !== undefined) {
|
|
if (g_calls[id]) {
|
|
g_calls[id].reject(message.error);
|
|
delete g_calls[id];
|
|
} else {
|
|
throw new Error(id + ' not found to reply.');
|
|
}
|
|
} else {
|
|
if (g_calls[id]) {
|
|
g_calls[id].resolve(message.result);
|
|
delete g_calls[id];
|
|
} else {
|
|
throw new Error(id + ' not found to reply.');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register a function that to be called remotely.
|
|
* @param method The method.
|
|
*/
|
|
export function register(method) {
|
|
g_api[method.name] = method;
|
|
}
|
|
|
|
/** @} */
|