Compare commits
2 Commits
main
...
tasiaiso-n
Author | SHA1 | Date | |
---|---|---|---|
d67e47ae4b | |||
b43b8da9ab |
@ -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 := 34
|
VERSION_CODE := 33
|
||||||
VERSION_CODE_IOS := 11
|
VERSION_CODE_IOS := 8
|
||||||
VERSION_NUMBER := 0.0.29-wip
|
VERSION_NUMBER := 0.0.28-wip
|
||||||
VERSION_NAME := This program kills fascists.
|
VERSION_NAME := This program kills fascists.
|
||||||
|
|
||||||
IPHONEOS_VERSION_MIN=14.0
|
IPHONEOS_VERSION_MIN=14.0
|
||||||
@ -1419,7 +1419,7 @@ dist-ios: iosrelease-app
|
|||||||
mkdir -p out/Payload/tildefriends.app
|
mkdir -p out/Payload/tildefriends.app
|
||||||
cp -avR out/tildefriends-iosrelease.app/* out/Payload/tildefriends.app/
|
cp -avR out/tildefriends-iosrelease.app/* out/Payload/tildefriends.app/
|
||||||
cp src/ios/tildefriends.png out/Payload/tildefriends.app/
|
cp src/ios/tildefriends.png out/Payload/tildefriends.app/
|
||||||
xcrun -sdk iphoneos actool --compile out/Payload/tildefriends.app/ --platform iphoneos --minimum-deployment-target $(IPHONEOS_VERSION_MIN) --app-icon AppIcon src/ios/icons/Assets.xcassets src/ios/icons/*.png --output-partial-info-plist out/actool.plist
|
cp src/ios/icons/Assets.car out/Payload/tildefriends.app/
|
||||||
cp src/ios/distribution.mobileprovision out/Payload/tildefriends.app/embedded.mobileprovision
|
cp src/ios/distribution.mobileprovision out/Payload/tildefriends.app/embedded.mobileprovision
|
||||||
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/Payload/tildefriends.app
|
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/Payload/tildefriends.app
|
||||||
cd out; zip -r tildefriends.ipa Payload; cd ..
|
cd out; zip -r tildefriends.ipa Payload; cd ..
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
async function main() {
|
async function main() {
|
||||||
print(core.url);
|
let host = core.url.match(/.*\/\/(.*?)\//)[1];
|
||||||
let host = core.url.match(/.*?\/\/([^:/]*)/)[1];
|
|
||||||
let port = await ssb.port();
|
|
||||||
let id = (await ssb.getServerIdentity()).substring(1);
|
let id = (await ssb.getServerIdentity()).substring(1);
|
||||||
let room = `net:${host}:${port}~shs:${id}:SSB+Room+SK3TLYC2T86EHQCUHBUHASCASE18JBV24=`;
|
let room = `net:${host}:${ssb.port}~shs:${id}:SSB+Room+SK3TLYC2T86EHQCUHBUHASCASE18JBV24=`;
|
||||||
await app.setDocument(`
|
await app.setDocument(`
|
||||||
<body style="color: #fff">
|
<body style="color: #fff">
|
||||||
<h1>Server</h1>
|
<h1>Server</h1>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🦀",
|
"emoji": "🦀",
|
||||||
"previous": "&Qae0CxJGEH7OspuapuXX/GurmV+VBtQiMhHRmCBKCwU=.sha256"
|
"previous": "&jAAzd36Nmpw0sRA1Dx9wLiIwGX+q//+S/Han+RLlEOw=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -206,21 +206,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_accordian(id) {
|
|
||||||
let element = this.renderRoot.getElementById(id);
|
|
||||||
element.classList.toggle('w3-hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
valid_connections() {
|
|
||||||
return this.connections.filter((x) => x.tunnel === undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
valid_broadcasts() {
|
|
||||||
return this.broadcasts
|
|
||||||
.filter((x) => x.address)
|
|
||||||
.filter((x) => this.connections.map((c) => c.id).indexOf(x.pubkey) == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
return html`
|
return html`
|
||||||
@ -235,33 +220,27 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
>
|
>
|
||||||
Connect
|
Connect
|
||||||
</button>
|
</button>
|
||||||
<h2
|
<h2>Broadcasts</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<ul class="w3-ul w3-border">
|
||||||
@click=${() => self.toggle_accordian('connections')}
|
${this.broadcasts
|
||||||
>
|
.filter((x) => x.address)
|
||||||
Connections (${this.valid_connections().length})
|
.filter(
|
||||||
</h2>
|
(x) => self.connections.map((c) => c.id).indexOf(x.pubkey) == -1
|
||||||
<ul class="w3-ul w3-border" id="connections">
|
)
|
||||||
${this.valid_connections().map(
|
.map((x) => self.render_broadcast(x))}
|
||||||
(x) => html` <li class="w3-bar">${this.render_connection(x)}</li> `
|
</ul>
|
||||||
|
<h2>Connections</h2>
|
||||||
|
<ul class="w3-ul w3-border">
|
||||||
|
${this.connections
|
||||||
|
.filter((x) => x.tunnel === undefined)
|
||||||
|
.map(
|
||||||
|
(x) => html`
|
||||||
|
<li class="w3-bar">${this.render_connection(x)}</li>
|
||||||
|
`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<h2
|
<h2>Stored Connections</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<ul class="w3-ul w3-border">
|
||||||
@click=${() => self.toggle_accordian('broadcasts')}
|
|
||||||
>
|
|
||||||
Broadcasts (${this.valid_broadcasts().length})
|
|
||||||
</h2>
|
|
||||||
<ul class="w3-ul w3-border w3-hide" id="broadcasts">
|
|
||||||
${this.valid_broadcasts().map((x) => self.render_broadcast(x))}
|
|
||||||
</ul>
|
|
||||||
<h2
|
|
||||||
class="w3-button w3-block w3-theme-d1"
|
|
||||||
@click=${() => self.toggle_accordian('stored_connections')}
|
|
||||||
>
|
|
||||||
Stored Connections (${this.stored_connections.length})
|
|
||||||
</h2>
|
|
||||||
<ul class="w3-ul w3-border w3-hide" id="stored_connections">
|
|
||||||
${this.stored_connections.map(
|
${this.stored_connections.map(
|
||||||
(x) => html`
|
(x) => html`
|
||||||
<li>
|
<li>
|
||||||
@ -288,13 +267,8 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<h2
|
<h2>Local Accounts</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<div class="w3-container">
|
||||||
@click=${() => self.toggle_accordian('local_accounts')}
|
|
||||||
>
|
|
||||||
Local Accounts (${this.identities.length})
|
|
||||||
</h2>
|
|
||||||
<div class="w3-container w3-hide" id="local_accounts">
|
|
||||||
${this.identities.map(
|
${this.identities.map(
|
||||||
(x) =>
|
(x) =>
|
||||||
html`<div
|
html`<div
|
||||||
|
106
core/app.js
@ -1,26 +1,53 @@
|
|||||||
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 = self._next_call_id++;
|
let id = g_next_id++;
|
||||||
while (!id || self.calls[id]) {
|
while (!id || g_calls[id]) {
|
||||||
id = self._next_call_id++;
|
id = g_next_id++;
|
||||||
}
|
}
|
||||||
let promise = new Promise(function (resolve, reject) {
|
let promise = new Promise(function (resolve, reject) {
|
||||||
self.calls[id] = {resolve: resolve, reject: reject};
|
g_calls[id] = {resolve: resolve, reject: reject};
|
||||||
});
|
});
|
||||||
let message = {
|
let message = {
|
||||||
action: 'tfrpc',
|
message: 'tfrpc',
|
||||||
method: api[0],
|
method: api[0],
|
||||||
params: [...arguments],
|
params: [...arguments],
|
||||||
id: id,
|
id: id,
|
||||||
@ -32,6 +59,10 @@ 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) {
|
||||||
@ -46,6 +77,11 @@ 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 = {};
|
||||||
@ -66,16 +102,10 @@ 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(
|
print('ERROR', error, event.data, event.data.length, event.opCode);
|
||||||
'WebSocket error:',
|
|
||||||
error,
|
|
||||||
event.data,
|
|
||||||
event.data.length,
|
|
||||||
event.opCode
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!process && message.action == 'hello') {
|
if (message.action == 'hello') {
|
||||||
let packageOwner;
|
let packageOwner;
|
||||||
let packageName;
|
let packageName;
|
||||||
let blobId;
|
let blobId;
|
||||||
@ -92,7 +122,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
if (!blobId) {
|
if (!blobId) {
|
||||||
response.send(
|
response.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
action: 'tfrpc',
|
message: 'tfrpc',
|
||||||
method: 'error',
|
method: 'error',
|
||||||
params: [message.path + ' not found'],
|
params: [message.path + ' not found'],
|
||||||
id: -1,
|
id: -1,
|
||||||
@ -133,7 +163,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 = 'session_' + (gSessionIndex++).toString();
|
let sessionId = makeSessionId();
|
||||||
if (blobId) {
|
if (blobId) {
|
||||||
if (message.edit_only) {
|
if (message.edit_only) {
|
||||||
response.send(
|
response.send(
|
||||||
@ -145,24 +175,9 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (process) {
|
if (process) {
|
||||||
process.client_api.tfrpc = function (message) {
|
process.app.readOutput(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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,13 +206,26 @@ 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 {
|
} else if (message.action == 'resetPermission') {
|
||||||
if (process) {
|
if (process) {
|
||||||
if (process.client_api[message.action]) {
|
process.resetPermission(message.permission);
|
||||||
process.client_api[message.action](message);
|
|
||||||
} else if (process.eventHandlers['message']) {
|
|
||||||
await core.invoke(process.eventHandlers['message'], [message]);
|
|
||||||
}
|
}
|
||||||
|
} 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 {
|
||||||
|
if (process && 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.action === 'tfrpc' && message.method) {
|
} else if (message && message.message === '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({
|
||||||
action: 'tfrpc',
|
message: 'tfrpc',
|
||||||
id: id,
|
id: id,
|
||||||
result: result,
|
result: result,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(function (error) {
|
.catch(function (error) {
|
||||||
send({
|
send({
|
||||||
action: 'tfrpc',
|
message: 'tfrpc',
|
||||||
id: id,
|
id: id,
|
||||||
error: error,
|
error: error,
|
||||||
});
|
});
|
||||||
|
106
core/core.js
@ -3,22 +3,31 @@ import * as http from './http.js';
|
|||||||
|
|
||||||
let gProcesses = {};
|
let gProcesses = {};
|
||||||
let gStatsTimer = false;
|
let gStatsTimer = false;
|
||||||
let g_handler_index = 0;
|
let kPingInterval = 60 * 1000;
|
||||||
|
|
||||||
const k_ping_interval = 60 * 1000;
|
/**
|
||||||
|
* TODOC
|
||||||
function printError(error) {
|
* @param {*} out
|
||||||
|
* @param {*} error
|
||||||
|
*/
|
||||||
|
function printError(out, error) {
|
||||||
if (error.stackTrace) {
|
if (error.stackTrace) {
|
||||||
print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
out.print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
||||||
print(error.stackTrace);
|
out.print(error.stackTrace);
|
||||||
} else {
|
} else {
|
||||||
for (let [k, v] of Object.entries(error)) {
|
for (let [k, v] of Object.entries(error)) {
|
||||||
print(k, v);
|
out.print(k, v);
|
||||||
}
|
}
|
||||||
print(error.toString());
|
out.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) {
|
||||||
@ -39,6 +48,12 @@ 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)) {
|
||||||
@ -49,6 +64,11 @@ 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 = [];
|
||||||
@ -65,6 +85,12 @@ 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,
|
||||||
@ -87,6 +113,12 @@ 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,
|
||||||
@ -97,6 +129,12 @@ 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 &&
|
||||||
@ -123,13 +161,28 @@ 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;
|
||||||
@ -148,7 +201,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
process.lastActive = Date.now();
|
process.lastActive = Date.now();
|
||||||
process.lastPing = null;
|
process.lastPing = null;
|
||||||
process.timeout = k_ping_interval;
|
process.timeout = kPingInterval;
|
||||||
process.ready = new Promise(function (resolve, reject) {
|
process.ready = new Promise(function (resolve, reject) {
|
||||||
resolveReady = resolve;
|
resolveReady = resolve;
|
||||||
rejectReady = reject;
|
rejectReady = reject;
|
||||||
@ -408,10 +461,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(error);
|
printError({print: print}, error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
printError(error);
|
printError({print: print}, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
imports.ssb = Object.fromEntries(
|
imports.ssb = Object.fromEntries(
|
||||||
@ -596,26 +649,17 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
permissions: await imports.core.permissionsGranted(),
|
permissions: await imports.core.permissionsGranted(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
process.client_api = {
|
process.resetPermission = async function resetPermission(permission) {
|
||||||
createIdentity: function () {
|
|
||||||
return process.createIdentity();
|
|
||||||
},
|
|
||||||
resetPermission: async function resetPermission(message) {
|
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
await ssb.setUserPermission(
|
await ssb.setUserPermission(
|
||||||
user,
|
user,
|
||||||
options?.packageOwner,
|
options?.packageOwner,
|
||||||
options?.packageName,
|
options?.packageName,
|
||||||
message.permission,
|
permission,
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
return process.sendPermissions();
|
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);
|
||||||
@ -642,7 +686,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
printError(e);
|
printError({print: print}, e);
|
||||||
}
|
}
|
||||||
broadcastEvent('onSessionBegin', [getUser(process, process)]);
|
broadcastEvent('onSessionBegin', [getUser(process, process)]);
|
||||||
if (process.app) {
|
if (process.app) {
|
||||||
@ -656,10 +700,14 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
sendStats();
|
sendStats();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (process?.app && process?.task?.onError) {
|
if (process.app) {
|
||||||
|
if (process?.task?.onError) {
|
||||||
process.task.onError(error);
|
process.task.onError(error);
|
||||||
} else {
|
} else {
|
||||||
printError(error);
|
printError({print: print}, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printError({print: print}, error);
|
||||||
}
|
}
|
||||||
rejectReady(error);
|
rejectReady(error);
|
||||||
}
|
}
|
||||||
@ -679,6 +727,9 @@ ssb.addEventListener('connections', function () {
|
|||||||
broadcastEvent('onConnectionsChanged', []);
|
broadcastEvent('onConnectionsChanged', []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
*/
|
||||||
async function loadSettings() {
|
async function loadSettings() {
|
||||||
let data = {};
|
let data = {};
|
||||||
try {
|
try {
|
||||||
@ -697,6 +748,9 @@ 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)
|
||||||
@ -712,6 +766,8 @@ 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,
|
||||||
|
@ -31,8 +31,8 @@ pkgs.stdenv.mkDerivation rec {
|
|||||||
domain = "dev.tildefriends.net";
|
domain = "dev.tildefriends.net";
|
||||||
owner = "cory";
|
owner = "cory";
|
||||||
repo = "tildefriends";
|
repo = "tildefriends";
|
||||||
rev = "v${version}";
|
rev = "f02423d0846fefd5ab21fa4542fb77ce5714547c";
|
||||||
hash = "sha256-vcLJCXgIrjC37t9oavK2QMRcMJljghuzKDYxQ4nyTcE=";
|
hash = "sha256-QyM7wmViXJc4r8uTu4oE/HO3Z9tzNbFIX2+AOTQz9ZY=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
deps/codemirror/cm6.js
vendored
6
deps/codemirror_src/package-lock.json
generated
vendored
@ -115,9 +115,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/search": {
|
"node_modules/@codemirror/search": {
|
||||||
"version": "6.5.10",
|
"version": "6.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.10.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.9.tgz",
|
||||||
"integrity": "sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==",
|
"integrity": "sha512-7DdQ9aaZMMxuWB1u6IIFWWuK9NocVZwvo4nG8QjJTS6oZGvteoLSiXw3EbVZVlO08Ri2ltO89JVInMpfcJxhtg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.0.0",
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
- run the tests
|
- run the tests
|
||||||
- format + prettier
|
- format + prettier
|
||||||
- update metadata/en-US/changelogs
|
- update metadata/en-US/changelogs
|
||||||
- git tag v1.2.3
|
- git tag
|
||||||
- git tag -f latest_release
|
|
||||||
- push
|
- push
|
||||||
- make a release on gitea
|
- make a release on gitea
|
||||||
- upload the artifacts
|
- upload the artifacts
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
# Upgrading
|
|
||||||
|
|
||||||
Tilde Friends can be upgraded simply by running a new executable against an
|
|
||||||
existing database.
|
|
||||||
|
|
||||||
Tilde Friends writes all data to a `db.sqlite` file, either in
|
|
||||||
`~/.local/share/tildefriends/` or in the working directory where it is run,
|
|
||||||
depending on the platform and whether each one already exists. Run with
|
|
||||||
`tildefriends run -d DB_PATH` to specify the path to the database explicitly.
|
|
||||||
|
|
||||||
This file can be copied and moved across machines as needed like any [sqlite3
|
|
||||||
database](https://www.sqlite.org/onefile.html).
|
|
||||||
|
|
||||||
Schema changes and compatibility breaks have been rare, by design. In general,
|
|
||||||
upgrading is not expected to require any manual intervention and likely does
|
|
||||||
not involve any automatic migration, either. Downgrading is not well-supported
|
|
||||||
but will probably just work excepting rare changes that will be called out in
|
|
||||||
the changelog.
|
|
22
flake.nix
@ -35,5 +35,27 @@
|
|||||||
graphviz
|
graphviz
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nixosModules.default = {
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
# Shorter name to access final settings a
|
||||||
|
# user of hello.nix module HAS ACTUALLY SET.
|
||||||
|
# cfg is a typical convention.
|
||||||
|
cfg = config.services.tildefriends;
|
||||||
|
in {
|
||||||
|
options.services.tildefriends = {
|
||||||
|
enable = lib.mkEnableOption "Enable Tilde Friends";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
systemd.services.tildefriends = {
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
serviceConfig.ExecStart = "${pkgs.tildefriends}/bin/tildefriends";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
* Allow specifying all global settings from the command-line (CLI usage changed).
|
|
||||||
* Replication improvements.
|
|
||||||
* An iOS build is on TestFlight.
|
* An iOS build is on TestFlight.
|
||||||
* macOS targets are debug and release like everywhere else.
|
* macOS targets are debug and release like everywhere else.
|
||||||
* Running from a subdirectory is fine.
|
* Running from a subdirectory is fine.
|
||||||
@ -7,9 +5,10 @@
|
|||||||
* Invite fixes.
|
* Invite fixes.
|
||||||
* Follow/block UI fixes.
|
* Follow/block UI fixes.
|
||||||
* Mobile automatically logs in.
|
* Mobile automatically logs in.
|
||||||
* Updates:
|
* Allow specifying all global settings from the command-line.
|
||||||
|
* UpdateS:
|
||||||
* CodeMirror
|
* CodeMirror
|
||||||
* OpenSSL 3.4.1
|
* OpenSSL 3.4.1
|
||||||
* libbacktrace
|
* libbacktrace
|
||||||
* speedscope 1.22.2
|
|
||||||
* sqlite 3.49.1
|
* sqlite 3.49.1
|
||||||
|
* speedscope 1.22.2
|
||||||
|
6
package-lock.json
generated
@ -11,9 +11,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.5.2",
|
"version": "3.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
|
||||||
"integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==",
|
"integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
|
@ -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="34"
|
android:versionCode="33"
|
||||||
android:versionName="0.0.29-wip">
|
android:versionName="0.0.28-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
@ -1,19 +0,0 @@
|
|||||||
#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
@ -1,18 +0,0 @@
|
|||||||
#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
@ -84,7 +84,6 @@ 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;
|
||||||
@ -396,7 +395,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
|
|
||||||
if (fin)
|
if (fin)
|
||||||
{
|
{
|
||||||
if (connection->request && connection->request->on_message)
|
if (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,
|
||||||
@ -787,13 +786,7 @@ 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++)
|
||||||
{
|
{
|
||||||
@ -852,10 +845,6 @@ 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)
|
||||||
@ -974,42 +963,9 @@ static void _http_write(tf_http_connection_t* connection, const void* data, size
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_http_request_websocket_send(tf_http_request_t* request, int op_code, const void* data, size_t size)
|
void tf_http_request_send(tf_http_request_t* request, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t* copy = tf_malloc(size + 16);
|
_http_write(request->connection, data, size);
|
||||||
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,11 +209,10 @@ 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_websocket_send(tf_http_request_t* request, int op_code, const void* data, size_t size);
|
void tf_http_request_send(tf_http_request_t* request, const void* data, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Upgrade an HTTP request to a websocket session.
|
** Upgrade an HTTP request to a websocket session.
|
||||||
|
@ -152,9 +152,44 @@ 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]);
|
||||||
size_t length = 0;
|
uint64_t length = 0;
|
||||||
const char* message = JS_ToCStringLen(context, &length, argv[0]);
|
size_t length_size = 0;
|
||||||
tf_http_request_websocket_send(request, opcode, message, length);
|
const char* message = JS_ToCStringLen(context, &length_size, argv[0]);
|
||||||
|
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.29</string>
|
<string>0.0.28</string>
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
<array>
|
<array>
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>11</string>
|
<string>8</string>
|
||||||
<key>DTPlatformName</key>
|
<key>DTPlatformName</key>
|
||||||
<string>iphoneos</string>
|
<string>iphoneos</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
BIN
src/ios/icons/Assets.car
Normal file
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 974 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.9 KiB |
@ -1 +1 @@
|
|||||||
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]}
|
{"images":[{"idiom":"ios-marketing","scale":"1x","size":"1024x1024","filename":"icon-ios-marketing-1-1024-1024.png"}],"info":{"author":"xcode","version":1}}
|
After Width: | Height: | Size: 101 KiB |
1
src/ios/icons/Assets.xcassets/Contents.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"info": {"version": 1, "author": "xcode"}}
|
BIN
src/ios/icons/android/mipmap-hdpi.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
src/ios/icons/android/mipmap-ldpi.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/ios/icons/android/mipmap-mdpi.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
src/ios/icons/android/mipmap-xhdpi.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src/ios/icons/android/mipmap-xxhdpi.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/ios/icons/android/mipmap-xxxhdpi.png
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 74 KiB |
BIN
src/ios/icons/ios/100.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
src/ios/icons/ios/114.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
src/ios/icons/ios/128.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
src/ios/icons/ios/16.png
Normal file
After Width: | Height: | Size: 639 B |
BIN
src/ios/icons/ios/172.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/ios/icons/ios/180.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/ios/icons/ios/196.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/ios/icons/ios/216.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
src/ios/icons/ios/256.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
src/ios/icons/ios/32.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/ios/icons/ios/48.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
src/ios/icons/ios/50.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
src/ios/icons/ios/512.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
src/ios/icons/ios/55.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
src/ios/icons/ios/64.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
src/ios/icons/ios/88.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/ios/icons/ios/icon-120.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src/ios/icons/ios/icon-144.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/ios/icons/ios/icon-152.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/ios/icons/ios/icon-167.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/ios/icons/ios/icon-72.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
src/ios/icons/ios/icon-76.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
src/ios/icons/ios/icon-notification.png
Normal file
After Width: | Height: | Size: 858 B |
BIN
src/ios/icons/ios/icon-notification@2x.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
src/ios/icons/ios/icon-notification@3x.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src/ios/icons/ios/icon-small-120.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src/ios/icons/ios/icon-small-40.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
src/ios/icons/ios/icon-small-80.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/ios/icons/ios/icon-small.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/ios/icons/ios/icon-small@2x.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/ios/icons/ios/icon-small@3x.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/ios/icons/ios/icon-store.png
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
src/ios/icons/ios/icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/ios/icons/ios/icon@2x.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 56 KiB |
BIN
src/ios/icons/uploaded.png
Normal file
After Width: | Height: | Size: 104 KiB |
@ -1057,7 +1057,7 @@ static int _tf_command_get_profile(const char* file, int argc, char* argv[])
|
|||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
tf_free((void*)profile);
|
tf_free((void*)profile);
|
||||||
tf_free((void*)default_db_path);
|
tf_free((void*)default_db_path);
|
||||||
return profile != NULL ? EXIT_SUCCESS : EXIT_FAILURE;
|
return profile != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _tf_command_get_contacts(const char* file, int argc, char* argv[])
|
static int _tf_command_get_contacts(const char* file, int argc, char* argv[])
|
||||||
@ -1299,12 +1299,10 @@ static int _tf_run_task(const tf_run_args_t* args, int index)
|
|||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
int64_t http_port = 0;
|
int64_t http_port = 0;
|
||||||
int64_t https_port = 0;
|
int64_t https_port = 0;
|
||||||
char out_http_port_file[512] = "";
|
|
||||||
tf_ssb_db_get_global_setting_int64(db, "http_port", &http_port);
|
tf_ssb_db_get_global_setting_int64(db, "http_port", &http_port);
|
||||||
tf_ssb_db_get_global_setting_int64(db, "https_port", &https_port);
|
tf_ssb_db_get_global_setting_int64(db, "https_port", &https_port);
|
||||||
tf_ssb_db_get_global_setting_string(db, "out_http_port_file", out_http_port_file, sizeof(out_http_port_file));
|
|
||||||
tf_ssb_release_db_reader(ssb, db);
|
tf_ssb_release_db_reader(ssb, db);
|
||||||
if (http_port || https_port || *out_http_port_file)
|
if (http_port || https_port)
|
||||||
{
|
{
|
||||||
if (args->zip)
|
if (args->zip)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,8 @@ static int64_t s_tls_malloc_size;
|
|||||||
static int64_t s_js_malloc_size;
|
static int64_t s_js_malloc_size;
|
||||||
static int64_t s_sqlite_malloc_size;
|
static int64_t s_sqlite_malloc_size;
|
||||||
|
|
||||||
|
extern uint32_t fnv32a(const void* buffer, int length, uint32_t start);
|
||||||
|
|
||||||
static size_t _tf_mem_round_up(size_t size)
|
static size_t _tf_mem_round_up(size_t size)
|
||||||
{
|
{
|
||||||
return (size + 7) & ~7;
|
return (size + 7) & ~7;
|
||||||
@ -154,7 +156,7 @@ static void _tf_mem_summarize(void* ptr, size_t size, int frames_count, void* co
|
|||||||
{
|
{
|
||||||
summary_t* summary = user_data;
|
summary_t* summary = user_data;
|
||||||
tf_mem_allocation_t allocation = {
|
tf_mem_allocation_t allocation = {
|
||||||
.stack_hash = tf_util_fnv32a(frames, sizeof(void*) * frames_count, 0),
|
.stack_hash = fnv32a(frames, sizeof(void*) * frames_count, 0),
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.size = size,
|
.size = size,
|
||||||
.frames_count = frames_count,
|
.frames_count = frames_count,
|
||||||
|
10
src/ssb.c
@ -746,9 +746,7 @@ static bool _tf_ssb_connection_get_request_callback(
|
|||||||
*out_name = request->name;
|
*out_name = request->name;
|
||||||
}
|
}
|
||||||
request->last_active = uv_now(connection->ssb->loop);
|
request->last_active = uv_now(connection->ssb->loop);
|
||||||
if (tf_ssb_connection_is_connected(connection) && !tf_ssb_connection_is_closing(connection) && !tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)))
|
if (connection->flags & k_tf_ssb_connect_flag_one_shot)
|
||||||
{
|
|
||||||
if ((connection->flags & k_tf_ssb_connect_flag_one_shot))
|
|
||||||
{
|
{
|
||||||
uv_timer_start(&connection->activity_timer, _tf_ssb_connection_activity_timer, k_activity_timeout_ms, 0);
|
uv_timer_start(&connection->activity_timer, _tf_ssb_connection_activity_timer, k_activity_timeout_ms, 0);
|
||||||
}
|
}
|
||||||
@ -756,7 +754,6 @@ static bool _tf_ssb_connection_get_request_callback(
|
|||||||
{
|
{
|
||||||
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -802,8 +799,6 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
|
|||||||
connection->requests_count++;
|
connection->requests_count++;
|
||||||
connection->ssb->request_count++;
|
connection->ssb->request_count++;
|
||||||
}
|
}
|
||||||
if (tf_ssb_connection_is_connected(connection) && !tf_ssb_connection_is_closing(connection) && !tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)))
|
|
||||||
{
|
|
||||||
if (connection->flags & k_tf_ssb_connect_flag_one_shot)
|
if (connection->flags & k_tf_ssb_connect_flag_one_shot)
|
||||||
{
|
{
|
||||||
uv_timer_start(&connection->activity_timer, _tf_ssb_connection_activity_timer, k_activity_timeout_ms, 0);
|
uv_timer_start(&connection->activity_timer, _tf_ssb_connection_activity_timer, k_activity_timeout_ms, 0);
|
||||||
@ -812,7 +807,6 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
|
|||||||
{
|
{
|
||||||
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_update, connection);
|
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_update, connection);
|
||||||
connection->last_notified_active = now_ms;
|
connection->last_notified_active = now_ms;
|
||||||
}
|
}
|
||||||
@ -2003,7 +1997,7 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
|
|||||||
if (!connection->is_closing)
|
if (!connection->is_closing)
|
||||||
{
|
{
|
||||||
connection->is_closing = true;
|
connection->is_closing = true;
|
||||||
uv_timer_start(&connection->linger_timer, _tf_ssb_connection_linger_timer, ssb->shutting_down ? 0 : 5000, 0);
|
uv_timer_start(&connection->linger_timer, _tf_ssb_connection_linger_timer, 5000, 0);
|
||||||
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_update, connection);
|
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_update, connection);
|
||||||
}
|
}
|
||||||
if (connection->connect_callback)
|
if (connection->connect_callback)
|
||||||
|
132
src/ssb.db.c
@ -1277,7 +1277,7 @@ static int _following_compare(const void* a, const void* b)
|
|||||||
|
|
||||||
static bool _has_following_entry(const char* id, following_t** list, int count)
|
static bool _has_following_entry(const char* id, following_t** list, int count)
|
||||||
{
|
{
|
||||||
return count ? bsearch(id, list, count, sizeof(following_t*), _following_compare) != NULL : false;
|
return count ? bsearch(id, list, count, sizeof(following_t*), _following_compare) != 0 : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _add_following_entry(following_t*** list, int* count, following_t* add)
|
static bool _add_following_entry(following_t*** list, int* count, following_t* add)
|
||||||
@ -1432,26 +1432,25 @@ static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, foll
|
|||||||
static void _get_following(
|
static void _get_following(
|
||||||
tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, int depth, int max_depth, block_node_t* active_blocks, bool include_blocks)
|
tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, int depth, int max_depth, block_node_t* active_blocks, bool include_blocks)
|
||||||
{
|
{
|
||||||
int old_depth = entry->depth;
|
|
||||||
entry->depth = tf_min(depth, entry->depth);
|
entry->depth = tf_min(depth, entry->depth);
|
||||||
if (depth < max_depth && depth < old_depth)
|
if (depth < max_depth && !entry->populated && !_is_blocked_by_active_blocks(entry->id, active_blocks))
|
||||||
{
|
|
||||||
if (!_is_blocked_by_active_blocks(entry->id, active_blocks))
|
|
||||||
{
|
|
||||||
if (!entry->populated)
|
|
||||||
{
|
{
|
||||||
entry->populated = true;
|
entry->populated = true;
|
||||||
_populate_follows_and_blocks(ssb, entry, following, following_count, active_blocks, include_blocks);
|
_populate_follows_and_blocks(ssb, entry, following, following_count, active_blocks, include_blocks);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (depth < max_depth)
|
||||||
|
{
|
||||||
block_node_t blocks = { .entry = entry, .parent = active_blocks };
|
block_node_t blocks = { .entry = entry, .parent = active_blocks };
|
||||||
for (int i = 0; i < entry->following_count; i++)
|
for (int i = 0; i < entry->following_count; i++)
|
||||||
|
{
|
||||||
|
if (!_has_following_entry(entry->following[i]->id, entry->blocking, entry->blocking_count))
|
||||||
{
|
{
|
||||||
_get_following(ssb, entry->following[i], following, following_count, depth + 1, max_depth, &blocks, include_blocks);
|
_get_following(ssb, entry->following[i], following, following_count, depth + 1, max_depth, &blocks, include_blocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth, bool include_blocks)
|
tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth, bool include_blocks)
|
||||||
{
|
{
|
||||||
@ -2331,120 +2330,3 @@ bool tf_ssb_db_has_invite(sqlite3* db, const char* id)
|
|||||||
}
|
}
|
||||||
return has;
|
return has;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_db_get_identity_info_visit(const char* identity, void* user_data)
|
|
||||||
{
|
|
||||||
tf_ssb_identity_info_t* info = user_data;
|
|
||||||
info->identity = tf_resize_vec(info->identity, (info->count + 1) * sizeof(char*));
|
|
||||||
info->name = tf_resize_vec(info->name, (info->count + 1) * sizeof(char*));
|
|
||||||
char buffer[k_id_base64_len];
|
|
||||||
snprintf(buffer, sizeof(buffer), "@%s", identity);
|
|
||||||
info->identity[info->count] = tf_strdup(buffer);
|
|
||||||
info->name[info->count] = NULL;
|
|
||||||
info->count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
tf_ssb_identity_info_t* tf_ssb_db_get_identity_info(tf_ssb_t* ssb, const char* user, const char* package_owner, const char* package_name)
|
|
||||||
{
|
|
||||||
tf_ssb_identity_info_t* info = tf_malloc(sizeof(tf_ssb_identity_info_t));
|
|
||||||
*info = (tf_ssb_identity_info_t) { 0 };
|
|
||||||
|
|
||||||
char id[k_id_base64_len] = "";
|
|
||||||
if (tf_ssb_db_user_has_permission(ssb, NULL, user, "administration"))
|
|
||||||
{
|
|
||||||
if (tf_ssb_whoami(ssb, id, sizeof(id)))
|
|
||||||
{
|
|
||||||
_tf_ssb_db_get_identity_info_visit(*id == '@' ? id + 1 : id, info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tf_ssb_db_identity_visit(ssb, user, _tf_ssb_db_get_identity_info_visit, info);
|
|
||||||
|
|
||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
|
||||||
sqlite3_stmt* statement = NULL;
|
|
||||||
int result = sqlite3_prepare(db,
|
|
||||||
"SELECT author, name FROM ( "
|
|
||||||
" SELECT "
|
|
||||||
" messages.author, "
|
|
||||||
" RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, "
|
|
||||||
" messages.content ->> 'name' AS name "
|
|
||||||
" FROM messages "
|
|
||||||
" JOIN identities ON messages.author = ('@' || identities.public_key) "
|
|
||||||
" WHERE "
|
|
||||||
" (identities.user = ? OR identities.public_key = ?) AND "
|
|
||||||
" json_extract(messages.content, '$.type') = 'about' AND "
|
|
||||||
" content ->> 'about' = messages.author AND name IS NOT NULL) "
|
|
||||||
"WHERE author_rank = 1 ",
|
|
||||||
-1, &statement, NULL);
|
|
||||||
if (result == SQLITE_OK)
|
|
||||||
{
|
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, *id == '@' ? id + 1 : id, -1, NULL) == SQLITE_OK)
|
|
||||||
{
|
|
||||||
int r = SQLITE_OK;
|
|
||||||
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
|
||||||
{
|
|
||||||
const char* identity = (const char*)sqlite3_column_text(statement, 0);
|
|
||||||
const char* name = (const char*)sqlite3_column_text(statement, 1);
|
|
||||||
for (int i = 0; i < info->count; i++)
|
|
||||||
{
|
|
||||||
if (!info->name[i] && strcmp(info->identity[i], identity) == 0)
|
|
||||||
{
|
|
||||||
info->name[i] = tf_strdup(name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tf_printf("prepare failed: %s.\n", sqlite3_errmsg(db));
|
|
||||||
}
|
|
||||||
|
|
||||||
tf_ssb_db_identity_get_active(db, user, package_owner, package_name, info->active_identity, sizeof(info->active_identity));
|
|
||||||
if (!*info->active_identity && info->count)
|
|
||||||
{
|
|
||||||
snprintf(info->active_identity, sizeof(info->active_identity), "%s", info->identity[0]);
|
|
||||||
}
|
|
||||||
tf_ssb_release_db_reader(ssb, db);
|
|
||||||
|
|
||||||
size_t size = sizeof(tf_ssb_identity_info_t) + sizeof(char*) * info->count * 2;
|
|
||||||
for (int i = 0; i < info->count; i++)
|
|
||||||
{
|
|
||||||
size += strlen(info->identity[i]) + 1;
|
|
||||||
size += info->name[i] ? strlen(info->name[i]) + 1 : 0;
|
|
||||||
}
|
|
||||||
tf_ssb_identity_info_t* copy = tf_malloc(size);
|
|
||||||
*copy = *info;
|
|
||||||
|
|
||||||
copy->identity = (const char**)(copy + 1);
|
|
||||||
copy->name = (const char**)(copy + 1) + copy->count;
|
|
||||||
|
|
||||||
char* p = (char*)((const char**)(copy + 1) + copy->count * 2);
|
|
||||||
|
|
||||||
for (int i = 0; i < info->count; i++)
|
|
||||||
{
|
|
||||||
size_t length = strlen(info->identity[i]);
|
|
||||||
memcpy(p, info->identity[i], length + 1);
|
|
||||||
copy->identity[i] = p;
|
|
||||||
p += length + 1;
|
|
||||||
tf_free((void*)info->identity[i]);
|
|
||||||
|
|
||||||
if (info->name[i])
|
|
||||||
{
|
|
||||||
length = strlen(info->name[i]);
|
|
||||||
memcpy(p, info->name[i], length + 1);
|
|
||||||
copy->name[i] = p;
|
|
||||||
p += length + 1;
|
|
||||||
tf_free((void*)info->name[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
copy->name[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tf_free(info->name);
|
|
||||||
tf_free(info->identity);
|
|
||||||
tf_free(info);
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
25
src/ssb.db.h
@ -564,29 +564,4 @@ int tf_ssb_sqlite_authorizer(void* user_data, int action_code, const char* arg0,
|
|||||||
*/
|
*/
|
||||||
bool tf_ssb_db_has_invite(sqlite3* db, const char* id);
|
bool tf_ssb_db_has_invite(sqlite3* db, const char* id);
|
||||||
|
|
||||||
/**
|
|
||||||
** Identity information
|
|
||||||
*/
|
|
||||||
typedef struct _tf_ssb_identity_info_t
|
|
||||||
{
|
|
||||||
/** An array of identities. */
|
|
||||||
const char** identity;
|
|
||||||
/** A array of identities, one for each identity. */
|
|
||||||
const char** name;
|
|
||||||
/** The number of elements in both the identity and name arrays. */
|
|
||||||
int count;
|
|
||||||
/** The active identity. */
|
|
||||||
char active_identity[k_id_base64_len];
|
|
||||||
} tf_ssb_identity_info_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
** Get available identities, names, and the active identity for a user.
|
|
||||||
** @param ssb The SSB instance.
|
|
||||||
** @param user The user name.
|
|
||||||
** @param package_owner The owner of the package for which identity info is being fetched.
|
|
||||||
** @param package_name The name of the package for which identity info is being fetched.
|
|
||||||
** @return A struct of identities, names, and the active identity. Free with tf_free().
|
|
||||||
*/
|
|
||||||
tf_ssb_identity_info_t* tf_ssb_db_get_identity_info(tf_ssb_t* ssb, const char* user, const char* package_owner, const char* package_name);
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
95
src/ssb.js.c
@ -613,14 +613,87 @@ typedef struct _identity_info_work_t
|
|||||||
const char* name;
|
const char* name;
|
||||||
const char* package_owner;
|
const char* package_owner;
|
||||||
const char* package_name;
|
const char* package_name;
|
||||||
tf_ssb_identity_info_t* info;
|
int count;
|
||||||
|
char** identities;
|
||||||
|
char** names;
|
||||||
|
int result;
|
||||||
|
char active_identity[k_id_base64_len];
|
||||||
JSValue promise[2];
|
JSValue promise[2];
|
||||||
} identity_info_work_t;
|
} identity_info_work_t;
|
||||||
|
|
||||||
|
static void _tf_ssb_getIdentityInfo_visit(const char* identity, void* data)
|
||||||
|
{
|
||||||
|
identity_info_work_t* request = data;
|
||||||
|
request->identities = tf_resize_vec(request->identities, (request->count + 1) * sizeof(char*));
|
||||||
|
request->names = tf_resize_vec(request->names, (request->count + 1) * sizeof(char*));
|
||||||
|
char buffer[k_id_base64_len];
|
||||||
|
snprintf(buffer, sizeof(buffer), "@%s", identity);
|
||||||
|
request->identities[request->count] = tf_strdup(buffer);
|
||||||
|
request->names[request->count] = NULL;
|
||||||
|
request->count++;
|
||||||
|
}
|
||||||
|
|
||||||
static void _tf_ssb_getIdentityInfo_work(tf_ssb_t* ssb, void* user_data)
|
static void _tf_ssb_getIdentityInfo_work(tf_ssb_t* ssb, void* user_data)
|
||||||
{
|
{
|
||||||
identity_info_work_t* request = user_data;
|
identity_info_work_t* request = user_data;
|
||||||
request->info = tf_ssb_db_get_identity_info(ssb, request->name, request->package_owner, request->package_name);
|
char id[k_id_base64_len] = "";
|
||||||
|
if (tf_ssb_db_user_has_permission(ssb, NULL, request->name, "administration"))
|
||||||
|
{
|
||||||
|
if (tf_ssb_whoami(ssb, id, sizeof(id)))
|
||||||
|
{
|
||||||
|
_tf_ssb_getIdentityInfo_visit(*id == '@' ? id + 1 : id, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getIdentityInfo_visit, request);
|
||||||
|
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
|
sqlite3_stmt* statement = NULL;
|
||||||
|
request->result = sqlite3_prepare(db,
|
||||||
|
"SELECT author, name FROM ( "
|
||||||
|
" SELECT "
|
||||||
|
" messages.author, "
|
||||||
|
" RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, "
|
||||||
|
" messages.content ->> 'name' AS name "
|
||||||
|
" FROM messages "
|
||||||
|
" JOIN identities ON messages.author = ('@' || identities.public_key) "
|
||||||
|
" WHERE "
|
||||||
|
" (identities.user = ? OR identities.public_key = ?) AND "
|
||||||
|
" json_extract(messages.content, '$.type') = 'about' AND "
|
||||||
|
" content ->> 'about' = messages.author AND name IS NOT NULL) "
|
||||||
|
"WHERE author_rank = 1 ",
|
||||||
|
-1, &statement, NULL);
|
||||||
|
if (request->result == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, request->name, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, *id == '@' ? id + 1 : id, -1, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
int r = SQLITE_OK;
|
||||||
|
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
const char* identity = (const char*)sqlite3_column_text(statement, 0);
|
||||||
|
const char* name = (const char*)sqlite3_column_text(statement, 1);
|
||||||
|
for (int i = 0; i < request->count; i++)
|
||||||
|
{
|
||||||
|
if (!request->names[i] && strcmp(request->identities[i], identity) == 0)
|
||||||
|
{
|
||||||
|
request->names[i] = tf_strdup(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("prepare failed: %s.\n", sqlite3_errmsg(db));
|
||||||
|
}
|
||||||
|
|
||||||
|
tf_ssb_db_identity_get_active(db, request->name, request->package_owner, request->package_name, request->active_identity, sizeof(request->active_identity));
|
||||||
|
if (!*request->active_identity && request->count)
|
||||||
|
{
|
||||||
|
snprintf(request->active_identity, sizeof(request->active_identity), "%s", request->identities[0]);
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_reader(ssb, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
@ -630,20 +703,20 @@ static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void*
|
|||||||
JSValue result = JS_NewObject(context);
|
JSValue result = JS_NewObject(context);
|
||||||
|
|
||||||
JSValue identities = JS_NewArray(context);
|
JSValue identities = JS_NewArray(context);
|
||||||
for (int i = 0; i < request->info->count; i++)
|
for (int i = 0; i < request->count; i++)
|
||||||
{
|
{
|
||||||
JS_SetPropertyUint32(context, identities, i, JS_NewString(context, request->info->identity[i]));
|
JS_SetPropertyUint32(context, identities, i, JS_NewString(context, request->identities[i]));
|
||||||
}
|
}
|
||||||
JS_SetPropertyStr(context, result, "identities", identities);
|
JS_SetPropertyStr(context, result, "identities", identities);
|
||||||
|
|
||||||
JSValue names = JS_NewObject(context);
|
JSValue names = JS_NewObject(context);
|
||||||
for (int i = 0; i < request->info->count; i++)
|
for (int i = 0; i < request->count; i++)
|
||||||
{
|
{
|
||||||
JS_SetPropertyStr(context, names, request->info->identity[i], JS_NewString(context, request->info->name[i] ? request->info->name[i] : request->info->identity[i]));
|
JS_SetPropertyStr(context, names, request->identities[i], JS_NewString(context, request->names[i] ? request->names[i] : request->identities[i]));
|
||||||
}
|
}
|
||||||
JS_SetPropertyStr(context, result, "names", names);
|
JS_SetPropertyStr(context, result, "names", names);
|
||||||
|
|
||||||
JS_SetPropertyStr(context, result, "identity", JS_NewString(context, request->info->active_identity));
|
JS_SetPropertyStr(context, result, "identity", JS_NewString(context, request->active_identity));
|
||||||
|
|
||||||
JSValue error = JS_Call(context, request->promise[0], JS_UNDEFINED, 1, &result);
|
JSValue error = JS_Call(context, request->promise[0], JS_UNDEFINED, 1, &result);
|
||||||
tf_util_report_error(context, error);
|
tf_util_report_error(context, error);
|
||||||
@ -652,10 +725,16 @@ static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void*
|
|||||||
JS_FreeValue(context, request->promise[0]);
|
JS_FreeValue(context, request->promise[0]);
|
||||||
JS_FreeValue(context, request->promise[1]);
|
JS_FreeValue(context, request->promise[1]);
|
||||||
|
|
||||||
|
for (int i = 0; i < request->count; i++)
|
||||||
|
{
|
||||||
|
tf_free(request->identities[i]);
|
||||||
|
tf_free(request->names[i]);
|
||||||
|
}
|
||||||
|
tf_free(request->identities);
|
||||||
|
tf_free(request->names);
|
||||||
tf_free((void*)request->name);
|
tf_free((void*)request->name);
|
||||||
tf_free((void*)request->package_owner);
|
tf_free((void*)request->package_owner);
|
||||||
tf_free((void*)request->package_name);
|
tf_free((void*)request->package_name);
|
||||||
tf_free(request->info);
|
|
||||||
tf_free(request);
|
tf_free(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,19 +83,6 @@ static void _tf_ssb_rpc_blobs_get_after_work(tf_ssb_connection_t* connection, in
|
|||||||
tf_free(work);
|
tf_free(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_blobs_get_callback(tf_ssb_connection_t* connection, bool skip, void* user_data)
|
|
||||||
{
|
|
||||||
blobs_get_work_t* work = user_data;
|
|
||||||
if (!skip)
|
|
||||||
{
|
|
||||||
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_blobs_get_work, _tf_ssb_rpc_blobs_get_after_work, work);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_tf_ssb_rpc_blobs_get_after_work(connection, -1, work);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
if (flags & k_ssb_rpc_flag_end_error)
|
if (flags & k_ssb_rpc_flag_end_error)
|
||||||
@ -135,7 +122,7 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
.request_number = request_number,
|
.request_number = request_number,
|
||||||
};
|
};
|
||||||
snprintf(work->id, sizeof(work->id), "%s", id);
|
snprintf(work->id, sizeof(work->id), "%s", id);
|
||||||
tf_ssb_connection_schedule_idle(connection, id, _tf_ssb_blobs_get_callback, work);
|
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_blobs_get_work, _tf_ssb_rpc_blobs_get_after_work, work);
|
||||||
|
|
||||||
JS_FreeCString(context, id);
|
JS_FreeCString(context, id);
|
||||||
JS_FreeValue(context, arg);
|
JS_FreeValue(context, arg);
|
||||||
@ -593,7 +580,6 @@ static void _tf_ssb_rpc_connection_blobs_get_callback(
|
|||||||
bool stored = true;
|
bool stored = true;
|
||||||
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json | k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error, -request_number, NULL,
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json | k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error, -request_number, NULL,
|
||||||
(const uint8_t*)(stored ? "true" : "false"), strlen(stored ? "true" : "false"), NULL, NULL, NULL);
|
(const uint8_t*)(stored ? "true" : "false"), strlen(stored ? "true" : "false"), NULL, NULL, NULL);
|
||||||
tf_ssb_connection_remove_request(connection, -request_number);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,23 +1101,6 @@ static void _tf_ssb_rpc_ebt_replicate_resend_clock(tf_ssb_connection_t* connecti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_ebt_schedule_send_clock(tf_ssb_connection_t* connection)
|
|
||||||
{
|
|
||||||
tf_ssb_ebt_t* ebt = tf_ssb_connection_get_ebt(connection);
|
|
||||||
int pending = tf_ssb_ebt_get_send_clock_pending(ebt) + 1;
|
|
||||||
tf_ssb_ebt_set_send_clock_pending(ebt, pending);
|
|
||||||
if (pending == 1)
|
|
||||||
{
|
|
||||||
resend_clock_t* resend = tf_malloc(sizeof(resend_clock_t));
|
|
||||||
*resend = (resend_clock_t) {
|
|
||||||
.connection = connection,
|
|
||||||
.request_number = -tf_ssb_connection_get_ebt_request_number(connection),
|
|
||||||
.pending = pending,
|
|
||||||
};
|
|
||||||
tf_ssb_connection_schedule_idle(connection, "ebt.clock", _tf_ssb_rpc_ebt_replicate_resend_clock, resend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
@ -1139,7 +1108,6 @@ static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t f
|
|||||||
if (_is_error(context, args))
|
if (_is_error(context, args))
|
||||||
{
|
{
|
||||||
/* TODO: Send createHistoryStream. */
|
/* TODO: Send createHistoryStream. */
|
||||||
tf_ssb_connection_set_ebt_request_number(connection, 0);
|
|
||||||
tf_ssb_connection_remove_request(connection, -request_number);
|
tf_ssb_connection_remove_request(connection, -request_number);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1172,7 +1140,18 @@ static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t f
|
|||||||
|
|
||||||
if (resend_clock && tf_ssb_connection_is_connected(connection) && !tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)) && !tf_ssb_connection_is_closing(connection))
|
if (resend_clock && tf_ssb_connection_is_connected(connection) && !tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)) && !tf_ssb_connection_is_closing(connection))
|
||||||
{
|
{
|
||||||
_tf_ssb_rpc_ebt_schedule_send_clock(connection);
|
int pending = tf_ssb_ebt_get_send_clock_pending(ebt) + 1;
|
||||||
|
tf_ssb_ebt_set_send_clock_pending(ebt, pending);
|
||||||
|
if (pending == 1)
|
||||||
|
{
|
||||||
|
resend_clock_t* resend = tf_malloc(sizeof(resend_clock_t));
|
||||||
|
*resend = (resend_clock_t) {
|
||||||
|
.connection = connection,
|
||||||
|
.request_number = request_number,
|
||||||
|
.pending = pending,
|
||||||
|
};
|
||||||
|
tf_ssb_connection_schedule_idle(connection, "ebt.clock", _tf_ssb_rpc_ebt_replicate_resend_clock, resend);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
JS_FreeValue(context, name);
|
JS_FreeValue(context, name);
|
||||||
JS_FreeValue(context, author);
|
JS_FreeValue(context, author);
|
||||||
@ -1876,25 +1855,10 @@ static void _tf_ssb_rpc_invite_use(tf_ssb_connection_t* connection, uint8_t flag
|
|||||||
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_invite_use_work, _tf_ssb_rpc_invite_use_after_work, work);
|
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_invite_use_work, _tf_ssb_rpc_invite_use_after_work, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_message_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
|
||||||
{
|
|
||||||
tf_ssb_connection_t* connections[256];
|
|
||||||
int count = tf_ssb_get_connections(ssb, connections, tf_countof(connections));
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
tf_ssb_connection_t* connection = connections[i];
|
|
||||||
if (tf_ssb_connection_is_connected(connection) && !tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)) && !tf_ssb_connection_is_closing(connection))
|
|
||||||
{
|
|
||||||
_tf_ssb_rpc_ebt_schedule_send_clock(connections[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
||||||
{
|
{
|
||||||
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
|
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
|
||||||
tf_ssb_add_broadcasts_changed_callback(ssb, _tf_ssb_rpc_broadcasts_changed_callback, NULL, NULL);
|
tf_ssb_add_broadcasts_changed_callback(ssb, _tf_ssb_rpc_broadcasts_changed_callback, NULL, NULL);
|
||||||
tf_ssb_add_message_added_callback(ssb, _tf_ssb_rpc_message_added_callback, NULL, NULL);
|
|
||||||
tf_ssb_add_rpc_callback(ssb, "gossip.ping", _tf_ssb_rpc_gossip_ping, NULL, NULL); /* DUPLEX */
|
tf_ssb_add_rpc_callback(ssb, "gossip.ping", _tf_ssb_rpc_gossip_ping, NULL, NULL); /* DUPLEX */
|
||||||
tf_ssb_add_rpc_callback(ssb, "blobs.get", _tf_ssb_rpc_blobs_get, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, "blobs.get", _tf_ssb_rpc_blobs_get, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, "blobs.has", _tf_ssb_rpc_blobs_has, NULL, NULL); /* ASYNC */
|
tf_ssb_add_rpc_callback(ssb, "blobs.has", _tf_ssb_rpc_blobs_has, NULL, NULL); /* ASYNC */
|
||||||
|
29
src/task.c
@ -1,6 +1,5 @@
|
|||||||
#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"
|
||||||
@ -164,7 +163,6 @@ typedef struct _tf_task_t
|
|||||||
|
|
||||||
promise_stack_t* _promise_stacks;
|
promise_stack_t* _promise_stacks;
|
||||||
int _promise_stack_count;
|
int _promise_stack_count;
|
||||||
bool _promise_stack_debug;
|
|
||||||
|
|
||||||
timeout_t* timeouts;
|
timeout_t* timeouts;
|
||||||
|
|
||||||
@ -1252,8 +1250,6 @@ static void _add_promise_stack(tf_task_t* task, uint32_t hash, const char* stack
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _remove_promise_stack(tf_task_t* task, uint32_t hash)
|
static void _remove_promise_stack(tf_task_t* task, uint32_t hash)
|
||||||
{
|
|
||||||
if (task->_promise_stack_debug)
|
|
||||||
{
|
{
|
||||||
promise_stack_t* found = bsearch(&hash, task->_promise_stacks, task->_promise_stack_count, sizeof(promise_stack_t), _promise_stack_compare);
|
promise_stack_t* found = bsearch(&hash, task->_promise_stacks, task->_promise_stack_count, sizeof(promise_stack_t), _promise_stack_compare);
|
||||||
if (found)
|
if (found)
|
||||||
@ -1261,7 +1257,6 @@ static void _remove_promise_stack(tf_task_t* task, uint32_t hash)
|
|||||||
found->count--;
|
found->count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_task_free_promise(tf_task_t* task, promiseid_t id)
|
static void _tf_task_free_promise(tf_task_t* task, promiseid_t id)
|
||||||
{
|
{
|
||||||
@ -1275,26 +1270,33 @@ static void _tf_task_free_promise(tf_task_t* task, promiseid_t id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue tf_task_allocate_promise(tf_task_t* task, promiseid_t* out_promise)
|
uint32_t fnv32a(const void* buffer, int length, uint32_t start)
|
||||||
{
|
{
|
||||||
uint32_t stack_hash = 0;
|
uint32_t result = 0x811c9dc5;
|
||||||
if (task->_promise_stack_debug)
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
result ^= ((const uint8_t*)buffer)[i];
|
||||||
|
result += (result << 1) + (result << 4) + (result << 7) + (result << 8) + (result << 24);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue tf_task_allocate_promise(tf_task_t* task, promiseid_t* out_promise)
|
||||||
{
|
{
|
||||||
JSValue error = JS_ThrowInternalError(task->_context, "promise callstack");
|
JSValue error = JS_ThrowInternalError(task->_context, "promise callstack");
|
||||||
JSValue exception = JS_GetException(task->_context);
|
JSValue exception = JS_GetException(task->_context);
|
||||||
JSValue stack_value = JS_GetPropertyStr(task->_context, exception, "stack");
|
JSValue stack_value = JS_GetPropertyStr(task->_context, exception, "stack");
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
const char* stack = JS_ToCStringLen(task->_context, &length, stack_value);
|
const char* stack = JS_ToCStringLen(task->_context, &length, stack_value);
|
||||||
stack_hash = tf_util_fnv32a((const void*)stack, (int)length, 0);
|
uint32_t stack_hash = fnv32a((const void*)stack, (int)length, 0);
|
||||||
void* buffer[32];
|
void* buffer[32];
|
||||||
int count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer));
|
int count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer));
|
||||||
stack_hash = tf_util_fnv32a((const void*)buffer, sizeof(void*) * count, stack_hash);
|
stack_hash = fnv32a((const void*)buffer, sizeof(void*) * count, stack_hash);
|
||||||
_add_promise_stack(task, stack_hash, stack, buffer, count);
|
_add_promise_stack(task, stack_hash, stack, buffer, count);
|
||||||
JS_FreeCString(task->_context, stack);
|
JS_FreeCString(task->_context, stack);
|
||||||
JS_FreeValue(task->_context, stack_value);
|
JS_FreeValue(task->_context, stack_value);
|
||||||
JS_FreeValue(task->_context, exception);
|
JS_FreeValue(task->_context, exception);
|
||||||
JS_FreeValue(task->_context, error);
|
JS_FreeValue(task->_context, error);
|
||||||
}
|
|
||||||
|
|
||||||
promiseid_t promiseId;
|
promiseid_t promiseId;
|
||||||
do
|
do
|
||||||
@ -1589,10 +1591,6 @@ tf_task_t* tf_task_create()
|
|||||||
*task = (tf_task_t) { 0 };
|
*task = (tf_task_t) { 0 };
|
||||||
++_count;
|
++_count;
|
||||||
|
|
||||||
char buffer[8] = { 0 };
|
|
||||||
size_t buffer_size = sizeof(buffer);
|
|
||||||
task->_promise_stack_debug = uv_os_getenv("TF_PROMISE_DEBUG", buffer, &buffer_size) == 0 && strcmp(buffer, "1") == 0;
|
|
||||||
|
|
||||||
JSMallocFunctions funcs = { 0 };
|
JSMallocFunctions funcs = { 0 };
|
||||||
tf_get_js_malloc_functions(&funcs);
|
tf_get_js_malloc_functions(&funcs);
|
||||||
task->_runtime = JS_NewRuntime2(&funcs, NULL);
|
task->_runtime = JS_NewRuntime2(&funcs, NULL);
|
||||||
@ -1699,7 +1697,6 @@ 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)
|
||||||
|
@ -683,14 +683,3 @@ bool tf_util_is_mobile()
|
|||||||
{
|
{
|
||||||
return TF_IS_MOBILE != 0;
|
return TF_IS_MOBILE != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tf_util_fnv32a(const void* buffer, int length, uint32_t start)
|
|
||||||
{
|
|
||||||
uint32_t result = 0x811c9dc5;
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
result ^= ((const uint8_t*)buffer)[i];
|
|
||||||
result += (result << 1) + (result << 4) + (result << 7) + (result << 8) + (result << 24);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
@ -224,13 +224,4 @@ void tf_util_document_settings(const char* line_prefix);
|
|||||||
*/
|
*/
|
||||||
bool tf_util_is_mobile();
|
bool tf_util_is_mobile();
|
||||||
|
|
||||||
/**
|
|
||||||
** Compute a 32-bit hash of a buffer.
|
|
||||||
** @param buffer The data.
|
|
||||||
** @param length The size of the buffer in bytes.
|
|
||||||
** @param start The hash seed.
|
|
||||||
** @return The computed hash.
|
|
||||||
*/
|
|
||||||
uint32_t tf_util_fnv32a(const void* buffer, int length, uint32_t start);
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#define VERSION_NUMBER "0.0.29-wip"
|
#define VERSION_NUMBER "0.0.28-wip"
|
||||||
#define VERSION_NAME "This program kills fascists."
|
#define VERSION_NAME "This program kills fascists."
|
||||||
|
@ -25,7 +25,6 @@ def fix_title(entry):
|
|||||||
return entry.title.split('\n')[0]
|
return entry.title.split('\n')[0]
|
||||||
|
|
||||||
def get_entries():
|
def get_entries():
|
||||||
seen = set()
|
|
||||||
results = []
|
results = []
|
||||||
for name, url in k_feeds.items():
|
for name, url in k_feeds.items():
|
||||||
feed = feedparser.parse(url)
|
feed = feedparser.parse(url)
|
||||||
@ -42,12 +41,8 @@ def get_entries():
|
|||||||
continue
|
continue
|
||||||
if entry.summary.startswith('<a href='):
|
if entry.summary.startswith('<a href='):
|
||||||
for m in re.findall(r'<a href="(.*?)">.*?</a>$\s*^([^\n]+)$', entry.summary, re.S | re.M):
|
for m in re.findall(r'<a href="(.*?)">.*?</a>$\s*^([^\n]+)$', entry.summary, re.S | re.M):
|
||||||
if not m[0] in seen:
|
|
||||||
seen.add(m[0])
|
|
||||||
results.append((time.mktime(entry.get('updated_parsed')), name, m[0], m[1]))
|
results.append((time.mktime(entry.get('updated_parsed')), name, m[0], m[1]))
|
||||||
else:
|
else:
|
||||||
if not entry.link in seen:
|
|
||||||
seen.add(entry.link)
|
|
||||||
results.append((time.mktime(entry.get('updated_parsed')), name, entry.link, entry.title.split('\n')[0]))
|
results.append((time.mktime(entry.get('updated_parsed')), name, entry.link, entry.title.split('\n')[0]))
|
||||||
results.sort()
|
results.sort()
|
||||||
results.reverse()
|
results.reverse()
|
||||||
|