All checks were successful
		
		
	
	Build Tilde Friends / Build-All (push) Successful in 31m24s
				
			
		
			
				
	
	
		
			149 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			3.1 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 = {};
 | |
| 
 | |
| /**
 | |
|  * Check if being called from a browser vs. server-side.
 | |
|  * @return true if called from a browser.
 | |
|  */
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /** @} */
 |