const k_is_browser = get_is_browser(); let g_api = {}; let g_next_id = 1; let g_calls = {}; function get_is_browser() { try { return window !== undefined && console !== undefined; } catch { return false; } } if (k_is_browser) { print = console.log; } function make_rpc(target, prop, receiver) { return function() { let 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); } } } function send(response) { if (k_is_browser) { window.parent.postMessage(response, '*'); } else { app.postMessage(response); } } function call_rpc(message) { if (message && message.message === 'tfrpc') { if (message.method) { let method = g_api[message.method]; if (method) { let response = {message: 'tfrpc', id: message.id}; try { Promise.resolve(method(...message.params)).then(function(result) { response.result = result; send(response); }).catch(function(error) { response.error = error; send(response); }); } catch (error) { response.error = error; send(response); } } else { throw new Error(message.method + ' not found.'); } } else if (message.error !== undefined) { if (g_calls[message.id]) { g_calls[message.id].reject(message.error); delete g_calls[message.id]; } else { throw new Error(message.id + ' not found to reply.'); } } else { if (g_calls[message.id]) { g_calls[message.id].resolve(message.result); delete g_calls[message.id]; } else { throw new Error(message.id + ' not found to reply.'); } } } } 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}); export function register(method) { g_api[method.name] = method; }