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