forked from cory/tildefriends
		
	Add a helper for app <-> browser communication.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3908 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		@@ -410,7 +410,7 @@ function api_error(error) {
 | 
			
		||||
		if (typeof(error) == 'string') {
 | 
			
		||||
			setStatusMessage('⚠️ ' + error, '#f00');
 | 
			
		||||
		} else {
 | 
			
		||||
			setStatusMessage('⚠️ ' + merror.message + '\n' + error.stack, '#f00');
 | 
			
		||||
			setStatusMessage('⚠️ ' + error.message + '\n' + error.stack, '#f00');
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	console.log('error', error);
 | 
			
		||||
 
 | 
			
		||||
@@ -225,6 +225,7 @@ async function getProcessBlob(blobId, key, options) {
 | 
			
		||||
					var id = appObject.files[appSourceName];
 | 
			
		||||
					var blob = await getBlobOrContent(id);
 | 
			
		||||
					appSource = utf8Decode(blob);
 | 
			
		||||
					await process.task.loadFile(['/tfrpc.js', await File.readFile('core/tfrpc.js')]);
 | 
			
		||||
					await Promise.all(Object.keys(appObject.files).map(async function(f) {
 | 
			
		||||
						await process.task.loadFile([f, await getBlobOrContent(appObject.files[f])]);
 | 
			
		||||
					}));
 | 
			
		||||
@@ -264,6 +265,7 @@ var kStaticFiles = [
 | 
			
		||||
	{uri: '/style.css', type: 'text/css; charset=UTF-8'},
 | 
			
		||||
	{uri: '/favicon.png', type: 'image/png'},
 | 
			
		||||
	{uri: '/client.js', type: 'text/javascript; charset=UTF-8'},
 | 
			
		||||
	{uri: '/tfrpc.js', type: 'text/javascript; charset=UTF-8', headers: {'Access-Control-Allow-Origin': 'null'}},
 | 
			
		||||
	{uri: '/robots.txt', type: 'text/plain; charset=UTF-8'},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@@ -285,7 +287,7 @@ async function staticFileHandler(request, response, blobId, uri) {
 | 
			
		||||
			var path = kStaticFiles[i].path || uri.substring(1);
 | 
			
		||||
			var type = kStaticFiles[i].type || guessType(path);
 | 
			
		||||
			var data = await File.readFile("core/" + path);
 | 
			
		||||
			response.writeHead(200, {"Content-Type": type, "Content-Length": data.byteLength});
 | 
			
		||||
			response.writeHead(200, Object.assign({"Content-Type": type, "Content-Length": data.byteLength}, kStaticFiles[i].headers || {}));
 | 
			
		||||
			response.end(data);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								core/tfrpc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								core/tfrpc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
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 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 {
 | 
			
		||||
					response.result = method(...message.params);
 | 
			
		||||
				} catch (error) {
 | 
			
		||||
					response.error = error;
 | 
			
		||||
				}
 | 
			
		||||
				if (k_is_browser) {
 | 
			
		||||
					window.parent.postMessage(response, '*');
 | 
			
		||||
				} else {
 | 
			
		||||
					app.postMessage(response);
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				throw new Error(message.method + ' not found.');
 | 
			
		||||
			}
 | 
			
		||||
		} else if (message.result !== undefined) {
 | 
			
		||||
			if (g_calls[message.id]) {
 | 
			
		||||
				g_calls[message.id].resolve(message.result);
 | 
			
		||||
			} else {
 | 
			
		||||
				throw new Error(message.id + ' not found to reply.');
 | 
			
		||||
			}
 | 
			
		||||
		} else if (message.error !== undefined) {
 | 
			
		||||
			if (g_calls[message.id]) {
 | 
			
		||||
				g_calls[message.id].reject(message.error);
 | 
			
		||||
			} 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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user