Compare commits
	
		
			13 Commits
		
	
	
		
			v0.0.28
			...
			8912212d8e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8912212d8e | |||
| 6a346bf940 | |||
| b5bdae4611 | |||
| 6590da5793 | |||
| eb2b426ec7 | |||
| 4864a0411f | |||
| 68590cae33 | |||
| abf2bbaec2 | |||
| 0da7e2722f | |||
| 60d4b06057 | |||
| 4c3df34950 | |||
| 7737e60b52 | |||
| 71e816bc13 | 
| @@ -16,9 +16,9 @@ MAKEFLAGS += --no-builtin-rules | |||||||
| ## LD := Linker. | ## LD := Linker. | ||||||
| ## ANDROID_SDK := Path to the Android SDK. | ## ANDROID_SDK := Path to the Android SDK. | ||||||
|  |  | ||||||
| VERSION_CODE := 33 | VERSION_CODE := 34 | ||||||
| VERSION_CODE_IOS := 9 | VERSION_CODE_IOS := 11 | ||||||
| VERSION_NUMBER := 0.0.28 | VERSION_NUMBER := 0.0.29-wip | ||||||
| VERSION_NAME := This program kills fascists. | VERSION_NAME := This program kills fascists. | ||||||
|  |  | ||||||
| IPHONEOS_VERSION_MIN=14.0 | IPHONEOS_VERSION_MIN=14.0 | ||||||
|   | |||||||
							
								
								
									
										108
									
								
								core/app.js
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								core/app.js
									
									
									
									
									
								
							| @@ -1,53 +1,26 @@ | |||||||
| import * as core from './core.js'; | import * as core from './core.js'; | ||||||
|  |  | ||||||
| let g_next_id = 1; |  | ||||||
| let g_calls = {}; |  | ||||||
|  |  | ||||||
| let gSessionIndex = 0; | let gSessionIndex = 0; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function makeSessionId() { |  | ||||||
| 	return 'session_' + (gSessionIndex++).toString(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function App() { | function App() { | ||||||
| 	this._on_output = null; |  | ||||||
| 	this._send_queue = []; | 	this._send_queue = []; | ||||||
|  | 	this.calls = {}; | ||||||
|  | 	this._next_call_id = 1; | ||||||
| 	return this; | 	return this; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} callback |  | ||||||
|  */ |  | ||||||
| App.prototype.readOutput = function (callback) { |  | ||||||
| 	this._on_output = callback; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} api |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| App.prototype.makeFunction = function (api) { | App.prototype.makeFunction = function (api) { | ||||||
| 	let self = this; | 	let self = this; | ||||||
| 	let result = function () { | 	let result = function () { | ||||||
| 		let id = g_next_id++; | 		let id = self._next_call_id++; | ||||||
| 		while (!id || g_calls[id]) { | 		while (!id || self.calls[id]) { | ||||||
| 			id = g_next_id++; | 			id = self._next_call_id++; | ||||||
| 		} | 		} | ||||||
| 		let promise = new Promise(function (resolve, reject) { | 		let promise = new Promise(function (resolve, reject) { | ||||||
| 			g_calls[id] = {resolve: resolve, reject: reject}; | 			self.calls[id] = {resolve: resolve, reject: reject}; | ||||||
| 		}); | 		}); | ||||||
| 		let message = { | 		let message = { | ||||||
| 			message: 'tfrpc', | 			action: 'tfrpc', | ||||||
| 			method: api[0], | 			method: api[0], | ||||||
| 			params: [...arguments], | 			params: [...arguments], | ||||||
| 			id: id, | 			id: id, | ||||||
| @@ -59,10 +32,6 @@ App.prototype.makeFunction = function (api) { | |||||||
| 	return result; | 	return result; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} message |  | ||||||
|  */ |  | ||||||
| App.prototype.send = function (message) { | App.prototype.send = function (message) { | ||||||
| 	if (this._send_queue) { | 	if (this._send_queue) { | ||||||
| 		if (this._on_output) { | 		if (this._on_output) { | ||||||
| @@ -77,11 +46,6 @@ App.prototype.send = function (message) { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} request |  | ||||||
|  * @param {*} response |  | ||||||
|  */ |  | ||||||
| exports.app_socket = async function socket(request, response) { | exports.app_socket = async function socket(request, response) { | ||||||
| 	let process; | 	let process; | ||||||
| 	let options = {}; | 	let options = {}; | ||||||
| @@ -102,10 +66,16 @@ exports.app_socket = async function socket(request, response) { | |||||||
| 			try { | 			try { | ||||||
| 				message = JSON.parse(event.data); | 				message = JSON.parse(event.data); | ||||||
| 			} catch (error) { | 			} catch (error) { | ||||||
| 				print('ERROR', error, event.data, event.data.length, event.opCode); | 				print( | ||||||
|  | 					'WebSocket error:', | ||||||
|  | 					error, | ||||||
|  | 					event.data, | ||||||
|  | 					event.data.length, | ||||||
|  | 					event.opCode | ||||||
|  | 				); | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			if (message.action == 'hello') { | 			if (!process && message.action == 'hello') { | ||||||
| 				let packageOwner; | 				let packageOwner; | ||||||
| 				let packageName; | 				let packageName; | ||||||
| 				let blobId; | 				let blobId; | ||||||
| @@ -122,7 +92,7 @@ exports.app_socket = async function socket(request, response) { | |||||||
| 					if (!blobId) { | 					if (!blobId) { | ||||||
| 						response.send( | 						response.send( | ||||||
| 							JSON.stringify({ | 							JSON.stringify({ | ||||||
| 								message: 'tfrpc', | 								action: 'tfrpc', | ||||||
| 								method: 'error', | 								method: 'error', | ||||||
| 								params: [message.path + ' not found'], | 								params: [message.path + ' not found'], | ||||||
| 								id: -1, | 								id: -1, | ||||||
| @@ -163,7 +133,7 @@ exports.app_socket = async function socket(request, response) { | |||||||
| 				options.packageOwner = packageOwner; | 				options.packageOwner = packageOwner; | ||||||
| 				options.packageName = packageName; | 				options.packageName = packageName; | ||||||
| 				options.url = message.url; | 				options.url = message.url; | ||||||
| 				let sessionId = makeSessionId(); | 				let sessionId = 'session_' + (gSessionIndex++).toString(); | ||||||
| 				if (blobId) { | 				if (blobId) { | ||||||
| 					if (message.edit_only) { | 					if (message.edit_only) { | ||||||
| 						response.send( | 						response.send( | ||||||
| @@ -175,9 +145,24 @@ exports.app_socket = async function socket(request, response) { | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				if (process) { | 				if (process) { | ||||||
| 					process.app.readOutput(function (message) { | 					process.client_api.tfrpc = function (message) { | ||||||
|  | 						if (message.id) { | ||||||
|  | 							let calls = process?.app?.calls; | ||||||
|  | 							if (calls) { | ||||||
|  | 								let call = calls[message.id]; | ||||||
|  | 								if (call) { | ||||||
|  | 									if (message.error !== undefined) { | ||||||
|  | 										call.reject(message.error); | ||||||
|  | 									} else { | ||||||
|  | 										call.resolve(message.result); | ||||||
|  | 									} | ||||||
|  | 									delete calls[message.id]; | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					}; | ||||||
|  | 					process.app._on_output = (message) => | ||||||
| 						response.send(JSON.stringify(message), 0x1); | 						response.send(JSON.stringify(message), 0x1); | ||||||
| 					}); |  | ||||||
| 					process.app.send(); | 					process.app.send(); | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| @@ -206,26 +191,13 @@ exports.app_socket = async function socket(request, response) { | |||||||
| 				if (process && process.timeout > 0) { | 				if (process && process.timeout > 0) { | ||||||
| 					setTimeout(ping, process.timeout); | 					setTimeout(ping, process.timeout); | ||||||
| 				} | 				} | ||||||
| 			} else if (message.action == 'resetPermission') { |  | ||||||
| 				if (process) { |  | ||||||
| 					process.resetPermission(message.permission); |  | ||||||
| 				} |  | ||||||
| 			} else if (message.action == 'setActiveIdentity') { |  | ||||||
| 				process.setActiveIdentity(message.identity); |  | ||||||
| 			} else if (message.action == 'createIdentity') { |  | ||||||
| 				await process.createIdentity(); |  | ||||||
| 			} 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) { | ||||||
| 					await core.invoke(process.eventHandlers['message'], [message]); | 					if (process.client_api[message.action]) { | ||||||
|  | 						process.client_api[message.action](message); | ||||||
|  | 					} else if (process.eventHandlers['message']) { | ||||||
|  | 						await core.invoke(process.eventHandlers['message'], [message]); | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} else if (event.opCode == 0x8) { | 		} else if (event.opCode == 0x8) { | ||||||
|   | |||||||
| @@ -1325,7 +1325,7 @@ function _receive_websocket_message(message) { | |||||||
| 				line.append(key, message.stats[key]); | 				line.append(key, message.stats[key]); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else if (message && message.message === 'tfrpc' && message.method) { | 	} else if (message && message.action === 'tfrpc' && message.method) { | ||||||
| 		let api = k_api[message.method]; | 		let api = k_api[message.method]; | ||||||
| 		let id = message.id; | 		let id = message.id; | ||||||
| 		let params = message.params; | 		let params = message.params; | ||||||
| @@ -1333,14 +1333,14 @@ function _receive_websocket_message(message) { | |||||||
| 			Promise.resolve(api.func(...params)) | 			Promise.resolve(api.func(...params)) | ||||||
| 				.then(function (result) { | 				.then(function (result) { | ||||||
| 					send({ | 					send({ | ||||||
| 						message: 'tfrpc', | 						action: 'tfrpc', | ||||||
| 						id: id, | 						id: id, | ||||||
| 						result: result, | 						result: result, | ||||||
| 					}); | 					}); | ||||||
| 				}) | 				}) | ||||||
| 				.catch(function (error) { | 				.catch(function (error) { | ||||||
| 					send({ | 					send({ | ||||||
| 						message: 'tfrpc', | 						action: 'tfrpc', | ||||||
| 						id: id, | 						id: id, | ||||||
| 						error: error, | 						error: error, | ||||||
| 					}); | 					}); | ||||||
|   | |||||||
							
								
								
									
										124
									
								
								core/core.js
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								core/core.js
									
									
									
									
									
								
							| @@ -3,31 +3,22 @@ import * as http from './http.js'; | |||||||
|  |  | ||||||
| let gProcesses = {}; | let gProcesses = {}; | ||||||
| let gStatsTimer = false; | let gStatsTimer = false; | ||||||
| let kPingInterval = 60 * 1000; | let g_handler_index = 0; | ||||||
|  |  | ||||||
| /** | const k_ping_interval = 60 * 1000; | ||||||
|  * TODOC |  | ||||||
|  * @param {*} out | function printError(error) { | ||||||
|  * @param {*} error |  | ||||||
|  */ |  | ||||||
| function printError(out, error) { |  | ||||||
| 	if (error.stackTrace) { | 	if (error.stackTrace) { | ||||||
| 		out.print(error.fileName + ':' + error.lineNumber + ': ' + error.message); | 		print(error.fileName + ':' + error.lineNumber + ': ' + error.message); | ||||||
| 		out.print(error.stackTrace); | 		print(error.stackTrace); | ||||||
| 	} else { | 	} else { | ||||||
| 		for (let [k, v] of Object.entries(error)) { | 		for (let [k, v] of Object.entries(error)) { | ||||||
| 			out.print(k, v); | 			print(k, v); | ||||||
| 		} | 		} | ||||||
| 		out.print(error.toString()); | 		print(error.toString()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} handlers |  | ||||||
|  * @param {*} argv |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function invoke(handlers, argv) { | function invoke(handlers, argv) { | ||||||
| 	let promises = []; | 	let promises = []; | ||||||
| 	if (handlers) { | 	if (handlers) { | ||||||
| @@ -48,12 +39,6 @@ function invoke(handlers, argv) { | |||||||
| 	return Promise.all(promises); | 	return Promise.all(promises); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} eventName |  | ||||||
|  * @param {*} argv |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function broadcastEvent(eventName, argv) { | function broadcastEvent(eventName, argv) { | ||||||
| 	let promises = []; | 	let promises = []; | ||||||
| 	for (let process of Object.values(gProcesses)) { | 	for (let process of Object.values(gProcesses)) { | ||||||
| @@ -64,11 +49,6 @@ function broadcastEvent(eventName, argv) { | |||||||
| 	return Promise.all(promises); | 	return Promise.all(promises); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} message |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function broadcast(message) { | function broadcast(message) { | ||||||
| 	let sender = this; | 	let sender = this; | ||||||
| 	let promises = []; | 	let promises = []; | ||||||
| @@ -85,12 +65,6 @@ function broadcast(message) { | |||||||
| 	return Promise.all(promises); | 	return Promise.all(promises); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {String} eventName |  | ||||||
|  * @param {*} argv |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function broadcastAppEventToUser( | function broadcastAppEventToUser( | ||||||
| 	user, | 	user, | ||||||
| 	packageOwner, | 	packageOwner, | ||||||
| @@ -113,12 +87,6 @@ function broadcastAppEventToUser( | |||||||
| 	return Promise.all(promises); | 	return Promise.all(promises); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} caller |  | ||||||
|  * @param {*} process |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function getUser(caller, process) { | function getUser(caller, process) { | ||||||
| 	return { | 	return { | ||||||
| 		key: process.key, | 		key: process.key, | ||||||
| @@ -129,12 +97,6 @@ function getUser(caller, process) { | |||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} user |  | ||||||
|  * @param {*} process |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| async function getApps(user, process) { | async function getApps(user, process) { | ||||||
| 	if ( | 	if ( | ||||||
| 		process.credentials && | 		process.credentials && | ||||||
| @@ -161,28 +123,13 @@ async function getApps(user, process) { | |||||||
| 	return {}; | 	return {}; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} from |  | ||||||
|  * @param {*} to |  | ||||||
|  * @param {*} message |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function postMessageInternal(from, to, message) { | function postMessageInternal(from, to, message) { | ||||||
| 	if (to.eventHandlers['message']) { | 	if (to.eventHandlers['message']) { | ||||||
| 		return invoke(to.eventHandlers['message'], [getUser(from, from), message]); | 		return invoke(to.eventHandlers['message'], [getUser(from, from), message]); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  * @param {*} blobId |  | ||||||
|  * @param {*} key |  | ||||||
|  * @param {*} options |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| async function getProcessBlob(blobId, key, options) { | async function getProcessBlob(blobId, key, options) { | ||||||
| 	// TODO(tasiaiso): break this down ? |  | ||||||
| 	let process = gProcesses[key]; | 	let process = gProcesses[key]; | ||||||
| 	if (!process && !(options && 'create' in options && !options.create)) { | 	if (!process && !(options && 'create' in options && !options.create)) { | ||||||
| 		let resolveReady; | 		let resolveReady; | ||||||
| @@ -201,7 +148,7 @@ async function getProcessBlob(blobId, key, options) { | |||||||
| 			} | 			} | ||||||
| 			process.lastActive = Date.now(); | 			process.lastActive = Date.now(); | ||||||
| 			process.lastPing = null; | 			process.lastPing = null; | ||||||
| 			process.timeout = kPingInterval; | 			process.timeout = k_ping_interval; | ||||||
| 			process.ready = new Promise(function (resolve, reject) { | 			process.ready = new Promise(function (resolve, reject) { | ||||||
| 				resolveReady = resolve; | 				resolveReady = resolve; | ||||||
| 				rejectReady = reject; | 				rejectReady = reject; | ||||||
| @@ -461,10 +408,10 @@ async function getProcessBlob(blobId, key, options) { | |||||||
| 					if (process.app) { | 					if (process.app) { | ||||||
| 						process.app.makeFunction(['error'])(error); | 						process.app.makeFunction(['error'])(error); | ||||||
| 					} else { | 					} else { | ||||||
| 						printError({print: print}, error); | 						printError(error); | ||||||
| 					} | 					} | ||||||
| 				} catch (e) { | 				} catch (e) { | ||||||
| 					printError({print: print}, error); | 					printError(error); | ||||||
| 				} | 				} | ||||||
| 			}; | 			}; | ||||||
| 			imports.ssb = Object.fromEntries( | 			imports.ssb = Object.fromEntries( | ||||||
| @@ -649,17 +596,26 @@ async function getProcessBlob(blobId, key, options) { | |||||||
| 					permissions: await imports.core.permissionsGranted(), | 					permissions: await imports.core.permissionsGranted(), | ||||||
| 				}); | 				}); | ||||||
| 			}; | 			}; | ||||||
| 			process.resetPermission = async function resetPermission(permission) { | 			process.client_api = { | ||||||
| 				let user = process?.credentials?.session?.name; | 				createIdentity: function () { | ||||||
| 				await ssb.setUserPermission( | 					return process.createIdentity(); | ||||||
| 					user, | 				}, | ||||||
| 					options?.packageOwner, | 				resetPermission: async function resetPermission(message) { | ||||||
| 					options?.packageName, | 					let user = process?.credentials?.session?.name; | ||||||
| 					permission, | 					await ssb.setUserPermission( | ||||||
| 					undefined | 						user, | ||||||
| 				); | 						options?.packageOwner, | ||||||
| 				return process.sendPermissions(); | 						options?.packageName, | ||||||
|  | 						message.permission, | ||||||
|  | 						undefined | ||||||
|  | 					); | ||||||
|  | 					return process.sendPermissions(); | ||||||
|  | 				}, | ||||||
|  | 				setActiveIdentity: function setActiveIdentity(message) { | ||||||
|  | 					return process.setActiveIdentity(message.identity); | ||||||
|  | 				}, | ||||||
| 			}; | 			}; | ||||||
|  | 			ssb.registerImports(imports, process); | ||||||
| 			process.task.setImports(imports); | 			process.task.setImports(imports); | ||||||
| 			process.task.activate(); | 			process.task.activate(); | ||||||
| 			let source = await ssb.blobGet(blobId); | 			let source = await ssb.blobGet(blobId); | ||||||
| @@ -686,7 +642,7 @@ async function getProcessBlob(blobId, key, options) { | |||||||
| 					); | 					); | ||||||
| 				} | 				} | ||||||
| 			} catch (e) { | 			} catch (e) { | ||||||
| 				printError({print: print}, e); | 				printError(e); | ||||||
| 			} | 			} | ||||||
| 			broadcastEvent('onSessionBegin', [getUser(process, process)]); | 			broadcastEvent('onSessionBegin', [getUser(process, process)]); | ||||||
| 			if (process.app) { | 			if (process.app) { | ||||||
| @@ -700,14 +656,10 @@ async function getProcessBlob(blobId, key, options) { | |||||||
| 				sendStats(); | 				sendStats(); | ||||||
| 			} | 			} | ||||||
| 		} catch (error) { | 		} catch (error) { | ||||||
| 			if (process.app) { | 			if (process?.app && process?.task?.onError) { | ||||||
| 				if (process?.task?.onError) { | 				process.task.onError(error); | ||||||
| 					process.task.onError(error); |  | ||||||
| 				} else { |  | ||||||
| 					printError({print: print}, error); |  | ||||||
| 				} |  | ||||||
| 			} else { | 			} else { | ||||||
| 				printError({print: print}, error); | 				printError(error); | ||||||
| 			} | 			} | ||||||
| 			rejectReady(error); | 			rejectReady(error); | ||||||
| 		} | 		} | ||||||
| @@ -727,9 +679,6 @@ ssb.addEventListener('connections', function () { | |||||||
| 	broadcastEvent('onConnectionsChanged', []); | 	broadcastEvent('onConnectionsChanged', []); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  */ |  | ||||||
| async function loadSettings() { | async function loadSettings() { | ||||||
| 	let data = {}; | 	let data = {}; | ||||||
| 	try { | 	try { | ||||||
| @@ -748,9 +697,6 @@ async function loadSettings() { | |||||||
| 	return data; | 	return data; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * TODOC |  | ||||||
|  */ |  | ||||||
| function sendStats() { | function sendStats() { | ||||||
| 	let apps = Object.values(gProcesses) | 	let apps = Object.values(gProcesses) | ||||||
| 		.filter((process) => process.app) | 		.filter((process) => process.app) | ||||||
| @@ -766,8 +712,6 @@ function sendStats() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| let g_handler_index = 0; |  | ||||||
|  |  | ||||||
| exports.callAppHandler = async function callAppHandler( | exports.callAppHandler = async function callAppHandler( | ||||||
| 	response, | 	response, | ||||||
| 	app_blob_id, | 	app_blob_id, | ||||||
|   | |||||||
| @@ -25,14 +25,14 @@ | |||||||
| }: | }: | ||||||
| pkgs.stdenv.mkDerivation rec { | pkgs.stdenv.mkDerivation rec { | ||||||
|   pname = "tildefriends"; |   pname = "tildefriends"; | ||||||
|   version = "0.0.27.1"; |   version = "0.0.28"; | ||||||
|  |  | ||||||
|   src = pkgs.fetchFromGitea { |   src = pkgs.fetchFromGitea { | ||||||
|     domain = "dev.tildefriends.net"; |     domain = "dev.tildefriends.net"; | ||||||
|     owner = "cory"; |     owner = "cory"; | ||||||
|     repo = "tildefriends"; |     repo = "tildefriends"; | ||||||
|     rev = "v${version}"; |     rev = "v${version}"; | ||||||
|     hash = "sha256-3t1m9ZomQF3DteWyALJWrnCq0EAROEK8shKXh6Ao38c="; |     hash = "sha256-vcLJCXgIrjC37t9oavK2QMRcMJljghuzKDYxQ4nyTcE="; | ||||||
|     fetchSubmodules = true; |     fetchSubmodules = true; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
| 	package="com.unprompted.tildefriends" | 	package="com.unprompted.tildefriends" | ||||||
| 	android:versionCode="33" | 	android:versionCode="34" | ||||||
| 	android:versionName="0.0.28"> | 	android:versionName="0.0.29-wip"> | ||||||
| 	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | 	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | ||||||
| 	<uses-permission android:name="android.permission.INTERNET"/> | 	<uses-permission android:name="android.permission.INTERNET"/> | ||||||
| 	<application | 	<application | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								src/api.js.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/api.js.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | #include "api.js.h" | ||||||
|  |  | ||||||
|  | #include "log.h" | ||||||
|  |  | ||||||
|  | #include <quickjs.h> | ||||||
|  |  | ||||||
|  | static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) | ||||||
|  | { | ||||||
|  | 	return JS_UNDEFINED; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void tf_api_register(JSContext* context) | ||||||
|  | { | ||||||
|  | 	JSValue global = JS_GetGlobalObject(context); | ||||||
|  | 	JSValue ssb = JS_GetPropertyStr(context, global, "ssb"); | ||||||
|  | 	JS_SetPropertyStr(context, ssb, "registerImports", JS_NewCFunction(context, _tf_api_register_imports, "registerImports", 2)); | ||||||
|  | 	JS_FreeValue(context, ssb); | ||||||
|  | 	JS_FreeValue(context, global); | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/api.js.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/api.js.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | ** \defgroup api_js JS API | ||||||
|  | ** Functions that are ultimately exposed to apps. | ||||||
|  | ** @{ | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | /** A JS context. */ | ||||||
|  | typedef struct JSContext JSContext; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | ** Register JS API functions. | ||||||
|  | ** @param context The JS context. | ||||||
|  | */ | ||||||
|  | void tf_api_register(JSContext* context); | ||||||
|  |  | ||||||
|  | /** @} */ | ||||||
							
								
								
									
										50
									
								
								src/http.c
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								src/http.c
									
									
									
									
									
								
							| @@ -84,6 +84,7 @@ typedef struct _tf_http_listener_t | |||||||
| typedef struct _tf_http_t | typedef struct _tf_http_t | ||||||
| { | { | ||||||
| 	bool is_shutting_down; | 	bool is_shutting_down; | ||||||
|  | 	bool is_in_destroy; | ||||||
|  |  | ||||||
| 	tf_http_listener_t** listeners; | 	tf_http_listener_t** listeners; | ||||||
| 	int listeners_count; | 	int listeners_count; | ||||||
| @@ -395,7 +396,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d | |||||||
|  |  | ||||||
| 				if (fin) | 				if (fin) | ||||||
| 				{ | 				{ | ||||||
| 					if (connection->request->on_message) | 					if (connection->request && connection->request->on_message) | ||||||
| 					{ | 					{ | ||||||
| 						tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "websocket"); | 						tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "websocket"); | ||||||
| 						connection->request->on_message(connection->request, connection->fragment_length ? connection->fragment_op_code : op_code, | 						connection->request->on_message(connection->request, connection->fragment_length ? connection->fragment_op_code : op_code, | ||||||
| @@ -786,7 +787,13 @@ static void _http_free_listener_on_close(uv_handle_t* handle) | |||||||
|  |  | ||||||
| void tf_http_destroy(tf_http_t* http) | void tf_http_destroy(tf_http_t* http) | ||||||
| { | { | ||||||
|  | 	if (http->is_in_destroy) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	http->is_shutting_down = true; | 	http->is_shutting_down = true; | ||||||
|  | 	http->is_in_destroy = true; | ||||||
|  |  | ||||||
| 	for (int i = 0; i < http->connections_count; i++) | 	for (int i = 0; i < http->connections_count; i++) | ||||||
| 	{ | 	{ | ||||||
| @@ -845,6 +852,10 @@ void tf_http_destroy(tf_http_t* http) | |||||||
|  |  | ||||||
| 		tf_free(http); | 		tf_free(http); | ||||||
| 	} | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		http->is_in_destroy = false; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| const char* tf_http_status_text(int status) | const char* tf_http_status_text(int status) | ||||||
| @@ -963,9 +974,42 @@ static void _http_write(tf_http_connection_t* connection, const void* data, size | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void tf_http_request_send(tf_http_request_t* request, const void* data, size_t size) | void tf_http_request_websocket_send(tf_http_request_t* request, int op_code, const void* data, size_t size) | ||||||
| { | { | ||||||
| 	_http_write(request->connection, data, size); | 	uint8_t* copy = tf_malloc(size + 16); | ||||||
|  | 	bool fin = true; | ||||||
|  | 	size_t header = 1; | ||||||
|  | 	copy[0] = (fin ? (1 << 7) : 0) | (op_code & 0xf); | ||||||
|  | 	if (size < 126) | ||||||
|  | 	{ | ||||||
|  | 		copy[1] = size; | ||||||
|  | 		header += 1; | ||||||
|  | 	} | ||||||
|  | 	else if (size < (1 << 16)) | ||||||
|  | 	{ | ||||||
|  | 		copy[1] = 126; | ||||||
|  | 		copy[2] = (size >> 8) & 0xff; | ||||||
|  | 		copy[3] = (size >> 0) & 0xff; | ||||||
|  | 		header += 3; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		uint32_t high = ((uint64_t)size >> 32) & 0xffffffff; | ||||||
|  | 		uint32_t low = (size >> 0) & 0xffffffff; | ||||||
|  | 		copy[1] = 127; | ||||||
|  | 		copy[2] = (high >> 24) & 0xff; | ||||||
|  | 		copy[3] = (high >> 16) & 0xff; | ||||||
|  | 		copy[4] = (high >> 8) & 0xff; | ||||||
|  | 		copy[5] = (high >> 0) & 0xff; | ||||||
|  | 		copy[6] = (low >> 24) & 0xff; | ||||||
|  | 		copy[7] = (low >> 16) & 0xff; | ||||||
|  | 		copy[8] = (low >> 8) & 0xff; | ||||||
|  | 		copy[9] = (low >> 0) & 0xff; | ||||||
|  | 		header += 9; | ||||||
|  | 	} | ||||||
|  | 	memcpy(copy + header, data, size); | ||||||
|  | 	_http_write(request->connection, copy, header + size); | ||||||
|  | 	tf_free(copy); | ||||||
| } | } | ||||||
|  |  | ||||||
| void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length) | void tf_http_respond(tf_http_request_t* request, int status, const char** headers, int headers_count, const void* body, size_t content_length) | ||||||
|   | |||||||
| @@ -209,10 +209,11 @@ const char* tf_http_get_cookie(const char* cookie_header, const char* name); | |||||||
| ** Send a websocket message. | ** Send a websocket message. | ||||||
| ** @param request The HTTP request which was previously updated to a websocket | ** @param request The HTTP request which was previously updated to a websocket | ||||||
| ** session with tf_http_request_websocket_upgrade(). | ** session with tf_http_request_websocket_upgrade(). | ||||||
|  | ** @param op_code Websocket op code. | ||||||
| ** @param data The message data. | ** @param data The message data. | ||||||
| ** @param size The size of data. | ** @param size The size of data. | ||||||
| */ | */ | ||||||
| void tf_http_request_send(tf_http_request_t* request, const void* data, size_t size); | void tf_http_request_websocket_send(tf_http_request_t* request, int op_code, const void* data, size_t size); | ||||||
|  |  | ||||||
| /** | /** | ||||||
| ** Upgrade an HTTP request to a websocket session. | ** Upgrade an HTTP request to a websocket session. | ||||||
|   | |||||||
| @@ -152,44 +152,9 @@ static JSValue _httpd_response_send(JSContext* context, JSValueConst this_val, i | |||||||
| 	tf_http_request_t* request = JS_GetOpaque(this_val, _httpd_request_class_id); | 	tf_http_request_t* request = JS_GetOpaque(this_val, _httpd_request_class_id); | ||||||
| 	int opcode = 0x1; | 	int opcode = 0x1; | ||||||
| 	JS_ToInt32(context, &opcode, argv[1]); | 	JS_ToInt32(context, &opcode, argv[1]); | ||||||
| 	uint64_t length = 0; | 	size_t length = 0; | ||||||
| 	size_t length_size = 0; | 	const char* message = JS_ToCStringLen(context, &length, argv[0]); | ||||||
| 	const char* message = JS_ToCStringLen(context, &length_size, argv[0]); | 	tf_http_request_websocket_send(request, opcode, message, length); | ||||||
| 	length = length_size; |  | ||||||
| 	uint8_t* copy = tf_malloc(length + 16); |  | ||||||
| 	bool fin = true; |  | ||||||
| 	size_t header = 1; |  | ||||||
| 	copy[0] = (fin ? (1 << 7) : 0) | (opcode & 0xf); |  | ||||||
| 	if (length < 126) |  | ||||||
| 	{ |  | ||||||
| 		copy[1] = length; |  | ||||||
| 		header += 1; |  | ||||||
| 	} |  | ||||||
| 	else if (length < (1 << 16)) |  | ||||||
| 	{ |  | ||||||
| 		copy[1] = 126; |  | ||||||
| 		copy[2] = (length >> 8) & 0xff; |  | ||||||
| 		copy[3] = (length >> 0) & 0xff; |  | ||||||
| 		header += 3; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		uint32_t high = (length >> 32) & 0xffffffff; |  | ||||||
| 		uint32_t low = (length >> 0) & 0xffffffff; |  | ||||||
| 		copy[1] = 127; |  | ||||||
| 		copy[2] = (high >> 24) & 0xff; |  | ||||||
| 		copy[3] = (high >> 16) & 0xff; |  | ||||||
| 		copy[4] = (high >> 8) & 0xff; |  | ||||||
| 		copy[5] = (high >> 0) & 0xff; |  | ||||||
| 		copy[6] = (low >> 24) & 0xff; |  | ||||||
| 		copy[7] = (low >> 16) & 0xff; |  | ||||||
| 		copy[8] = (low >> 8) & 0xff; |  | ||||||
| 		copy[9] = (low >> 0) & 0xff; |  | ||||||
| 		header += 9; |  | ||||||
| 	} |  | ||||||
| 	memcpy(copy + header, message, length); |  | ||||||
| 	tf_http_request_send(request, copy, header + length); |  | ||||||
| 	tf_free(copy); |  | ||||||
| 	JS_FreeCString(context, message); | 	JS_FreeCString(context, message); | ||||||
| 	return JS_UNDEFINED; | 	return JS_UNDEFINED; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,13 +13,13 @@ | |||||||
| 	<key>CFBundlePackageType</key> | 	<key>CFBundlePackageType</key> | ||||||
| 	<string>APPL</string> | 	<string>APPL</string> | ||||||
| 	<key>CFBundleShortVersionString</key> | 	<key>CFBundleShortVersionString</key> | ||||||
| 	<string>0.0.28</string> | 	<string>0.0.29</string> | ||||||
| 	<key>CFBundleSupportedPlatforms</key> | 	<key>CFBundleSupportedPlatforms</key> | ||||||
| 	<array> | 	<array> | ||||||
| 		<string>iPhoneOS</string> | 		<string>iPhoneOS</string> | ||||||
| 	</array> | 	</array> | ||||||
| 	<key>CFBundleVersion</key> | 	<key>CFBundleVersion</key> | ||||||
| 	<string>9</string> | 	<string>11</string> | ||||||
| 	<key>DTPlatformName</key> | 	<key>DTPlatformName</key> | ||||||
| 	<string>iphoneos</string> | 	<string>iphoneos</string> | ||||||
| 	<key>LSRequiresIPhoneOS</key> | 	<key>LSRequiresIPhoneOS</key> | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #include "task.h" | #include "task.h" | ||||||
|  |  | ||||||
|  | #include "api.js.h" | ||||||
| #include "bcrypt.js.h" | #include "bcrypt.js.h" | ||||||
| #include "database.js.h" | #include "database.js.h" | ||||||
| #include "file.js.h" | #include "file.js.h" | ||||||
| @@ -1697,6 +1698,7 @@ void tf_task_activate(tf_task_t* task) | |||||||
| 		task->_ssb = tf_ssb_create(&task->_loop, task->_context, task->_db_path, task->_network_key); | 		task->_ssb = tf_ssb_create(&task->_loop, task->_context, task->_db_path, task->_network_key); | ||||||
| 		tf_ssb_set_trace(task->_ssb, task->_trace); | 		tf_ssb_set_trace(task->_ssb, task->_trace); | ||||||
| 		tf_ssb_register(context, task->_ssb); | 		tf_ssb_register(context, task->_ssb); | ||||||
|  | 		tf_api_register(context); | ||||||
| 		tf_ssb_set_hitch_callback(task->_ssb, _tf_task_record_hitch, task); | 		tf_ssb_set_hitch_callback(task->_ssb, _tf_task_record_hitch, task); | ||||||
|  |  | ||||||
| 		if (task->_args) | 		if (task->_args) | ||||||
|   | |||||||
| @@ -1,2 +1,2 @@ | |||||||
| #define VERSION_NUMBER "0.0.28" | #define VERSION_NUMBER "0.0.29-wip" | ||||||
| #define VERSION_NAME "This program kills fascists." | #define VERSION_NAME "This program kills fascists." | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user