Compare commits
42 Commits
899605c860
...
v0.0.32
Author | SHA1 | Date | |
---|---|---|---|
94b7703ca9 | |||
a391dd1316 | |||
b6ba5211b7 | |||
8e8e130045 | |||
1f40bc1a0f | |||
5437212222 | |||
a8ab845cd2 | |||
8cee6dc98b | |||
70c2b73414 | |||
98013c4422 | |||
e9e22b762d | |||
620db19936 | |||
94a79dd62c | |||
b56c3efde0 | |||
066827f8f1 | |||
c3b65d9cd8 | |||
a15b916b06 | |||
31d0a5c233 | |||
140179e80a | |||
53cba2d7e4 | |||
e54312d3b8 | |||
cadc27b7b5 | |||
388b829ec1 | |||
67861f0f33 | |||
a1f1eb34d5 | |||
2a6789063e | |||
cbf1273a55 | |||
8143a23ced | |||
3c17810747 | |||
bea7a2e9ed | |||
2f0a2ac6b0 | |||
18908b6b56 | |||
b135a210cc | |||
3a2a829940 | |||
e56dd2dd2d | |||
3f41a48bc7 | |||
65ed53281a | |||
1121557a2e | |||
d4a7b86ee7 | |||
626c18b04e | |||
bfa97ed7c7 | |||
deae4d5367 |
14
GNUmakefile
14
GNUmakefile
@@ -18,7 +18,7 @@ MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
VERSION_CODE := 38
|
||||
VERSION_CODE_IOS := 14
|
||||
VERSION_NUMBER := 0.0.32-wip
|
||||
VERSION_NUMBER := 0.0.32
|
||||
VERSION_NAME := This program kills fascists.
|
||||
|
||||
IPHONEOS_VERSION_MIN=14.0
|
||||
@@ -1483,6 +1483,18 @@ help: ## Display this help message.
|
||||
.PHONY: help
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
docs: debug
|
||||
docs: ## Build HTML docs.
|
||||
@echo '# CLI Usage\n' > docs/usage.md
|
||||
@echo "## tildefriends -h" >> docs/usage.md
|
||||
@echo '\n```' >> docs/usage.md
|
||||
@out/debug/tildefriends -h >> docs/usage.md
|
||||
@echo '```' >> docs/usage.md
|
||||
@for command in $$(out/debug/tildefriends -h | grep -Po '[A-Za-z_]*(?= - )'); do
|
||||
@ echo "\n## tildefriends $$command -h" >> docs/usage.md
|
||||
@ echo '\n```' >> docs/usage.md
|
||||
@ out/debug/tildefriends $$command -h >> docs/usage.md
|
||||
@ echo '```' >> docs/usage.md
|
||||
@done
|
||||
@doxygen
|
||||
.PHONY: docs
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"type": "tildefriends-app",
|
||||
"emoji": "💡",
|
||||
"previous": "&ckE7T/dt9f1xV8jNSgXVcXYkAzMhU9689MRQbhOi9Wo=.sha256"
|
||||
"previous": "&eN6DNPpQUNhGvxneLuLPgsOXR6qyFZ7u+MAz0b4fa7k=.sha256"
|
||||
}
|
||||
|
@@ -5,7 +5,10 @@ async function main() {
|
||||
}
|
||||
|
||||
tfrpc.register(async function complete() {
|
||||
if ((await core.globalSettingsGet('index')) == '/~core/intro/') {
|
||||
if (
|
||||
core.user?.credentials?.permissions?.administration &&
|
||||
(await core.globalSettingsGet('index')) == '/~core/intro/'
|
||||
) {
|
||||
return await core.globalSettingsSet('index', '/~core/ssb/');
|
||||
}
|
||||
});
|
||||
|
@@ -82,7 +82,7 @@
|
||||
<div class="w3-container w3-large w3-left-align">
|
||||
<p>
|
||||
Secure Scuttlebutt is a social network whose technical operation
|
||||
attempts to mirrors human social interaction.
|
||||
attempts to mirror human social interaction.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"type": "tildefriends-app",
|
||||
"emoji": "🦀",
|
||||
"previous": "&i6mkfmh4sW8PpILznWL8VxDzI3MX6V5OJWDs47Qxias=.sha256"
|
||||
"previous": "&Rn4Eg5ev5qhrYRnwxPB0DiEwO7VdGMDGp7tL/W7bRZo=.sha256"
|
||||
}
|
||||
|
@@ -106,6 +106,15 @@ tfrpc.register(async function sync() {
|
||||
tfrpc.register(async function url() {
|
||||
return core.url;
|
||||
});
|
||||
tfrpc.register(async function globalSettingsGet(key) {
|
||||
return core.globalSettingsGet(key);
|
||||
});
|
||||
tfrpc.register(async function globalSettingsSet(key, value) {
|
||||
return core.globalSettingsSet(key, value);
|
||||
});
|
||||
tfrpc.register(function isAdministrator() {
|
||||
return core.user?.credentials?.permissions?.administration;
|
||||
});
|
||||
|
||||
core.register('onBroadcastsChanged', async function () {
|
||||
await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts());
|
||||
|
@@ -308,11 +308,7 @@ class TfElement extends LitElement {
|
||||
ranges.push([i, Math.min(i + k_chunk_size, latest), true]);
|
||||
}
|
||||
for (let i = cache.range[0]; i >= 0; i -= k_chunk_size) {
|
||||
ranges.push([
|
||||
Math.max(i - k_chunk_size, 0),
|
||||
Math.min(cache.range[0], i + k_chunk_size),
|
||||
false,
|
||||
]);
|
||||
ranges.push([Math.max(i - k_chunk_size, 0), i, false]);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < latest; i += k_chunk_size) {
|
||||
@@ -328,7 +324,7 @@ class TfElement extends LitElement {
|
||||
messages.rowid > ?1 AND
|
||||
messages.rowid <= ?2 AND
|
||||
json(messages.content) LIKE '"%'
|
||||
ORDER BY sequence DESC
|
||||
ORDER BY messages.rowid DESC
|
||||
`,
|
||||
[range[0], range[1]]
|
||||
);
|
||||
@@ -354,10 +350,26 @@ class TfElement extends LitElement {
|
||||
return [cache.latest, cache.messages];
|
||||
}
|
||||
|
||||
async query_timed(sql, args) {
|
||||
let start = new Date();
|
||||
let result = await tfrpc.rpc.query(sql, args);
|
||||
let end = new Date();
|
||||
console.log((end - start) / 1000, sql);
|
||||
return result;
|
||||
}
|
||||
|
||||
async load_channels_latest(following) {
|
||||
let start_time = new Date();
|
||||
let latest_private = this.get_latest_private(following);
|
||||
let channels = await tfrpc.rpc.query(
|
||||
const k_args = [
|
||||
JSON.stringify(this.channels),
|
||||
JSON.stringify(following),
|
||||
'"' + this.whoami.replace('"', '""') + '"',
|
||||
this.whoami,
|
||||
];
|
||||
let channels = (
|
||||
await Promise.all([
|
||||
this.query_timed(
|
||||
`
|
||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
|
||||
@@ -367,7 +379,11 @@ class TfElement extends LitElement {
|
||||
messages.content ->> 'root' IS NULL AND
|
||||
messages.author != ?4
|
||||
GROUP by channel
|
||||
UNION
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
`
|
||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN messages_refs ON messages.id = messages_refs.message
|
||||
JOIN json_each(?1) AS channels ON messages_refs.ref = '#' || channels.value
|
||||
@@ -377,32 +393,41 @@ class TfElement extends LitElement {
|
||||
messages.content ->> 'root' IS NULL AND
|
||||
messages.author != ?4
|
||||
GROUP by channel
|
||||
UNION
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
`
|
||||
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||
WHERE
|
||||
messages.content ->> 'type' = 'post' AND
|
||||
messages.content ->> 'root' IS NULL AND
|
||||
messages.author != ?4
|
||||
UNION
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
`
|
||||
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
|
||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||
WHERE messages.author != ?4
|
||||
UNION
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
`
|
||||
SELECT '👍' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||
WHERE
|
||||
messages.content ->> 'type' = 'vote' AND
|
||||
messages.author != ?4
|
||||
`,
|
||||
[
|
||||
JSON.stringify(this.channels),
|
||||
JSON.stringify(following),
|
||||
'"' + this.whoami.replace('"', '""') + '"',
|
||||
this.whoami,
|
||||
]
|
||||
);
|
||||
k_args
|
||||
),
|
||||
])
|
||||
).flat();
|
||||
let latest = {};
|
||||
for (let row of channels) {
|
||||
if (!latest[row.channel]) {
|
||||
|
@@ -632,8 +632,10 @@ class TfMessageElement extends LitElement {
|
||||
}
|
||||
|
||||
allow_unread() {
|
||||
return;
|
||||
!this.channel.startsWith('@') && !this.channel.startsWith('%');
|
||||
return (
|
||||
this.channel == '@' ||
|
||||
(!this.channel.startsWith('@') && !this.channel.startsWith('%'))
|
||||
);
|
||||
}
|
||||
|
||||
render_unread_icon() {
|
||||
|
@@ -14,6 +14,7 @@ class TfNewsElement extends LitElement {
|
||||
channel: {type: String},
|
||||
channel_unread: {type: Number},
|
||||
recent_reactions: {type: Array},
|
||||
hash: {type: String},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -193,17 +194,23 @@ class TfNewsElement extends LitElement {
|
||||
return result;
|
||||
}
|
||||
|
||||
unread_allowed() {
|
||||
return !this.hash?.startsWith('#%') && !this.hash?.startsWith('#@');
|
||||
}
|
||||
|
||||
load_and_render(messages) {
|
||||
let messages_by_id = this.process_messages(messages);
|
||||
let final_messages = this.group_following(
|
||||
this.finalize_messages(messages_by_id)
|
||||
);
|
||||
let unread_rowid = -1;
|
||||
if (this.unread_allowed()) {
|
||||
for (let message of final_messages) {
|
||||
if (message.rowid >= this.channel_unread) {
|
||||
unread_rowid = message.rowid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return html`
|
||||
<div>
|
||||
${repeat(
|
||||
|
@@ -177,10 +177,10 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
WHERE messages.content ->> 'channel' = ?4
|
||||
UNION
|
||||
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||
FROM messages_fts(?5)
|
||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||
FROM messages_refs
|
||||
JOIN messages ON messages.id = messages_refs.message
|
||||
JOIN json_each(?1) AS following ON messages.author = following.value
|
||||
JOIN json_tree(messages.content, '$.mentions') AS mention ON mention.value = '#' || ?4
|
||||
WHERE messages_refs.ref = '#' || ?4
|
||||
)
|
||||
SELECT TRUE AS is_primary, all_news.* FROM all_news
|
||||
WHERE (?2 IS NULL OR all_news.timestamp >= ?2) AND all_news.timestamp < ?3
|
||||
@@ -191,7 +191,6 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
start_time,
|
||||
end_time,
|
||||
this.hash.substring(2),
|
||||
'"#' + this.hash.substring(2).replace('"', '""') + '"',
|
||||
]
|
||||
);
|
||||
let t1 = new Date();
|
||||
@@ -209,7 +208,7 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
WHERE
|
||||
(?2 IS NULL OR (messages.timestamp >= ?2)) AND messages.timestamp < ?3 AND
|
||||
json(messages.content) LIKE '"%'
|
||||
ORDER BY messages.sequence DESC LIMIT 20
|
||||
ORDER BY messages.rowid DESC LIMIT 20
|
||||
`,
|
||||
[JSON.stringify(this.private_messages), start_time, end_time]
|
||||
);
|
||||
@@ -276,6 +275,13 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
];
|
||||
}
|
||||
|
||||
unread_allowed() {
|
||||
return (
|
||||
this.hash == '#@' ||
|
||||
(!this.hash.startsWith('#%') && !this.hash.startsWith('#@'))
|
||||
);
|
||||
}
|
||||
|
||||
async load_more() {
|
||||
this.loading++;
|
||||
this.loading_canceled = false;
|
||||
@@ -425,9 +431,16 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
if (!this.hash.startsWith('#%')) {
|
||||
more = html`
|
||||
<p>
|
||||
<button class="w3-button w3-theme-d1" @click=${this.mark_all_read}>
|
||||
${this.unread_allowed()
|
||||
? html`
|
||||
<button
|
||||
class="w3-button w3-theme-d1"
|
||||
@click=${this.mark_all_read}
|
||||
>
|
||||
Mark All Read
|
||||
</button>
|
||||
`
|
||||
: undefined}
|
||||
<button
|
||||
?disabled=${this.loading}
|
||||
class="w3-button w3-theme-d1"
|
||||
@@ -459,7 +472,7 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
`;
|
||||
}
|
||||
return cache(html`
|
||||
${!this.hash.startsWith('#%')
|
||||
${this.unread_allowed()
|
||||
? html`<button
|
||||
class="w3-button w3-theme-d1"
|
||||
@click=${this.mark_all_read}
|
||||
@@ -475,6 +488,7 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
.following=${this.following}
|
||||
.drafts=${this.drafts}
|
||||
.expanded=${this.expanded}
|
||||
hash=${this.hash}
|
||||
channel=${this.channel()}
|
||||
channel_unread=${this.channels_unread?.[this.channel()]}
|
||||
.recent_reactions=${this.recent_reactions}
|
||||
|
@@ -25,6 +25,7 @@ class TfTabNewsElement extends LitElement {
|
||||
connections: {type: Array},
|
||||
private_messages: {type: Array},
|
||||
recent_reactions: {type: Array},
|
||||
peer_exchange: {type: Boolean},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -48,6 +49,7 @@ class TfTabNewsElement extends LitElement {
|
||||
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
|
||||
self.drafts = JSON.parse(d || '{}');
|
||||
});
|
||||
this.check_peer_exchange();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -60,6 +62,14 @@ class TfTabNewsElement extends LitElement {
|
||||
document.body.removeEventListener('keypress', this.on_keypress.bind(this));
|
||||
}
|
||||
|
||||
async check_peer_exchange() {
|
||||
if (await tfrpc.rpc.isAdministrator()) {
|
||||
this.peer_exchange = await tfrpc.rpc.globalSettingsGet('peer_exchange');
|
||||
} else {
|
||||
this.peer_exchange = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
load_latest() {
|
||||
let news = this.shadowRoot?.getElementById('news');
|
||||
if (news) {
|
||||
@@ -164,6 +174,15 @@ class TfTabNewsElement extends LitElement {
|
||||
.map((x) => x[0]);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
tfrpc.rpc.sync();
|
||||
}
|
||||
|
||||
async enable_peer_exchange() {
|
||||
await tfrpc.rpc.globalSettingsSet('peer_exchange', true);
|
||||
await this.check_peer_exchange();
|
||||
}
|
||||
|
||||
render_sidebar() {
|
||||
return html`
|
||||
<div
|
||||
@@ -240,6 +259,26 @@ class TfTabNewsElement extends LitElement {
|
||||
<a class="w3-bar-item w3-theme-d2 w3-button" href="#connections">
|
||||
<h4 style="margin: 0">Connections</h4>
|
||||
</a>
|
||||
${this.connections?.filter((x) => x.id)?.length == 0
|
||||
? html`
|
||||
<button
|
||||
class=${'w3-bar-item w3-button' +
|
||||
(this.connections?.some((x) => x.flags.one_shot)
|
||||
? ' w3-spin'
|
||||
: '')}
|
||||
@click=${this.refresh}
|
||||
>
|
||||
↻ Sync now
|
||||
</button>
|
||||
<button
|
||||
class=${'w3-bar-item w3-button' +
|
||||
(this.peer_exchange !== false ? ' w3-hide' : '')}
|
||||
@click=${this.enable_peer_exchange}
|
||||
>
|
||||
Enable peer exchange
|
||||
</button>
|
||||
`
|
||||
: undefined}
|
||||
${this.connections
|
||||
.filter((x) => x.id)
|
||||
.map(
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"type": "tildefriends-app",
|
||||
"emoji": "👋",
|
||||
"previous": "&1o8MrBHfH42NnO+ruajwCmW/DUCb+IT1qtnAZI/agyo=.sha256"
|
||||
"previous": "&fY3YUKPuH/wqOgKPVNJu1vWEHCXf5fToL2qiVXMRmxc=.sha256"
|
||||
}
|
||||
|
1521
apps/welcome/hermietildefriends.svg
Normal file
1521
apps/welcome/hermietildefriends.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 86 KiB |
@@ -28,23 +28,12 @@
|
||||
<b>😎 Tilde Friends</b>
|
||||
</h1>
|
||||
<h1 class="w3-xxlarge w3-text-green">
|
||||
<b
|
||||
>the Secure Scuttlebutt decentralized social network client that's
|
||||
<i>fancy🎩</i></b
|
||||
>
|
||||
<b>a Secure Scuttlebutt decentralized social network client</b>
|
||||
</h1>
|
||||
<p>
|
||||
In addition to participating in Secure Scuttlebutt, Tilde Friends is
|
||||
a platform for building, running, and sharing applications.
|
||||
</p>
|
||||
<p>
|
||||
Available for lots of devices:
|
||||
<i class="fa-brands fa-linux w3-xlarge"></i>
|
||||
<i class="fa-brands fa-android w3-xlarge"></i>
|
||||
<i class="fa-brands fa-apple w3-xlarge"></i>
|
||||
<i class="fa fa-mobile-screen w3-xlarge"></i>
|
||||
<i class="fa-brands fa-windows w3-xlarge"></i>
|
||||
</p>
|
||||
<a
|
||||
class="w3-button w3-blue w3-padding-large"
|
||||
href="https://www.tildefriends.net/~core/ssb/"
|
||||
@@ -52,7 +41,7 @@
|
||||
>
|
||||
<a
|
||||
class="w3-button w3-black w3-padding-large"
|
||||
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||
href="https://dev.tildefriends.net/cory/tildefriends/releases/latest"
|
||||
><i class="fa fa-download"></i> Download</a
|
||||
>
|
||||
<a
|
||||
@@ -70,35 +59,6 @@
|
||||
href="https://www.tildefriends.net/~cory/tildeblog/"
|
||||
><i class="fa fa-solid fa-square-rss"></i> Blog</a
|
||||
>
|
||||
<p>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
|
||||
><img src="f-droid.svg" style="height: 2em; margin: 0" /> Get it
|
||||
on F-Droid</a
|
||||
>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
|
||||
>
|
||||
<img src="appimage.svg" style="height: 2em; margin: 0" />
|
||||
Get Linux 64-bit AppImage
|
||||
</a>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
|
||||
>
|
||||
<img src="googleplay.svg" style="height: 2em; margin: 0" />
|
||||
Get it on Google Play (Open Testing)
|
||||
</a>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://testflight.apple.com/join/tXxgtSpE"
|
||||
>
|
||||
<img src="ios.svg" style="height: 2em; margin: 0" />
|
||||
Get it on iOS (TestFlight)
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="w3-col l4 m6">
|
||||
<img src="tildefriends.png" class="w3-image w3-right w3-hide-small" />
|
||||
@@ -123,8 +83,100 @@
|
||||
<a href="https://www.tildefriends.net/"
|
||||
>https://www.tildefriends.net/</a
|
||||
>.
|
||||
<div class="w3-cell-row">
|
||||
<div class="w3-container w3-cell">
|
||||
<h3>Mobile</h3>
|
||||
<p>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
|
||||
><img src="f-droid.svg" style="height: 2em; margin: 0" />
|
||||
Get it on F-Droid</a
|
||||
>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
|
||||
>
|
||||
<img
|
||||
src="googleplay.svg"
|
||||
style="height: 2em; margin: 0"
|
||||
/>
|
||||
Get it on Google Play (Open Testing)
|
||||
</a>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||
href="https://testflight.apple.com/join/tXxgtSpE"
|
||||
>
|
||||
<img src="ios.svg" style="height: 2em; margin: 0" />
|
||||
Get it on iOS (TestFlight)
|
||||
</a>
|
||||
</p>
|
||||
<p>Just launch the app.</p>
|
||||
</div>
|
||||
<div class="w3-container w3-cell">
|
||||
<h3>Web</h3>
|
||||
<p>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-blue w3-padding-large"
|
||||
href="https://www.tildefriends.net/~core/ssb/"
|
||||
>🦀 Try It</a
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/login?return=/~core/intro"
|
||||
>Register an account with tildefriends.net</a
|
||||
>
|
||||
to take it for a spin right away.
|
||||
</p>
|
||||
</div>
|
||||
<div class="w3-container w3-cell">
|
||||
<h3>Desktop</h3>
|
||||
<p>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-black w3-padding-large"
|
||||
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||
><i class="fa fa-download"></i> Download</a
|
||||
>
|
||||
<a
|
||||
class="w3-button w3-round-large w3-padding w3-blue-gray"
|
||||
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
|
||||
>
|
||||
<img src="appimage.svg" style="height: 2em; margin: 0" />
|
||||
Get Linux 64-bit AppImage
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
Tilde Friends is distributed as a single executable file (or
|
||||
source that you can
|
||||
<a href="http://dev.tildefriends.net">build yourself</a>)
|
||||
and stores all of its data in a single
|
||||
file(<code>db.sqlite</code>). You can generally download the
|
||||
latest executable from
|
||||
<a
|
||||
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||
>releases</a
|
||||
>
|
||||
for your platform, mark it as executable (<code
|
||||
>chmod +x tildefriends*</code
|
||||
>
|
||||
on macOS and Linux), and run. Run with <code>-h</code> to
|
||||
learn more.
|
||||
</p>
|
||||
<p>
|
||||
Tilde Friends will run in the console and provide a web
|
||||
interface at
|
||||
<a href="http://localhost:12345/">http://localhost:12345/</a
|
||||
>. You will have to register a username and password to sign
|
||||
into your instance.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
After a <a href="/~core/intro">brief introduction</a>, Tilde
|
||||
Friends will take you to the Secure Scuttlebutt social network
|
||||
app.
|
||||
</p>
|
||||
</li>
|
||||
<li>Create an account to identify yourself with that instance.</li>
|
||||
<li>
|
||||
Describe yourself in your profile in the <b>ssb</b> app. Give
|
||||
yourself a name and an avatar if you like.
|
||||
@@ -158,11 +210,11 @@
|
||||
<!-- SSB Section -->
|
||||
<div class="w3-light-grey">
|
||||
<div class="w3-row-padding w3-padding-64">
|
||||
<div class="w3-col l4 m6 s4">
|
||||
<div class="w3-col l4 m6 s4 w3-center">
|
||||
<a href="https://scuttlebutt.nz/"
|
||||
><img
|
||||
class="w3-image w3-round-large"
|
||||
src="ssb.png"
|
||||
class="w3-image"
|
||||
src="hermietildefriends.svg"
|
||||
alt="Secure Scuttlebutt"
|
||||
/></a>
|
||||
</div>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
@@ -8,6 +8,7 @@ let gFiles = {};
|
||||
let gApp = {files: {}, emoji: '📦'};
|
||||
let gEditor;
|
||||
let gOriginalInput;
|
||||
let gUnloading;
|
||||
|
||||
let kErrorColor = '#dc322f';
|
||||
let kDisconnectColor = '#f00';
|
||||
@@ -1560,6 +1561,9 @@ function connectSocket(path) {
|
||||
_receive_websocket_message(JSON.parse(event.data));
|
||||
};
|
||||
gSocket.onclose = function (event) {
|
||||
if (gUnloading) {
|
||||
setStatusMessage('⚪ Closing...', kStatusColor);
|
||||
} else {
|
||||
const k_codes = {
|
||||
1000: 'Normal closure',
|
||||
1001: 'Going away',
|
||||
@@ -1581,6 +1585,7 @@ function connectSocket(path) {
|
||||
'🔴 Closed: ' + (k_codes[event.code] || event.code),
|
||||
kDisconnectColor
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1854,6 +1859,9 @@ window.addEventListener('load', function () {
|
||||
window.addEventListener('blur', blur);
|
||||
window.addEventListener('message', message, false);
|
||||
window.addEventListener('online', connectSocket);
|
||||
window.addEventListener('beforeunload', function () {
|
||||
gUnloading = true;
|
||||
});
|
||||
document.getElementById('name').value = window.location.pathname;
|
||||
document
|
||||
.getElementById('closeEditor')
|
||||
|
2
deps/codemirror/cm6.js
vendored
2
deps/codemirror/cm6.js
vendored
File diff suppressed because one or more lines are too long
223
deps/codemirror_src/package-lock.json
generated
vendored
223
deps/codemirror_src/package-lock.json
generated
vendored
@@ -83,18 +83,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-json": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
|
||||
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
||||
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@lezer/json": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/language": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.0.tgz",
|
||||
"integrity": "sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==",
|
||||
"version": "6.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz",
|
||||
"integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.23.0",
|
||||
@@ -133,9 +133,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/theme-one-dark": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
||||
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
||||
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
@@ -144,11 +144,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.0.tgz",
|
||||
"integrity": "sha512-ghHIeRGfWB8h9Tc3sMdr7D5zp4sZvlCzG36Xjdh2ymmfAwvSaCJAAsL3HLyLEnHcE953+5Uox1bx5OS+YCW/7Q==",
|
||||
"version": "6.37.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz",
|
||||
"integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.5.0",
|
||||
"crelt": "^1.0.6",
|
||||
"style-mod": "^4.1.0",
|
||||
"w3c-keyname": "^2.2.4"
|
||||
}
|
||||
@@ -323,9 +324,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
|
||||
"integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz",
|
||||
"integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
@@ -344,9 +345,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz",
|
||||
"integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz",
|
||||
"integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -356,9 +357,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz",
|
||||
"integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz",
|
||||
"integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -368,9 +369,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz",
|
||||
"integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz",
|
||||
"integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -380,9 +381,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz",
|
||||
"integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz",
|
||||
"integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -392,9 +393,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz",
|
||||
"integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz",
|
||||
"integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -404,9 +405,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz",
|
||||
"integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz",
|
||||
"integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -416,9 +417,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz",
|
||||
"integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz",
|
||||
"integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -428,9 +429,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz",
|
||||
"integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz",
|
||||
"integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -440,9 +441,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz",
|
||||
"integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -452,9 +453,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz",
|
||||
"integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz",
|
||||
"integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -464,9 +465,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz",
|
||||
"integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -476,9 +477,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz",
|
||||
"integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -488,9 +489,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz",
|
||||
"integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -500,9 +501,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz",
|
||||
"integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz",
|
||||
"integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -512,9 +513,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz",
|
||||
"integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -524,9 +525,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz",
|
||||
"integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -536,9 +537,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz",
|
||||
"integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz",
|
||||
"integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -548,9 +549,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz",
|
||||
"integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz",
|
||||
"integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -560,9 +561,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz",
|
||||
"integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz",
|
||||
"integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -572,9 +573,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz",
|
||||
"integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz",
|
||||
"integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -584,9 +585,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
||||
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.20.2",
|
||||
@@ -594,9 +595,9 @@
|
||||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
@@ -612,9 +613,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/codemirror": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
||||
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/commands": "^6.0.0",
|
||||
@@ -745,11 +746,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz",
|
||||
"integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
|
||||
"version": "4.44.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz",
|
||||
"integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.7"
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
@@ -759,26 +760,26 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.41.1",
|
||||
"@rollup/rollup-android-arm64": "4.41.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.41.1",
|
||||
"@rollup/rollup-darwin-x64": "4.41.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.41.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.41.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.41.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.41.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.41.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.41.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.41.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.41.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.41.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.41.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.44.0",
|
||||
"@rollup/rollup-android-arm64": "4.44.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.44.0",
|
||||
"@rollup/rollup-darwin-x64": "4.44.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.44.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.44.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.44.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.44.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.44.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.44.0",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.44.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.44.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.44.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.44.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.44.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.44.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.44.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.44.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.44.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.44.0",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -853,9 +854,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.40.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.40.0.tgz",
|
||||
"integrity": "sha512-cfeKl/jjwSR5ar7d0FGmave9hFGJT8obyo0z+CrQOylLDbk7X81nPU6vq9VORa5jU30SkDnT2FXjLbR8HLP+xA==",
|
||||
"version": "5.43.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
|
||||
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
|
288
docs/usage.md
Normal file
288
docs/usage.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# CLI Usage
|
||||
|
||||
## tildefriends -h
|
||||
|
||||
```
|
||||
Usage: out/debug/tildefriends command [command-options]
|
||||
commands:
|
||||
run - Run tildefriends (default).
|
||||
sandbox - Run a sandboxed tildefriends sandbox process (used internally).
|
||||
import - Import apps from file to the database.
|
||||
export - Export apps from the database to file.
|
||||
publish - Append a message to a feed.
|
||||
private - Append a private post message to a feed.
|
||||
create_invite - Create an invite.
|
||||
get_sequence - Get the last sequence number for a feed.
|
||||
get_identity - Get the server account identity.
|
||||
get_profile - Get profile information for the given identity.
|
||||
get_contacts - Get information about followed, blocked, and friend identities.
|
||||
has_blob - Check whether a blob is in the blob store.
|
||||
get_blob - Read a file from the blob store.
|
||||
store_blob - Write a file to the blob store.
|
||||
verify - Verify a feed.
|
||||
test - Test SSB.
|
||||
```
|
||||
|
||||
## tildefriends run -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends run [options]
|
||||
|
||||
Run tildefriends (default).
|
||||
|
||||
options:
|
||||
-s, --script script Script to run (default: core/core.js).
|
||||
-d, --db-path path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-k, --ssb-network-key key SSB network key to use.
|
||||
-n, --count count Number of instances to run.
|
||||
-a, --args args Arguments of the format key=value,foo=bar,verbose=true (note: these are persisted to the database).
|
||||
code_of_conduct (default: ""): Code of conduct presented at sign-in.
|
||||
ssb_port (default: 8008): Port on which to listen for SSB secure handshake connections.
|
||||
http_local_only (default: false): Whether to bind http(s) to the loopback address. Otherwise any.
|
||||
http_port (default: 12345): Port on which to listen for HTTP connections.
|
||||
https_port (default: 0): Port on which to listen for secure HTTP connections.
|
||||
out_http_port_file (default: ""): File to which to write bound HTTP port.
|
||||
blob_fetch_age_seconds (default: -1): Only blobs mentioned more recently than this age will be automatically fetched.
|
||||
blob_expire_age_seconds (default: -1): Blobs older than this will be automatically deleted.
|
||||
fetch_hosts (default: ""): Comma-separated list of host names to which HTTP fetch requests are allowed. None if empty.
|
||||
http_redirect (default: ""): If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "http://example.com")
|
||||
index (default: "/~core/intro/"): Default path.
|
||||
index_map (default: ""): Mappings from hostname to redirect path, one per line, as in: "www.tildefriends.net=/~core/index/"
|
||||
peer_exchange (default: false): Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.
|
||||
replicator (default: true): Enable message and blob replication.
|
||||
room (default: true): Enable peers to tunnel through this instance as a room.
|
||||
room_name (default: "tilde friends tunnel"): Name of the room.
|
||||
seeds_host (default: "seeds.tildefriends.net"): Hostname for seed connections.
|
||||
account_registration (default: true): Allow registration of new accounts.
|
||||
replication_hops (default: 2): Number of hops to replicate (1 = direct follows, 2 = follows of follows, etc.).
|
||||
delete_stale_feeds (default: false): Periodically delete feeds that aren't visible from local accounts or related follows.
|
||||
talk_to_strangers (default: true): Whether connections are accepted from accounts that aren't in the replication range or otherwise already known.
|
||||
autologin (default: false): Whether mobile autologin is supported.
|
||||
broadcast (default: true): Send network discovery broadcasts.
|
||||
discovery (default: true): Receive network discovery broadcasts.
|
||||
-o, --one-proc Run everything in one process (unsafely!).
|
||||
-z, --zip path Zip archive from which to load files.
|
||||
-v, --verbose Log raw messages.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends sandbox -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends sandbox [options]
|
||||
|
||||
Run a sandboxed tildefriends sandbox process (used internally).
|
||||
|
||||
options:
|
||||
-h, --help Show this usage information.
|
||||
-f, --fd File descriptor with which to communicate with parent process.
|
||||
```
|
||||
|
||||
## tildefriends import -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends import [options] [paths...]
|
||||
|
||||
Import apps from file to the database.
|
||||
|
||||
options:
|
||||
-u, --user user User into whose account apps will be imported (default: "import").
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends export -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends export [options] [paths...]
|
||||
|
||||
Export apps from the database to file.
|
||||
|
||||
options:
|
||||
-u, --user user User from whose account apps will be exported (default: "core").
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-h, --help Show this usage information.
|
||||
|
||||
paths Paths of apps to export (example: /~core/ssb /~user/app).
|
||||
```
|
||||
|
||||
## tildefriends publish -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends publish [options]
|
||||
|
||||
Append a message to a feed.
|
||||
|
||||
options:
|
||||
-u, --user user User owning identity with which to publish.
|
||||
-i, --id identity Identity with which to publish message.
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-c, --content json JSON content of message to publish.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends private -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends private [options]
|
||||
|
||||
Append a private post message to a feed.
|
||||
|
||||
options:
|
||||
-u, --user user User owning identity with which to publish (optional).
|
||||
-i, --id identity Identity with which to publish message.
|
||||
-r, --recipients recipients Recipient identities.
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-t, --text text Private post text.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends create_invite -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends create_invite [options]
|
||||
|
||||
Create an invite.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-i, --identity identity Account from which to get latest sequence number.
|
||||
-a, --address address Address to which the recipient will connect.
|
||||
-p, --port port Port to which the recipient will connect.
|
||||
-u, --use_count count Number of times this invite may be used (default: 1).
|
||||
-e, --expires seconds How long this invite is valid in seconds (-1 for indefinitely, default: 1 hour).
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends get_sequence -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends get_sequence [options]
|
||||
|
||||
Get the last sequence number for a feed.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-i, --identity identity Account from which to get latest sequence number.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends get_identity -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends get_identity [options]
|
||||
|
||||
Get the server account identity.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends get_profile -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends get_profile [options]
|
||||
|
||||
Get profile information for the given identity.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-i, --identity identity Account for which to get profile information.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends get_contacts -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends get_contacts [options]
|
||||
|
||||
Get information about followed, blocked, and friend identities.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-i, --identity identity Account from which to get contact information.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends has_blob -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends has_blob [options]
|
||||
|
||||
Check whether a blob is in the blob store.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-b, --blob_id blob_id ID of blob to query.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends get_blob -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends get_blob [options]
|
||||
|
||||
Read a file from the blob store.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-b, --blob blob_id Blob identifier to retrieve.
|
||||
-o, --output file_path Location to write the retrieved blob.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends store_blob -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends store_blob [options]
|
||||
|
||||
Write a file to the blob store.
|
||||
|
||||
options:
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-f, --file file_path Path to file to add to the blob store.
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends verify -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends verify [options]
|
||||
|
||||
Verify a feed.
|
||||
|
||||
options:
|
||||
-i, --identity identity Identity to verify.
|
||||
-s, --sequence sequence Sequence number to debug.
|
||||
-d, --db-path db_path SQLite database path (default: /home/cory/.local/share/tildefriends/db.sqlite).
|
||||
-h, --help Show this usage information.
|
||||
```
|
||||
|
||||
## tildefriends test -h
|
||||
|
||||
```
|
||||
|
||||
Usage: out/debug/tildefriends test [options]
|
||||
|
||||
Test SSB.
|
||||
|
||||
options:
|
||||
-t, --tests tests Comma-separated list of tests to run. (default: all)
|
||||
-h, --help Show this usage information.
|
||||
```
|
14
metadata/en-US/changelogs/38.txt
Normal file
14
metadata/en-US/changelogs/38.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
* Improve load times.
|
||||
* Fix the messages_refs table, and make it usable for hashtags.
|
||||
* Fix a circumstance where we would fail to call promise callbacks.
|
||||
* Fix the private messages tab.
|
||||
* Fix the room app.
|
||||
* Expose followed accounts in a user's profile.
|
||||
* Show connection status in the sidebar.
|
||||
* Simplify placeholder messages.
|
||||
* Only show "Mark as Read" when relevant.
|
||||
* Treat profile images more like post images.
|
||||
* Limit the WAL file size.
|
||||
* Updates:
|
||||
* CodeMirror
|
||||
* sqlite 3.50.1
|
6
package-lock.json
generated
6
package-lock.json
generated
@@ -11,9 +11,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.unprompted.tildefriends"
|
||||
android:versionCode="38"
|
||||
android:versionName="0.0.32-wip">
|
||||
android:versionName="0.0.32">
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application
|
||||
|
@@ -75,7 +75,6 @@ static int _object_to_headers(JSContext* context, JSValue object, const char** h
|
||||
JS_GetOwnPropertyNames(context, &ptab, &plen, object, JS_GPN_STRING_MASK);
|
||||
for (; count < (int)plen && count < headers_length / 2; ++count)
|
||||
{
|
||||
JSValue key = JS_AtomToString(context, ptab[count].atom);
|
||||
JSPropertyDescriptor desc;
|
||||
JSValue key_value = JS_NULL;
|
||||
if (JS_GetOwnProperty(context, &desc, object, ptab[count].atom) == 1)
|
||||
@@ -84,9 +83,8 @@ static int _object_to_headers(JSContext* context, JSValue object, const char** h
|
||||
JS_FreeValue(context, desc.setter);
|
||||
JS_FreeValue(context, desc.getter);
|
||||
}
|
||||
headers[count * 2 + 0] = JS_ToCString(context, key);
|
||||
headers[count * 2 + 0] = JS_AtomToCString(context, ptab[count].atom);
|
||||
headers[count * 2 + 1] = JS_ToCString(context, key_value);
|
||||
JS_FreeValue(context, key);
|
||||
JS_FreeValue(context, key_value);
|
||||
}
|
||||
for (uint32_t i = 0; i < plen; ++i)
|
||||
@@ -640,25 +638,6 @@ static void _httpd_endpoint_mem(tf_http_request_t* request)
|
||||
tf_free(response);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_hitches(tf_http_request_t* request)
|
||||
{
|
||||
if (_httpd_redirect(request))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tf_task_t* task = request->user_data;
|
||||
char* response = tf_task_get_hitches(task);
|
||||
const char* headers[] = {
|
||||
"Content-Type",
|
||||
"application/json; charset=utf-8",
|
||||
"Access-Control-Allow-Origin",
|
||||
"*",
|
||||
};
|
||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
||||
tf_free(response);
|
||||
}
|
||||
|
||||
static const char* _after(const char* text, const char* prefix)
|
||||
{
|
||||
if (!text || !prefix)
|
||||
@@ -950,7 +929,7 @@ static void _httpd_endpoint_app_blob_work(tf_ssb_t* ssb, void* user_data)
|
||||
char* app_path = tf_malloc(path_length);
|
||||
snprintf(app_path, path_length, "path:%s", data->user_app->app);
|
||||
const char* value = tf_ssb_db_get_property(ssb, data->user_app->user, app_path);
|
||||
snprintf(data->app_blob_id, sizeof(data->app_blob_id), "%s", value);
|
||||
tf_string_set(data->app_blob_id, sizeof(data->app_blob_id), value);
|
||||
tf_free(app_path);
|
||||
tf_free((void*)value);
|
||||
data->file = last_slash + 1;
|
||||
@@ -1149,7 +1128,7 @@ static void _httpd_endpoint_view_work(tf_ssb_t* ssb, void* user_data)
|
||||
char* app_path = tf_malloc(app_path_length);
|
||||
snprintf(app_path, app_path_length, "path:%s", user_app->app);
|
||||
const char* value = tf_ssb_db_get_property(ssb, user_app->user, app_path);
|
||||
snprintf(blob_id, sizeof(blob_id), "%s", value);
|
||||
tf_string_set(blob_id, sizeof(blob_id), value);
|
||||
tf_free(app_path);
|
||||
tf_free((void*)value);
|
||||
}
|
||||
@@ -1176,7 +1155,7 @@ static void _httpd_endpoint_view_work(tf_ssb_t* ssb, void* user_data)
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
tf_ssb_db_add_blob_wants(db, blob_id);
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
snprintf(view->notify_want_blob_id, sizeof(view->notify_want_blob_id), "%s", blob_id);
|
||||
tf_string_set(view->notify_want_blob_id, sizeof(view->notify_want_blob_id), blob_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1327,7 +1306,7 @@ static void _httpd_endpoint_save_work(tf_ssb_t* ssb, void* user_data)
|
||||
tf_ssb_db_set_property(ssb, user_app->user, app_path, blob_id))
|
||||
{
|
||||
tf_ssb_db_add_value_to_array_property(ssb, user_app->user, "apps", user_app->app);
|
||||
snprintf(save->blob_id, sizeof(save->blob_id), "%s", blob_id);
|
||||
tf_string_set(save->blob_id, sizeof(save->blob_id), blob_id);
|
||||
save->response = 200;
|
||||
}
|
||||
else
|
||||
@@ -1360,7 +1339,7 @@ static void _httpd_endpoint_save_work(tf_ssb_t* ssb, void* user_data)
|
||||
char blob_id[k_blob_id_len] = { 0 };
|
||||
if (tf_ssb_db_blob_store(ssb, request->body, request->content_length, blob_id, sizeof(blob_id), NULL))
|
||||
{
|
||||
snprintf(save->blob_id, sizeof(save->blob_id), "%s", blob_id);
|
||||
tf_string_set(save->blob_id, sizeof(save->blob_id), blob_id);
|
||||
save->response = 200;
|
||||
}
|
||||
else
|
||||
@@ -1980,7 +1959,7 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
||||
const char* return_url = _form_data_get(form_data, "return");
|
||||
if (return_url)
|
||||
{
|
||||
snprintf(login->location_header, sizeof(login->location_header), "%s", return_url);
|
||||
tf_string_set(login->location_header, sizeof(login->location_header), return_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2085,7 +2064,7 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
||||
const char* return_url = _form_data_get(form_data, "return");
|
||||
if (return_url)
|
||||
{
|
||||
snprintf(login->location_header, sizeof(login->location_header), "%s", return_url);
|
||||
tf_string_set(login->location_header, sizeof(login->location_header), return_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2437,7 +2416,6 @@ tf_http_t* tf_httpd_create(JSContext* context)
|
||||
|
||||
tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL);
|
||||
tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task);
|
||||
tf_http_add_handler(http, "/hitches", _httpd_endpoint_hitches, NULL, task);
|
||||
tf_http_add_handler(http, "/mem", _httpd_endpoint_mem, NULL, task);
|
||||
tf_http_add_handler(http, "/trace", _httpd_endpoint_trace, NULL, task);
|
||||
tf_http_add_handler(http, "/ebt", _httpd_endpoint_ebt, NULL, task);
|
||||
|
@@ -11,7 +11,8 @@
|
||||
** @{
|
||||
*/
|
||||
|
||||
#include "quickjs.h"
|
||||
/** A JS context. */
|
||||
typedef struct JSContext JSContext;
|
||||
|
||||
/**
|
||||
** An HTTP server instance.
|
||||
|
83
src/main.c
83
src/main.c
@@ -169,8 +169,8 @@ typedef struct _command_t
|
||||
const command_t k_commands[] = {
|
||||
{ "run", _tf_command_run, "Run tildefriends (default)." },
|
||||
{ "sandbox", _tf_command_sandbox, "Run a sandboxed tildefriends sandbox process (used internally)." },
|
||||
{ "import", _tf_command_import, "Import apps to SSB." },
|
||||
{ "export", _tf_command_export, "Export apps from SSB." },
|
||||
{ "import", _tf_command_import, "Import apps from file to the database." },
|
||||
{ "export", _tf_command_export, "Export apps from the database to file." },
|
||||
{ "publish", _tf_command_publish, "Append a message to a feed." },
|
||||
{ "private", _tf_command_private, "Append a private post message to a feed." },
|
||||
{ "create_invite", _tf_command_create_invite, "Create an invite." },
|
||||
@@ -185,6 +185,18 @@ const command_t k_commands[] = {
|
||||
{ "test", _tf_command_test, "Test SSB." },
|
||||
};
|
||||
|
||||
static const char* _description(const char* name)
|
||||
{
|
||||
for (int i = 0; i < tf_countof(k_commands); i++)
|
||||
{
|
||||
if (strcmp(name, k_commands[i].name) == 0)
|
||||
{
|
||||
return k_commands[i].description;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _tf_command_test(const char* file, int argc, char* argv[])
|
||||
{
|
||||
#if !defined(__ANDROID__)
|
||||
@@ -233,8 +245,9 @@ static int _tf_command_test(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\n%s test [options]\n\n", file);
|
||||
tf_printf("options\n");
|
||||
tf_printf("\nUsage: %s test [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("test"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -t, --tests tests Comma-separated list of tests to run. (default: all)\n");
|
||||
tf_printf(" -h, --help Show this usage information.\n");
|
||||
tf_free((void*)default_db_path);
|
||||
@@ -288,7 +301,8 @@ static int _tf_command_import(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\n%s import [options] [paths...]\n\n", file);
|
||||
tf_printf("\nUsage: %s import [options] [paths...]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("import"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -u, --user user User into whose account apps will be imported (default: \"import\").\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
@@ -357,7 +371,8 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\n%s export [options] [paths...]\n\n", file);
|
||||
tf_printf("\nUsage: %s export [options] [paths...]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("export"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -u, --user user User from whose account apps will be exported (default: \"core\").\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
@@ -473,7 +488,8 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !identity || !content)
|
||||
{
|
||||
tf_printf("\n%s publish [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s publish [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("publish"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -u, --user user User owning identity with which to publish.\n");
|
||||
tf_printf(" -i, --id identity Identity with which to publish message.\n");
|
||||
@@ -501,7 +517,7 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
|
||||
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
int64_t sequence = 0;
|
||||
int32_t sequence = 0;
|
||||
char previous[k_id_base64_len] = { 0 };
|
||||
tf_ssb_db_get_latest_message_by_author(ssb, identity, &sequence, previous, sizeof(previous));
|
||||
JSValue content_value = JS_ParseJSON(context, content, strlen(content), NULL);
|
||||
@@ -592,7 +608,8 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !identity || !recipients || !text)
|
||||
{
|
||||
tf_printf("\n%s private [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s private [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("private"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -u, --user user User owning identity with which to publish (optional).\n");
|
||||
tf_printf(" -i, --id identity Identity with which to publish message.\n");
|
||||
@@ -653,7 +670,7 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
|
||||
char* encrypted = tf_ssb_private_message_encrypt(private_key, recipient_list, recipient_count, message_str, strlen(message_str));
|
||||
if (encrypted)
|
||||
{
|
||||
int64_t sequence = 0;
|
||||
int32_t sequence = 0;
|
||||
char previous[k_id_base64_len] = { 0 };
|
||||
tf_ssb_db_get_latest_message_by_author(ssb, identity, &sequence, previous, sizeof(previous));
|
||||
|
||||
@@ -723,7 +740,8 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !file_path)
|
||||
{
|
||||
tf_printf("\n%s store_blob [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s store_blob [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("store_blob"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -f, --file file_path Path to file to add to the blob store.\n");
|
||||
@@ -825,7 +843,8 @@ static int _tf_command_get_blob(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !blob_id)
|
||||
{
|
||||
tf_printf("\n%s store_blob [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s get_blob [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("get_blob"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -b, --blob blob_id Blob identifier to retrieve.\n");
|
||||
@@ -927,7 +946,8 @@ static int _tf_command_has_blob(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !blob_id)
|
||||
{
|
||||
tf_printf("\n%s has_blob [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s has_blob [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("has_blob"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -b, --blob_id blob_id ID of blob to query.\n");
|
||||
@@ -1005,7 +1025,8 @@ static int _tf_command_create_invite(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !identity || !use_count || !expires || !host || !port)
|
||||
{
|
||||
tf_printf("\n%s get_sequence [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s create_invite [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("create_invite"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -i, --identity identity Account from which to get latest sequence number.\n");
|
||||
@@ -1073,7 +1094,8 @@ static int _tf_command_get_sequence(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !identity)
|
||||
{
|
||||
tf_printf("\n%s get_sequence [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s get_sequence [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("get_sequence"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -i, --identity identity Account from which to get latest sequence number.\n");
|
||||
@@ -1084,9 +1106,9 @@ static int _tf_command_get_sequence(const char* file, int argc, char* argv[])
|
||||
|
||||
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
|
||||
tf_ssb_set_quiet(ssb, true);
|
||||
int64_t sequence = -1;
|
||||
int32_t sequence = -1;
|
||||
int result = tf_ssb_db_get_latest_message_by_author(ssb, identity, &sequence, NULL, 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
tf_printf("%" PRId64 "\n", sequence);
|
||||
tf_printf("%d\n", sequence);
|
||||
tf_ssb_destroy(ssb);
|
||||
tf_free((void*)default_db_path);
|
||||
return result;
|
||||
@@ -1126,7 +1148,8 @@ static int _tf_command_get_identity(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\n%s get_identity [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s get_identity [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("get_identity"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -h, --help Show this usage information.\n");
|
||||
@@ -1183,7 +1206,8 @@ static int _tf_command_get_profile(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !identity)
|
||||
{
|
||||
tf_printf("\n%s get_profile [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s get_profile [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("get_profile"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -i, --identity identity Account for which to get profile information.\n");
|
||||
@@ -1242,7 +1266,8 @@ static int _tf_command_get_contacts(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage || !identity)
|
||||
{
|
||||
tf_printf("\n%s get_contacts [options]\n\n", file);
|
||||
tf_printf("\nUsage: %s get_contacts [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("get_contacts"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -i, --identity identity Account from which to get contact information.\n");
|
||||
@@ -1304,7 +1329,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[])
|
||||
const char* identity = NULL;
|
||||
const char* default_db_path = _get_db_path();
|
||||
const char* db_path = default_db_path;
|
||||
int64_t sequence = 0;
|
||||
int32_t sequence = 0;
|
||||
bool show_usage = false;
|
||||
|
||||
while (!show_usage)
|
||||
@@ -1333,7 +1358,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[])
|
||||
identity = optarg;
|
||||
break;
|
||||
case 's':
|
||||
sequence = atoll(optarg);
|
||||
sequence = atoi(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
db_path = optarg;
|
||||
@@ -1343,7 +1368,8 @@ static int _tf_command_verify(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\n%s import [options] [paths...]\n\n", file);
|
||||
tf_printf("\nUsage: %s verify [options]\n\n", file);
|
||||
tf_printf("%s\n\n", _description("verify"));
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -i, --identity identity Identity to verify.\n");
|
||||
tf_printf(" -s, --sequence sequence Sequence number to debug.\n");
|
||||
@@ -1671,8 +1697,11 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
||||
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\n%s run [options]\n\n", file);
|
||||
tf_printf("options\n");
|
||||
tf_printf("\nUsage: %s run [options]\n\n", file);
|
||||
#if !defined(__ANDROID__)
|
||||
tf_printf("%s\n\n", _description("run"));
|
||||
#endif
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -s, --script script Script to run (default: core/core.js).\n");
|
||||
tf_printf(" -d, --db-path path SQLite database path (default: %s).\n", default_db_path);
|
||||
tf_printf(" -k, --ssb-network-key key SSB network key to use.\n");
|
||||
@@ -1757,6 +1786,9 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
||||
if (show_usage)
|
||||
{
|
||||
tf_printf("\nUsage: %s sandbox [options]\n\n", file);
|
||||
#if !defined(__ANDROID__)
|
||||
tf_printf("%s\n\n", _description("sandbox"));
|
||||
#endif
|
||||
tf_printf("options:\n");
|
||||
tf_printf(" -h, --help Show this usage information.\n");
|
||||
tf_printf(" -f, --fd File descriptor with which to communicate with parent process.\n");
|
||||
@@ -2026,6 +2058,7 @@ void tf_run_thread_start(const char* zip_path)
|
||||
#else
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
_startup(argc, argv);
|
||||
ares_library_init(0);
|
||||
|
||||
|
@@ -489,7 +489,7 @@ static JSValue _socket_connect(JSContext* context, JSValueConst this_val, int ar
|
||||
const char* node = JS_ToCString(context, argv[0]);
|
||||
const char* port = JS_ToCString(context, argv[1]);
|
||||
|
||||
snprintf(socket->_peerName, sizeof(socket->_peerName), "%s", node);
|
||||
tf_string_set(socket->_peerName, sizeof(socket->_peerName), node);
|
||||
|
||||
socket_resolve_data_t* data = tf_malloc(sizeof(socket_resolve_data_t));
|
||||
memset(data, 0, sizeof(*data));
|
||||
@@ -1062,9 +1062,7 @@ static void _socket_onShutdown(uv_shutdown_t* request, int status)
|
||||
}
|
||||
else
|
||||
{
|
||||
char error[256];
|
||||
snprintf(error, sizeof(error), "uv_shutdown: %s", uv_strerror(status));
|
||||
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error));
|
||||
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "uv_shutdown: %s", uv_strerror(status)));
|
||||
}
|
||||
tf_free(request);
|
||||
}
|
||||
|
172
src/ssb.c
172
src/ssb.c
@@ -34,9 +34,6 @@
|
||||
#define CYAN "\e[1;36m"
|
||||
#define RESET "\e[0m"
|
||||
|
||||
#define PRE_CALLBACK(ssb, cb) uint64_t pre_callback_hrtime_ns = _tf_ssb_callback_pre(ssb)
|
||||
#define POST_CALLBACK(ssb, cb) _tf_ssb_callback_post(ssb, cb, pre_callback_hrtime_ns)
|
||||
|
||||
const int k_read_back_pressure_threshold = 256;
|
||||
|
||||
static_assert(k_id_base64_len == sodium_base64_ENCODED_LEN(9 + crypto_box_PUBLICKEYBYTES, sodium_base64_VARIANT_ORIGINAL), "k_id_base64_len");
|
||||
@@ -168,6 +165,12 @@ typedef struct _tf_ssb_timer_t
|
||||
void* user_data;
|
||||
} tf_ssb_timer_t;
|
||||
|
||||
typedef struct _tf_ssb_broadcast_result_t
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int result;
|
||||
} tf_ssb_broadcast_result_t;
|
||||
|
||||
typedef struct _tf_ssb_t
|
||||
{
|
||||
bool own_context;
|
||||
@@ -183,6 +186,7 @@ typedef struct _tf_ssb_t
|
||||
sqlite3* db_writer;
|
||||
sqlite3** db_readers;
|
||||
int db_readers_count;
|
||||
int db_ref_count;
|
||||
|
||||
uv_loop_t own_loop;
|
||||
uv_loop_t* loop;
|
||||
@@ -194,6 +198,9 @@ typedef struct _tf_ssb_t
|
||||
uv_timer_t request_activity_timer;
|
||||
uv_tcp_t server;
|
||||
|
||||
tf_ssb_broadcast_result_t* broadcast_results;
|
||||
int broadcast_results_count;
|
||||
|
||||
uint8_t network_key[32];
|
||||
|
||||
uint8_t pub[crypto_sign_PUBLICKEYBYTES];
|
||||
@@ -237,9 +244,6 @@ typedef struct _tf_ssb_t
|
||||
int32_t thread_busy_count;
|
||||
int32_t thread_busy_max;
|
||||
|
||||
void (*hitch_callback)(const char* name, uint64_t duration, void* user_data);
|
||||
void* hitch_user_data;
|
||||
|
||||
tf_ssb_store_queue_t store_queue;
|
||||
int ref_count;
|
||||
|
||||
@@ -368,8 +372,6 @@ static int s_connection_index;
|
||||
static int s_tunnel_index;
|
||||
|
||||
static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broadcast, int expires_seconds);
|
||||
static uint64_t _tf_ssb_callback_pre(tf_ssb_t* ssb);
|
||||
static void _tf_ssb_callback_post(tf_ssb_t* ssb, void* callback, uint64_t pre);
|
||||
static void _tf_ssb_connection_client_send_hello(tf_ssb_connection_t* connection);
|
||||
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason);
|
||||
static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value);
|
||||
@@ -645,9 +647,7 @@ static void _tf_ssb_connection_dispatch_scheduled(tf_ssb_connection_t* connectio
|
||||
connection->scheduled_count--;
|
||||
|
||||
tf_trace_begin(connection->ssb->trace, "scheduled callback");
|
||||
PRE_CALLBACK(connection->ssb, scheduled.callback);
|
||||
scheduled.callback(connection, false, scheduled.user_data);
|
||||
POST_CALLBACK(connection->ssb, scheduled.callback);
|
||||
tf_trace_end(connection->ssb->trace);
|
||||
}
|
||||
}
|
||||
@@ -666,9 +666,7 @@ void tf_ssb_connection_schedule_idle(tf_ssb_connection_t* connection, const char
|
||||
{
|
||||
/* Skip the new request. */
|
||||
tf_trace_begin(connection->ssb->trace, "scheduled callback (skip)");
|
||||
PRE_CALLBACK(connection->ssb, callback);
|
||||
callback(connection, true, user_data);
|
||||
POST_CALLBACK(connection->ssb, callback);
|
||||
tf_trace_end(connection->ssb->trace);
|
||||
}
|
||||
else
|
||||
@@ -679,7 +677,7 @@ void tf_ssb_connection_schedule_idle(tf_ssb_connection_t* connection, const char
|
||||
.callback = callback,
|
||||
.user_data = user_data,
|
||||
};
|
||||
snprintf(connection->scheduled[index].key, sizeof(connection->scheduled[index].key), "%s", key);
|
||||
tf_string_set(connection->scheduled[index].key, sizeof(connection->scheduled[index].key), key);
|
||||
connection->scheduled_count++;
|
||||
|
||||
uv_async_send(&connection->scheduled_async);
|
||||
@@ -800,7 +798,7 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
|
||||
.dependent_connection = dependent_connection,
|
||||
.last_active = now_ms,
|
||||
};
|
||||
snprintf(request.name, sizeof(request.name), "%s", name);
|
||||
tf_string_set(request.name, sizeof(request.name), name);
|
||||
int index = tf_util_insert_index(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare);
|
||||
connection->requests = tf_resize_vec(connection->requests, sizeof(tf_ssb_request_t) * (connection->requests_count + 1));
|
||||
if (connection->requests_count - index)
|
||||
@@ -853,7 +851,7 @@ void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection,
|
||||
.request_number = request_number,
|
||||
.keys = keys,
|
||||
};
|
||||
snprintf(connection->message_requests[index].author, sizeof(connection->message_requests[index].author), "%s", author);
|
||||
tf_string_set(connection->message_requests[index].author, sizeof(connection->message_requests[index].author), author);
|
||||
connection->message_requests_count++;
|
||||
}
|
||||
|
||||
@@ -1249,22 +1247,6 @@ bool tf_ssb_id_str_to_bin(uint8_t* bin, const char* str)
|
||||
return author_id && type ? tf_base64_decode(author_id, type - author_id, bin, crypto_box_PUBLICKEYBYTES) != 0 : false;
|
||||
}
|
||||
|
||||
static uint64_t _tf_ssb_callback_pre(tf_ssb_t* ssb)
|
||||
{
|
||||
return uv_hrtime();
|
||||
}
|
||||
|
||||
static void _tf_ssb_callback_post(tf_ssb_t* ssb, void* callback, uint64_t pre)
|
||||
{
|
||||
if (ssb->hitch_callback)
|
||||
{
|
||||
uint64_t post = uv_hrtime();
|
||||
const char* name = tf_util_function_to_string(callback);
|
||||
ssb->hitch_callback(name, post - pre, ssb->hitch_user_data);
|
||||
tf_free((void*)name);
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_notify_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection)
|
||||
{
|
||||
tf_ssb_connections_changed_callback_node_t* next = NULL;
|
||||
@@ -1272,9 +1254,7 @@ static void _tf_ssb_notify_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t ch
|
||||
{
|
||||
next = node->next;
|
||||
tf_trace_begin(ssb->trace, "connections_changed");
|
||||
PRE_CALLBACK(ssb, node->callback);
|
||||
node->callback(ssb, change, connection, node->user_data);
|
||||
POST_CALLBACK(ssb, node->callback);
|
||||
tf_trace_end(ssb->trace);
|
||||
}
|
||||
}
|
||||
@@ -1383,9 +1363,7 @@ static void _tf_ssb_connection_verify_identity(tf_ssb_connection_t* connection,
|
||||
connection->state = k_tf_ssb_state_verified;
|
||||
if (connection->connect_callback)
|
||||
{
|
||||
PRE_CALLBACK(connection->ssb, connection->connect_callback);
|
||||
connection->connect_callback(connection, NULL, connection->connect_callback_user_data);
|
||||
POST_CALLBACK(connection->ssb, connection->connect_callback);
|
||||
connection->connect_callback = NULL;
|
||||
connection->connect_callback_user_data = NULL;
|
||||
}
|
||||
@@ -1734,7 +1712,7 @@ static void _tf_ssb_name_to_string(JSContext* context, JSValue object, char* buf
|
||||
else if (JS_IsString(name))
|
||||
{
|
||||
const char* part_str = JS_ToCString(context, name);
|
||||
snprintf(buffer, size, "%s", part_str);
|
||||
tf_string_set(buffer, size, part_str);
|
||||
JS_FreeCString(context, part_str);
|
||||
}
|
||||
JS_FreeValue(context, name);
|
||||
@@ -1777,9 +1755,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "request %s:%d", request_name, request_number);
|
||||
tf_trace_begin(connection->ssb->trace, buffer);
|
||||
PRE_CALLBACK(connection->ssb, callback);
|
||||
callback(connection, flags, request_number, val, message, size, user_data);
|
||||
POST_CALLBACK(connection->ssb, callback);
|
||||
tf_trace_end(connection->ssb->trace);
|
||||
if (!(flags & k_ssb_rpc_flag_stream))
|
||||
{
|
||||
@@ -1798,9 +1774,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
{
|
||||
tf_ssb_connection_add_request(connection, -request_number, name, NULL, NULL, NULL, NULL);
|
||||
tf_trace_begin(connection->ssb->trace, it->name);
|
||||
PRE_CALLBACK(connection->ssb, it->callback);
|
||||
it->callback(connection, flags, request_number, val, message, size, it->user_data);
|
||||
POST_CALLBACK(connection->ssb, it->callback);
|
||||
tf_trace_end(connection->ssb->trace);
|
||||
found = true;
|
||||
break;
|
||||
@@ -1840,9 +1814,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "request %s:%d", request_name, request_number);
|
||||
tf_trace_begin(connection->ssb->trace, buffer);
|
||||
PRE_CALLBACK(connection->ssb, callback);
|
||||
callback(connection, flags, request_number, JS_UNDEFINED, message, size, user_data);
|
||||
POST_CALLBACK(connection->ssb, callback);
|
||||
tf_trace_end(connection->ssb->trace);
|
||||
}
|
||||
}
|
||||
@@ -1876,7 +1848,7 @@ static void _tf_ssb_connection_rpc_recv_push(tf_ssb_connection_t* connection, co
|
||||
|
||||
while (connection->rpc_recv_size >= 9)
|
||||
{
|
||||
uint8_t flags = *connection->rpc_recv_buffer;
|
||||
uint8_t flags = (*connection->rpc_recv_buffer) & 0xf;
|
||||
uint32_t body_len;
|
||||
int32_t request_number;
|
||||
memcpy(&body_len, connection->rpc_recv_buffer + 1, sizeof(body_len));
|
||||
@@ -1954,15 +1926,15 @@ static bool _tf_ssb_connection_box_stream_recv(tf_ssb_connection_t* connection)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message, const char* previous_id, int64_t previous_sequence)
|
||||
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message, const char* previous_id, int32_t previous_sequence)
|
||||
{
|
||||
char actual_previous_id[crypto_hash_sha256_BYTES * 2];
|
||||
int64_t actual_previous_sequence = 0;
|
||||
int32_t actual_previous_sequence = 0;
|
||||
bool have_previous = false;
|
||||
if (previous_id)
|
||||
{
|
||||
have_previous = *previous_id && previous_sequence > 0;
|
||||
snprintf(actual_previous_id, sizeof(actual_previous_id), "%s", previous_id);
|
||||
tf_string_set(actual_previous_id, sizeof(actual_previous_id), previous_id);
|
||||
actual_previous_sequence = previous_sequence;
|
||||
}
|
||||
else
|
||||
@@ -1975,7 +1947,7 @@ JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* pr
|
||||
|
||||
JS_SetPropertyStr(context, root, "previous", have_previous ? JS_NewString(context, actual_previous_id) : JS_NULL);
|
||||
JS_SetPropertyStr(context, root, "author", JS_NewString(context, author));
|
||||
JS_SetPropertyStr(context, root, "sequence", JS_NewInt64(context, actual_previous_sequence + 1));
|
||||
JS_SetPropertyStr(context, root, "sequence", JS_NewInt32(context, actual_previous_sequence + 1));
|
||||
|
||||
int64_t now = (int64_t)time(NULL);
|
||||
JS_SetPropertyStr(context, root, "timestamp", JS_NewInt64(context, now * 1000LL));
|
||||
@@ -2029,9 +2001,7 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
|
||||
}
|
||||
if (connection->connect_callback)
|
||||
{
|
||||
PRE_CALLBACK(connection->ssb, connection->connect_callback);
|
||||
connection->connect_callback(NULL, reason, connection->connect_callback_user_data);
|
||||
POST_CALLBACK(connection->ssb, connection->connect_callback);
|
||||
connection->connect_callback = NULL;
|
||||
connection->connect_callback_user_data = NULL;
|
||||
}
|
||||
@@ -2519,6 +2489,7 @@ sqlite3* tf_ssb_acquire_db_reader(tf_ssb_t* ssb)
|
||||
tf_ssb_db_init_reader(db);
|
||||
}
|
||||
tf_trace_sqlite(ssb->trace, db);
|
||||
ssb->db_ref_count++;
|
||||
uv_mutex_unlock(&ssb->db_readers_lock);
|
||||
sqlite3_set_authorizer(db, NULL, NULL);
|
||||
return db;
|
||||
@@ -2535,10 +2506,17 @@ void tf_ssb_release_db_reader(tf_ssb_t* ssb, sqlite3* db)
|
||||
{
|
||||
sqlite3_db_release_memory(db);
|
||||
uv_mutex_lock(&ssb->db_readers_lock);
|
||||
ssb->db_ref_count--;
|
||||
bool destroy = ssb->shutting_down_deferred && ssb->db_ref_count == 0;
|
||||
ssb->db_readers = tf_resize_vec(ssb->db_readers, sizeof(sqlite3*) * (ssb->db_readers_count + 1));
|
||||
ssb->db_readers[ssb->db_readers_count++] = db;
|
||||
uv_mutex_unlock(&ssb->db_readers_lock);
|
||||
tf_trace_end(ssb->trace);
|
||||
|
||||
if (destroy)
|
||||
{
|
||||
tf_ssb_destroy(ssb);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3* tf_ssb_acquire_db_writer(tf_ssb_t* ssb)
|
||||
@@ -2832,15 +2810,6 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
JS_FreeRuntime(ssb->runtime);
|
||||
ssb->own_context = false;
|
||||
}
|
||||
if (ssb->db_writer)
|
||||
{
|
||||
int r = sqlite3_close(ssb->db_writer);
|
||||
if (r != SQLITE_OK)
|
||||
{
|
||||
tf_printf("sqlite3_close: %s\n", sqlite3_errstr(r));
|
||||
}
|
||||
ssb->db_writer = NULL;
|
||||
}
|
||||
while (ssb->broadcasts)
|
||||
{
|
||||
tf_ssb_broadcast_t* broadcast = ssb->broadcasts;
|
||||
@@ -2856,6 +2825,15 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
tf_printf("sqlite3_close: %s\n", sqlite3_errstr(r));
|
||||
}
|
||||
}
|
||||
if (ssb->db_writer)
|
||||
{
|
||||
int r = sqlite3_close(ssb->db_writer);
|
||||
if (r != SQLITE_OK)
|
||||
{
|
||||
tf_printf("sqlite3_close: %s\n", sqlite3_errstr(r));
|
||||
}
|
||||
ssb->db_writer = NULL;
|
||||
}
|
||||
ssb->db_readers_count = 0;
|
||||
if (ssb->db_readers)
|
||||
{
|
||||
@@ -2872,9 +2850,15 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
tf_free(ssb->room_name);
|
||||
ssb->room_name = NULL;
|
||||
}
|
||||
if (ssb->broadcast_results_count)
|
||||
{
|
||||
tf_free(ssb->broadcast_results);
|
||||
ssb->broadcast_results = NULL;
|
||||
ssb->broadcast_results_count = 0;
|
||||
}
|
||||
|
||||
ssb->shutting_down_deferred = true;
|
||||
if (ssb->connection_ref_count == 0)
|
||||
if (ssb->connection_ref_count == 0 && ssb->db_ref_count == 0)
|
||||
{
|
||||
uv_mutex_destroy(&ssb->db_readers_lock);
|
||||
uv_mutex_destroy(&ssb->db_writer_lock);
|
||||
@@ -2996,7 +2980,7 @@ static tf_ssb_connection_t* _tf_ssb_connection_create(
|
||||
tf_ssb_connection_t* connection = _tf_ssb_connection_create_internal(ssb, "cli", s_connection_index++);
|
||||
connection->connect.data = connection;
|
||||
|
||||
snprintf(connection->host, sizeof(connection->host), "%s", host);
|
||||
tf_string_set(connection->host, sizeof(connection->host), host);
|
||||
connection->port = ntohs(addr->sin_port);
|
||||
connection->connect_callback = callback;
|
||||
connection->connect_callback_user_data = user_data;
|
||||
@@ -3171,7 +3155,7 @@ void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* ke
|
||||
{
|
||||
tf_ssb_connections_store(ssb->connections_tracker, host, port, id);
|
||||
}
|
||||
snprintf(connect->host, sizeof(connect->host), "%s", host);
|
||||
tf_string_set(connect->host, sizeof(connect->host), host);
|
||||
memcpy(connect->key, key, k_id_bin_len);
|
||||
tf_ssb_ref(ssb);
|
||||
int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET });
|
||||
@@ -3220,7 +3204,7 @@ static void _tf_ssb_connect_with_invite(
|
||||
{
|
||||
tf_ssb_connections_store(ssb->connections_tracker, host, port, id);
|
||||
}
|
||||
snprintf(connect->host, sizeof(connect->host), "%s", host);
|
||||
tf_string_set(connect->host, sizeof(connect->host), host);
|
||||
memcpy(connect->key, key, k_id_bin_len);
|
||||
memcpy(connect->invite, invite, sizeof(connect->invite));
|
||||
tf_ssb_ref(ssb);
|
||||
@@ -3288,6 +3272,39 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
|
||||
_tf_ssb_connection_read_start(connection);
|
||||
}
|
||||
|
||||
static void _tf_ssb_update_broadcast_result(tf_ssb_t* ssb, struct sockaddr* address, const char* address_str, int result)
|
||||
{
|
||||
for (int i = 0; i < ssb->broadcast_results_count; i++)
|
||||
{
|
||||
if (ssb->broadcast_results[i].addr.ss_family == address->sa_family && address->sa_family == AF_INET &&
|
||||
memcmp(&ssb->broadcast_results[i].addr, address, sizeof(struct sockaddr_in)) == 0)
|
||||
{
|
||||
if (result != ssb->broadcast_results[i].result)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
char broadcast_str[256] = { 0 };
|
||||
uv_ip4_name((struct sockaddr_in*)address, broadcast_str, sizeof(broadcast_str));
|
||||
tf_printf("Unable to send broadcast for %s via %s (%d): %s.\n", address_str, broadcast_str, result, uv_strerror(result));
|
||||
}
|
||||
ssb->broadcast_results[i].result = result;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (address->sa_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_storage storage = { 0 };
|
||||
memcpy(&storage, address, sizeof(struct sockaddr_in));
|
||||
ssb->broadcast_results = tf_resize_vec(ssb->broadcast_results, sizeof(tf_ssb_broadcast_result_t) * (ssb->broadcast_results_count + 1));
|
||||
ssb->broadcast_results[ssb->broadcast_results_count++] = (tf_ssb_broadcast_result_t) {
|
||||
.result = result,
|
||||
.addr = storage,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, struct sockaddr_in* netmask)
|
||||
{
|
||||
struct sockaddr server_addr;
|
||||
@@ -3321,12 +3338,7 @@ static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, s
|
||||
broadcast_addr.sin_port = htons(8008);
|
||||
broadcast_addr.sin_addr.s_addr = (address->sin_addr.s_addr & netmask->sin_addr.s_addr) | (INADDR_BROADCAST & ~netmask->sin_addr.s_addr);
|
||||
r = uv_udp_try_send(&ssb->broadcast_sender, &buf, 1, (struct sockaddr*)&broadcast_addr);
|
||||
if (r < 0)
|
||||
{
|
||||
char broadcast_str[256] = { 0 };
|
||||
uv_ip4_name(&broadcast_addr, broadcast_str, sizeof(broadcast_str));
|
||||
tf_printf("failed to send broadcast for %s via %s (%d): %s\n", address_str, broadcast_str, r, uv_strerror(r));
|
||||
}
|
||||
_tf_ssb_update_broadcast_result(ssb, (struct sockaddr*)&broadcast_addr, address_str, r);
|
||||
}
|
||||
|
||||
typedef struct _seeds_t
|
||||
@@ -3551,9 +3563,7 @@ static void _tf_ssb_notify_broadcasts_changed(tf_ssb_t* ssb)
|
||||
if (node->callback)
|
||||
{
|
||||
tf_trace_begin(ssb->trace, "broadcasts changed");
|
||||
PRE_CALLBACK(ssb, node->callback);
|
||||
node->callback(ssb, node->user_data);
|
||||
POST_CALLBACK(ssb, node->callback);
|
||||
tf_trace_end(ssb->trace);
|
||||
}
|
||||
}
|
||||
@@ -3657,9 +3667,7 @@ void tf_ssb_visit_broadcasts(tf_ssb_t* ssb,
|
||||
if (node->mtime - now < 60)
|
||||
{
|
||||
tf_trace_begin(ssb->trace, "broadcast");
|
||||
PRE_CALLBACK(ssb, callback);
|
||||
callback(node->host, &node->addr, node->origin, node->tunnel_connection, node->pub, user_data);
|
||||
POST_CALLBACK(ssb, callback);
|
||||
tf_trace_end(ssb->trace);
|
||||
}
|
||||
}
|
||||
@@ -3958,7 +3966,7 @@ void tf_ssb_notify_blob_stored(tf_ssb_t* ssb, const char* id)
|
||||
ssb->blobs_stored++;
|
||||
}
|
||||
|
||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int64_t sequence, const char* id, JSValue message_keys)
|
||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_keys)
|
||||
{
|
||||
tf_ssb_message_added_callback_node_t* next = NULL;
|
||||
ssb->messages_stored++;
|
||||
@@ -3966,9 +3974,7 @@ void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int64_t sequ
|
||||
{
|
||||
next = node->next;
|
||||
tf_trace_begin(ssb->trace, "message added callback");
|
||||
PRE_CALLBACK(ssb, node->callback);
|
||||
node->callback(ssb, author, sequence, id, node->user_data);
|
||||
POST_CALLBACK(ssb, node->callback);
|
||||
tf_trace_end(ssb->trace);
|
||||
}
|
||||
|
||||
@@ -4044,9 +4050,7 @@ void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id)
|
||||
{
|
||||
next = node->next;
|
||||
tf_trace_begin(ssb->trace, "blob want added callback");
|
||||
PRE_CALLBACK(ssb, node->callback);
|
||||
node->callback(ssb, id, node->user_data);
|
||||
POST_CALLBACK(ssb, node->callback);
|
||||
tf_trace_end(ssb->trace);
|
||||
}
|
||||
}
|
||||
@@ -4231,12 +4235,6 @@ float tf_ssb_get_average_thread_percent(tf_ssb_t* ssb)
|
||||
return 100.0f * ssb->thread_busy_count / ssb->thread_busy_max;
|
||||
}
|
||||
|
||||
void tf_ssb_set_hitch_callback(tf_ssb_t* ssb, void (*callback)(const char* name, uint64_t duration_ns, void* user_data), void* user_data)
|
||||
{
|
||||
ssb->hitch_callback = callback;
|
||||
ssb->hitch_user_data = user_data;
|
||||
}
|
||||
|
||||
tf_ssb_store_queue_t* tf_ssb_get_store_queue(tf_ssb_t* ssb)
|
||||
{
|
||||
return &ssb->store_queue;
|
||||
@@ -4292,9 +4290,7 @@ static void _tf_ssb_connection_after_work_callback(uv_work_t* work, int status)
|
||||
if (data->after_work_callback)
|
||||
{
|
||||
tf_trace_begin(data->connection->ssb->trace, data->after_name);
|
||||
PRE_CALLBACK(data->connection->ssb, data->after_work_callback);
|
||||
data->after_work_callback(data->connection, status, data->user_data);
|
||||
POST_CALLBACK(data->connection->ssb, data->after_work_callback);
|
||||
tf_trace_end(data->connection->ssb->trace);
|
||||
}
|
||||
data->connection->ref_count--;
|
||||
@@ -4361,9 +4357,7 @@ static void _tf_ssb_after_work_callback(uv_work_t* work, int status)
|
||||
if (data->after_work_callback)
|
||||
{
|
||||
tf_trace_begin(data->ssb->trace, data->after_name);
|
||||
PRE_CALLBACK(data->ssb, data->after_work_callback);
|
||||
data->after_work_callback(data->ssb, status, data->user_data);
|
||||
POST_CALLBACK(data->ssb, data->after_work_callback);
|
||||
tf_trace_end(data->ssb->trace);
|
||||
}
|
||||
tf_ssb_unref(data->ssb);
|
||||
@@ -4485,7 +4479,7 @@ static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void*
|
||||
uv_timer_start(&ssb->broadcast_timer, _tf_ssb_broadcast_timer, 2000, 2000);
|
||||
}
|
||||
ssb->discovery = update->discovery;
|
||||
snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host);
|
||||
tf_string_set(ssb->seeds_host, sizeof(ssb->seeds_host), update->seeds_host);
|
||||
_tf_ssb_start_update_settings(ssb);
|
||||
tf_free(update);
|
||||
}
|
||||
@@ -4526,9 +4520,7 @@ void tf_ssb_set_quiet(tf_ssb_t* ssb, bool quiet)
|
||||
static void _tf_ssb_scheduled_timer(uv_timer_t* handle)
|
||||
{
|
||||
tf_ssb_timer_t* timer = handle->data;
|
||||
PRE_CALLBACK(timer->ssb, timer->callback);
|
||||
timer->callback(timer->ssb, timer->user_data);
|
||||
POST_CALLBACK(timer->ssb, timer->callback);
|
||||
uv_close((uv_handle_t*)handle, _tf_ssb_on_timer_close);
|
||||
}
|
||||
|
||||
|
@@ -61,9 +61,9 @@ static bool _tf_ssb_connections_get_next_connection(tf_ssb_connections_t* connec
|
||||
{
|
||||
if (sqlite3_bind_int(statement, 1, 60000) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
snprintf(host, host_size, "%s", sqlite3_column_text(statement, 0));
|
||||
tf_string_set(host, host_size, (const char*)sqlite3_column_text(statement, 0));
|
||||
*port = sqlite3_column_int(statement, 1);
|
||||
snprintf(key, key_size, "%s", sqlite3_column_text(statement, 2));
|
||||
tf_string_set(key, key_size, (const char*)sqlite3_column_text(statement, 2));
|
||||
result = true;
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
@@ -246,8 +246,8 @@ void tf_ssb_connections_store(tf_ssb_connections_t* connections, const char* hos
|
||||
*update = (tf_ssb_connections_update_t) {
|
||||
.port = port,
|
||||
};
|
||||
snprintf(update->host, sizeof(update->host), "%s", host);
|
||||
snprintf(update->key, sizeof(update->key), "%s", key);
|
||||
tf_string_set(update->host, sizeof(update->host), host);
|
||||
tf_string_set(update->key, sizeof(update->key), key);
|
||||
_tf_ssb_connections_queue_update(connections, update);
|
||||
}
|
||||
|
||||
@@ -258,8 +258,8 @@ void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const c
|
||||
.port = port,
|
||||
.attempted = true,
|
||||
};
|
||||
snprintf(update->host, sizeof(update->host), "%s", host);
|
||||
snprintf(update->key, sizeof(update->key), "%s", key);
|
||||
tf_string_set(update->host, sizeof(update->host), host);
|
||||
tf_string_set(update->key, sizeof(update->key), key);
|
||||
_tf_ssb_connections_queue_update(connections, update);
|
||||
}
|
||||
|
||||
@@ -270,8 +270,8 @@ void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const c
|
||||
.port = port,
|
||||
.succeeded = true,
|
||||
};
|
||||
snprintf(update->host, sizeof(update->host), "%s", host);
|
||||
snprintf(update->key, sizeof(update->key), "%s", key);
|
||||
tf_string_set(update->host, sizeof(update->host), host);
|
||||
tf_string_set(update->key, sizeof(update->key), key);
|
||||
_tf_ssb_connections_queue_update(connections, update);
|
||||
}
|
||||
|
||||
|
110
src/ssb.db.c
110
src/ssb.db.c
@@ -232,6 +232,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_size_by_author_index ON messages (author, length(content))");
|
||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_timestamp_index ON messages (timestamp)");
|
||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_type_timestamp_index ON messages (content ->> 'type', timestamp)");
|
||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_type_root_index ON messages (author, content ->> 'type', content ->> 'root')");
|
||||
_tf_ssb_db_exec(db, "DROP INDEX IF EXISTS messages_author_id_index");
|
||||
_tf_ssb_db_exec(db, "DROP INDEX IF EXISTS messages_by_author_index");
|
||||
_tf_ssb_db_exec(db, "DROP INDEX IF EXISTS messages_id_index");
|
||||
@@ -495,7 +496,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
}
|
||||
|
||||
static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author, int64_t sequence, const char* previous, bool* out_id_mismatch)
|
||||
static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author, int32_t sequence, const char* previous, bool* out_id_mismatch)
|
||||
{
|
||||
bool exists = false;
|
||||
if (sequence == 1)
|
||||
@@ -507,7 +508,7 @@ static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author,
|
||||
sqlite3_stmt* statement;
|
||||
if (sqlite3_prepare_v2(db, "SELECT COUNT(*), id != ?3 AS is_mismatch FROM messages WHERE author = ?1 AND sequence = ?2", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, sequence - 1) == SQLITE_OK &&
|
||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, sequence - 1) == SQLITE_OK &&
|
||||
sqlite3_bind_text(statement, 3, previous, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
exists = sqlite3_column_int(statement, 0) != 0;
|
||||
@@ -519,7 +520,7 @@ static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author,
|
||||
return exists;
|
||||
}
|
||||
|
||||
static int64_t _tf_ssb_db_store_message_raw(sqlite3* db, const char* id, const char* previous, const char* author, int64_t sequence, double timestamp, const char* content,
|
||||
static int64_t _tf_ssb_db_store_message_raw(sqlite3* db, const char* id, const char* previous, const char* author, int32_t sequence, double timestamp, const char* content,
|
||||
size_t content_len, const char* signature, int flags)
|
||||
{
|
||||
int64_t last_row_id = -1;
|
||||
@@ -534,7 +535,7 @@ static int64_t _tf_ssb_db_store_message_raw(sqlite3* db, const char* id, const c
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
||||
(previous ? sqlite3_bind_text(statement, 2, previous, -1, NULL) : sqlite3_bind_null(statement, 2)) == SQLITE_OK &&
|
||||
sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 4, sequence) == SQLITE_OK &&
|
||||
sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 4, sequence) == SQLITE_OK &&
|
||||
sqlite3_bind_double(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_text(statement, 6, content, content_len, NULL) == SQLITE_OK &&
|
||||
sqlite3_bind_text(statement, 7, "sha256", 6, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK &&
|
||||
sqlite3_bind_int(statement, 9, flags) == SQLITE_OK)
|
||||
@@ -568,7 +569,7 @@ static int64_t _tf_ssb_db_store_message_raw(sqlite3* db, const char* id, const c
|
||||
** message when trying to receive what we don't have, and
|
||||
** that's not helping anybody.
|
||||
*/
|
||||
tf_printf("%p: Previous message doesn't exist for author=%s sequence=%" PRId64 " previous=%s.\n", db, author, sequence, previous);
|
||||
tf_printf("%p: Previous message doesn't exist for author=%s sequence=%d previous=%s.\n", db, author, sequence, previous);
|
||||
}
|
||||
return last_row_id;
|
||||
}
|
||||
@@ -625,7 +626,7 @@ typedef struct _message_store_t
|
||||
int flags;
|
||||
char previous[k_id_base64_len];
|
||||
char author[k_id_base64_len];
|
||||
int64_t sequence;
|
||||
int32_t sequence;
|
||||
double timestamp;
|
||||
const char* content;
|
||||
size_t length;
|
||||
@@ -761,9 +762,9 @@ void tf_ssb_db_store_message(
|
||||
const char* author = JS_ToCString(context, authorval);
|
||||
JS_FreeValue(context, authorval);
|
||||
|
||||
int64_t sequence = -1;
|
||||
int32_t sequence = -1;
|
||||
JSValue sequenceval = JS_GetPropertyStr(context, val, "sequence");
|
||||
JS_ToInt64(context, &sequence, sequenceval);
|
||||
JS_ToInt32(context, &sequence, sequenceval);
|
||||
JS_FreeValue(context, sequenceval);
|
||||
|
||||
double timestamp = -1.0;
|
||||
@@ -789,10 +790,10 @@ void tf_ssb_db_store_message(
|
||||
.callback = callback,
|
||||
.user_data = user_data,
|
||||
};
|
||||
snprintf(store->id, sizeof(store->id), "%s", id);
|
||||
snprintf(store->previous, sizeof(store->previous), "%s", previous ? previous : "");
|
||||
snprintf(store->author, sizeof(store->author), "%s", author);
|
||||
snprintf(store->signature, sizeof(store->signature), "%s", signature);
|
||||
tf_string_set(store->id, sizeof(store->id), id);
|
||||
tf_string_set(store->previous, sizeof(store->previous), previous ? previous : "");
|
||||
tf_string_set(store->author, sizeof(store->author), author);
|
||||
tf_string_set(store->signature, sizeof(store->signature), signature);
|
||||
JS_FreeCString(context, author);
|
||||
JS_FreeCString(context, previous);
|
||||
|
||||
@@ -949,7 +950,7 @@ void tf_ssb_db_blob_get_async(tf_ssb_t* ssb, const char* id, tf_ssb_db_blob_get_
|
||||
.callback = callback,
|
||||
.user_data = user_data,
|
||||
};
|
||||
snprintf(async->id, sizeof(async->id), "%s", id);
|
||||
tf_string_set(async->id, sizeof(async->id), id);
|
||||
tf_ssb_run_work(ssb, _tf_ssb_db_blob_get_async_work, _tf_ssb_db_blob_get_async_after_work, async);
|
||||
}
|
||||
|
||||
@@ -1046,7 +1047,7 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char*
|
||||
|
||||
if (result && out_id)
|
||||
{
|
||||
snprintf(out_id, out_id_size, "%s", id);
|
||||
tf_string_set(out_id, out_id_size, id);
|
||||
}
|
||||
if (out_new)
|
||||
{
|
||||
@@ -1055,7 +1056,7 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char*
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, char* out_previous,
|
||||
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int32_t sequence, char* out_message_id, size_t out_message_id_size, char* out_previous,
|
||||
size_t out_previous_size, double* out_timestamp, char** out_content, char* out_hash, size_t out_hash_size, char* out_signature, size_t out_signature_size, int* out_flags)
|
||||
{
|
||||
bool found = false;
|
||||
@@ -1064,11 +1065,11 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
|
||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||
if (sqlite3_prepare_v2(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, sequence) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, sequence) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
if (out_message_id)
|
||||
{
|
||||
snprintf(out_message_id, out_message_id_size, "%s", (const char*)sqlite3_column_text(statement, 0));
|
||||
tf_string_set(out_message_id, out_message_id_size, (const char*)sqlite3_column_text(statement, 0));
|
||||
}
|
||||
if (out_previous)
|
||||
{
|
||||
@@ -1081,7 +1082,7 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(out_previous, out_previous_size, "%s", (const char*)sqlite3_column_text(statement, 1));
|
||||
tf_string_set(out_previous, out_previous_size, (const char*)sqlite3_column_text(statement, 1));
|
||||
}
|
||||
}
|
||||
if (out_timestamp)
|
||||
@@ -1094,11 +1095,11 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
|
||||
}
|
||||
if (out_hash)
|
||||
{
|
||||
snprintf(out_hash, out_hash_size, "%s", (const char*)sqlite3_column_text(statement, 4));
|
||||
tf_string_set(out_hash, out_hash_size, (const char*)sqlite3_column_text(statement, 4));
|
||||
}
|
||||
if (out_signature)
|
||||
{
|
||||
snprintf(out_signature, out_signature_size, "%s", (const char*)sqlite3_column_text(statement, 5));
|
||||
tf_string_set(out_signature, out_signature_size, (const char*)sqlite3_column_text(statement, 5));
|
||||
}
|
||||
if (out_flags)
|
||||
{
|
||||
@@ -1116,7 +1117,7 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
|
||||
return found;
|
||||
}
|
||||
|
||||
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int64_t* out_sequence, char* out_message_id, size_t out_message_id_size)
|
||||
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int32_t* out_sequence, char* out_message_id, size_t out_message_id_size)
|
||||
{
|
||||
bool found = false;
|
||||
sqlite3_stmt* statement;
|
||||
@@ -1131,7 +1132,7 @@ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, i
|
||||
{
|
||||
if (out_sequence)
|
||||
{
|
||||
*out_sequence = sqlite3_column_int64(statement, 1);
|
||||
*out_sequence = sqlite3_column_int(statement, 1);
|
||||
}
|
||||
if (out_message_id)
|
||||
{
|
||||
@@ -1155,7 +1156,7 @@ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, i
|
||||
{
|
||||
if (out_sequence)
|
||||
{
|
||||
*out_sequence = sqlite3_column_int64(statement, 0);
|
||||
*out_sequence = sqlite3_column_int(statement, 0);
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
@@ -1333,19 +1334,19 @@ JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue bi
|
||||
}
|
||||
|
||||
JSValue tf_ssb_format_message(
|
||||
JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags)
|
||||
JSContext* context, const char* previous, const char* author, int32_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags)
|
||||
{
|
||||
JSValue value = JS_NewObject(context);
|
||||
JS_SetPropertyStr(context, value, "previous", (previous && *previous) ? JS_NewString(context, previous) : JS_NULL);
|
||||
if (flags & k_tf_ssb_message_flag_sequence_before_author)
|
||||
{
|
||||
JS_SetPropertyStr(context, value, "sequence", JS_NewInt64(context, sequence));
|
||||
JS_SetPropertyStr(context, value, "sequence", JS_NewInt32(context, sequence));
|
||||
JS_SetPropertyStr(context, value, "author", JS_NewString(context, author));
|
||||
}
|
||||
else
|
||||
{
|
||||
JS_SetPropertyStr(context, value, "author", JS_NewString(context, author));
|
||||
JS_SetPropertyStr(context, value, "sequence", JS_NewInt64(context, sequence));
|
||||
JS_SetPropertyStr(context, value, "sequence", JS_NewInt32(context, sequence));
|
||||
}
|
||||
JS_SetPropertyStr(context, value, "timestamp", JS_NewFloat64(context, timestamp));
|
||||
JS_SetPropertyStr(context, value, "hash", JS_NewString(context, hash));
|
||||
@@ -1552,14 +1553,14 @@ typedef struct _following_t following_t;
|
||||
typedef struct _following_t
|
||||
{
|
||||
char id[k_id_base64_len];
|
||||
bool populated;
|
||||
int depth;
|
||||
following_t** following;
|
||||
following_t** blocking;
|
||||
int following_count;
|
||||
int blocking_count;
|
||||
int depth;
|
||||
int ref_count;
|
||||
int block_ref_count;
|
||||
bool populated;
|
||||
} following_t;
|
||||
|
||||
static int _following_compare(const void* a, const void* b)
|
||||
@@ -1651,7 +1652,7 @@ static following_t* _make_following_node(const char* id, following_t*** followin
|
||||
(*following_count)++;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->depth = INT_MAX;
|
||||
snprintf(entry->id, sizeof(entry->id), "%s", id);
|
||||
tf_string_set(entry->id, sizeof(entry->id), id);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@@ -1745,7 +1746,7 @@ static sqlite3_stmt* _make_following_statement(sqlite3* db)
|
||||
"SELECT content ->> '$.contact' AS contact, content ->> '$.following', content ->> '$.blocking' "
|
||||
"FROM messages "
|
||||
"WHERE author = ? AND content ->> '$.type' = 'contact' AND contact IS NOT NULL "
|
||||
"ORDER BY content ->> '$.contact', sequence",
|
||||
"ORDER BY sequence",
|
||||
-1, &statement, NULL) != SQLITE_OK)
|
||||
{
|
||||
tf_printf("prepare failed: %s", sqlite3_errmsg(db));
|
||||
@@ -1778,22 +1779,23 @@ tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, in
|
||||
}
|
||||
|
||||
tf_ssb_following_t* result = tf_malloc(sizeof(tf_ssb_following_t) * (actual_following_count + 1));
|
||||
memset(result, 0, sizeof(tf_ssb_following_t) * (actual_following_count + 1));
|
||||
|
||||
int write_index = 0;
|
||||
for (int i = 0; i < following_count; i++)
|
||||
{
|
||||
if (following[i]->ref_count > 0 || include_blocks)
|
||||
{
|
||||
snprintf(result[write_index].id, sizeof(result[write_index].id), "%s", following[i]->id);
|
||||
result[write_index].following_count = following[i]->following_count;
|
||||
result[write_index].blocking_count = following[i]->blocking_count;
|
||||
result[write_index].followed_by_count = following[i]->ref_count;
|
||||
result[write_index].blocked_by_count = following[i]->block_ref_count;
|
||||
result[write_index].depth = following[i]->depth;
|
||||
result[write_index] = (tf_ssb_following_t) {
|
||||
.following_count = following[i]->following_count,
|
||||
.blocking_count = following[i]->blocking_count,
|
||||
.followed_by_count = following[i]->ref_count,
|
||||
.blocked_by_count = following[i]->block_ref_count,
|
||||
.depth = following[i]->depth,
|
||||
};
|
||||
tf_string_set(result[write_index].id, sizeof(result[write_index].id), following[i]->id);
|
||||
write_index++;
|
||||
}
|
||||
}
|
||||
result[write_index] = (tf_ssb_following_t) { 0 };
|
||||
|
||||
for (int i = 0; i < following_count; i++)
|
||||
{
|
||||
@@ -1840,7 +1842,7 @@ const char** tf_ssb_db_following_deep_ids(tf_ssb_t* ssb, const char** ids, int c
|
||||
if (following[i]->ref_count > 0)
|
||||
{
|
||||
result[write_index] = result_ids + k_id_base64_len * write_index;
|
||||
snprintf(result[write_index], k_id_base64_len, "%s", following[i]->id);
|
||||
tf_string_set(result[write_index], k_id_base64_len, following[i]->id);
|
||||
write_index++;
|
||||
}
|
||||
}
|
||||
@@ -1900,7 +1902,7 @@ JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys)
|
||||
{
|
||||
JSValue message = JS_UNDEFINED;
|
||||
JSValue formatted = tf_ssb_format_message(context, (const char*)sqlite3_column_text(statement, 0), (const char*)sqlite3_column_text(statement, 1),
|
||||
sqlite3_column_int64(statement, 3), sqlite3_column_double(statement, 4), (const char*)sqlite3_column_text(statement, 5),
|
||||
sqlite3_column_int(statement, 3), sqlite3_column_double(statement, 4), (const char*)sqlite3_column_text(statement, 5),
|
||||
(const char*)sqlite3_column_text(statement, 6), (const char*)sqlite3_column_text(statement, 7), sqlite3_column_int(statement, 8));
|
||||
if (is_keys)
|
||||
{
|
||||
@@ -1939,8 +1941,8 @@ tf_ssb_db_stored_connection_t* tf_ssb_db_get_stored_connections(tf_ssb_t* ssb, i
|
||||
.last_attempt = sqlite3_column_int64(statement, 3),
|
||||
.last_success = sqlite3_column_int64(statement, 4),
|
||||
};
|
||||
snprintf(result[count].address, sizeof(result[count].address), "%s", (const char*)sqlite3_column_text(statement, 0));
|
||||
snprintf(result[count].pubkey, sizeof(result[count].pubkey), "%s", (const char*)sqlite3_column_text(statement, 2));
|
||||
tf_string_set(result[count].address, sizeof(result[count].address), (const char*)sqlite3_column_text(statement, 0));
|
||||
tf_string_set(result[count].pubkey, sizeof(result[count].pubkey), (const char*)sqlite3_column_text(statement, 2));
|
||||
count++;
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
@@ -1978,7 +1980,7 @@ bool tf_ssb_db_get_account_password_hash(tf_ssb_t* ssb, const char* name, char*
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
snprintf(out_password, password_size, "%s", (const char*)sqlite3_column_text(statement, 0));
|
||||
tf_string_set(out_password, password_size, (const char*)sqlite3_column_text(statement, 0));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
@@ -2176,7 +2178,7 @@ bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* pa
|
||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, package_owner, -1, NULL) == SQLITE_OK &&
|
||||
sqlite3_bind_text(statement, 3, package_name, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
snprintf(out_identity, out_identity_size, "%s", (const char*)sqlite3_column_text(statement, 0));
|
||||
tf_string_set(out_identity, out_identity_size, (const char*)sqlite3_column_text(statement, 0));
|
||||
found = true;
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
@@ -2288,14 +2290,14 @@ static void _tf_ssb_db_set_flags(tf_ssb_t* ssb, const char* message_id, int flag
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
}
|
||||
|
||||
bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, bool fix)
|
||||
bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int32_t debug_sequence, bool fix)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
bool verified = true;
|
||||
int64_t sequence = -1;
|
||||
int32_t sequence = -1;
|
||||
if (tf_ssb_db_get_latest_message_by_author(ssb, id, &sequence, NULL, 0))
|
||||
{
|
||||
for (int64_t i = 1; i <= sequence; i++)
|
||||
for (int32_t i = 1; i <= sequence; i++)
|
||||
{
|
||||
char message_id[k_id_base64_len];
|
||||
char previous[256];
|
||||
@@ -2314,12 +2316,12 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, boo
|
||||
if (!tf_ssb_verify_and_strip_signature(context, message, i == debug_sequence ? k_tf_ssb_verify_flag_debug : 0, calculated_id, sizeof(calculated_id),
|
||||
extracted_signature, sizeof(extracted_signature), &calculated_flags))
|
||||
{
|
||||
tf_printf("author=%s sequence=%" PRId64 " verify failed.\n", id, i);
|
||||
tf_printf("author=%s sequence=%d verify failed.\n", id, i);
|
||||
verified = false;
|
||||
}
|
||||
if (calculated_flags != flags)
|
||||
{
|
||||
tf_printf("author=%s sequence=%" PRId64 " flag mismatch %d => %d.\n", id, i, flags, calculated_flags);
|
||||
tf_printf("author=%s sequence=%d flag mismatch %d => %d.\n", id, i, flags, calculated_flags);
|
||||
if (fix)
|
||||
{
|
||||
_tf_ssb_db_set_flags(ssb, message_id, calculated_flags);
|
||||
@@ -2331,7 +2333,7 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, boo
|
||||
}
|
||||
if (strcmp(message_id, calculated_id))
|
||||
{
|
||||
tf_printf("author=%s sequence=%" PRId64 " id mismatch %s => %s.\n", id, i, message_id, calculated_id);
|
||||
tf_printf("author=%s sequence=%d id mismatch %s => %s.\n", id, i, message_id, calculated_id);
|
||||
verified = false;
|
||||
}
|
||||
JS_FreeValue(context, message);
|
||||
@@ -2344,7 +2346,7 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, boo
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("Unable to find message with sequence=%" PRId64 " for author=%s.", i, id);
|
||||
tf_printf("Unable to find message with sequence=%d for author=%s.", i, id);
|
||||
verified = false;
|
||||
break;
|
||||
}
|
||||
@@ -2446,7 +2448,7 @@ bool tf_ssb_db_get_global_setting_string(sqlite3* db, const char* name, char* ou
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL)
|
||||
{
|
||||
snprintf(out_value, size, "%s", sqlite3_column_text(statement, 0));
|
||||
tf_string_set(out_value, size, (const char*)sqlite3_column_text(statement, 0));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
@@ -2458,7 +2460,7 @@ bool tf_ssb_db_get_global_setting_string(sqlite3* db, const char* name, char* ou
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
snprintf(out_value, size, "%s", tf_util_get_default_global_setting_string(name));
|
||||
tf_string_set(out_value, size, tf_util_get_default_global_setting_string(name));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -2740,7 +2742,7 @@ tf_ssb_identity_info_t* tf_ssb_db_get_identity_info(tf_ssb_t* ssb, const char* u
|
||||
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_string_set(info->active_identity, sizeof(info->active_identity), info->identity[0]);
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
|
||||
|
@@ -151,7 +151,7 @@ JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys)
|
||||
** @param[out] out_flags Populated with flags describing the format of the message.
|
||||
** @return True if the message was found and retrieved.
|
||||
*/
|
||||
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, char* out_previous,
|
||||
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int32_t sequence, char* out_message_id, size_t out_message_id_size, char* out_previous,
|
||||
size_t out_previous_size, double* out_timestamp, char** out_content, char* out_hash, size_t out_hash_size, char* out_signature, size_t out_signature_size, int* out_flags);
|
||||
|
||||
/**
|
||||
@@ -163,7 +163,7 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
|
||||
** @param out_message_id_size The size of the out_message_id buffer.
|
||||
** @return True if the message was found and information was retrieved.
|
||||
*/
|
||||
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int64_t* out_sequence, char* out_message_id, size_t out_message_id_size);
|
||||
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int32_t* out_sequence, char* out_message_id, size_t out_message_id_size);
|
||||
|
||||
/**
|
||||
** Call a function for each result row of an SQL query.
|
||||
@@ -281,7 +281,7 @@ bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const c
|
||||
** @param flags tf_ssb_message_flags_t describing the message.
|
||||
*/
|
||||
JSValue tf_ssb_format_message(
|
||||
JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags);
|
||||
JSContext* context, const char* previous, const char* author, int32_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags);
|
||||
|
||||
/** Information about a single followed account. */
|
||||
typedef struct _tf_ssb_following_t
|
||||
@@ -460,7 +460,7 @@ void tf_ssb_db_resolve_index_async(tf_ssb_t* ssb, const char* host, void (*callb
|
||||
** @param fix Fix invalid messages when possible.
|
||||
** @return true If the feed verified successfully.
|
||||
*/
|
||||
bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, bool fix);
|
||||
bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int32_t debug_sequence, bool fix);
|
||||
|
||||
/**
|
||||
** Check if a user has a specific permission.
|
||||
|
@@ -102,7 +102,7 @@ static ebt_entry_t* _ebt_get_entry(tf_ssb_ebt_t* ebt, const char* id)
|
||||
.in = -1,
|
||||
.out = -1,
|
||||
};
|
||||
snprintf(ebt->entries[index].id, sizeof(ebt->entries[index].id), "%s", id);
|
||||
tf_string_set(ebt->entries[index].id, sizeof(ebt->entries[index].id), id);
|
||||
ebt->entries_count++;
|
||||
return &ebt->entries[index];
|
||||
}
|
||||
@@ -127,10 +127,9 @@ void tf_ssb_ebt_receive_clock(tf_ssb_ebt_t* ebt, JSContext* context, JSValue clo
|
||||
}
|
||||
if (!JS_IsUndefined(in_clock))
|
||||
{
|
||||
JSValue key = JS_AtomToString(context, ptab[i].atom);
|
||||
const char* author = JS_ToCString(context, key);
|
||||
int64_t sequence = -1;
|
||||
JS_ToInt64(context, &sequence, in_clock);
|
||||
const char* author = JS_AtomToCString(context, ptab[i].atom);
|
||||
int32_t sequence = -1;
|
||||
JS_ToInt32(context, &sequence, in_clock);
|
||||
|
||||
ebt_entry_t* entry = _ebt_get_entry(ebt, author);
|
||||
if (entry)
|
||||
@@ -153,7 +152,6 @@ void tf_ssb_ebt_receive_clock(tf_ssb_ebt_t* ebt, JSContext* context, JSValue clo
|
||||
}
|
||||
}
|
||||
JS_FreeCString(context, author);
|
||||
JS_FreeValue(context, key);
|
||||
}
|
||||
JS_FreeValue(context, in_clock);
|
||||
}
|
||||
@@ -212,7 +210,7 @@ static void _ebt_add_to_clock(ebt_get_clock_t* work, const char* id, int64_t val
|
||||
memmove(work->clock->entries + index + 1, work->clock->entries + index, (count - index) * sizeof(tf_ssb_ebt_clock_entry_t));
|
||||
}
|
||||
work->clock->entries[index] = (tf_ssb_ebt_clock_entry_t) { .value = out_value };
|
||||
snprintf(work->clock->entries[index].id, sizeof(work->clock->entries[index].id), "%s", id);
|
||||
tf_string_set(work->clock->entries[index].id, sizeof(work->clock->entries[index].id), id);
|
||||
work->clock->count = count + 1;
|
||||
}
|
||||
}
|
||||
@@ -237,12 +235,12 @@ static void _tf_ssb_ebt_get_send_clock_work(tf_ssb_connection_t* connection, voi
|
||||
const char** visible = tf_ssb_db_get_all_visible_identities(ssb, depth);
|
||||
if (visible)
|
||||
{
|
||||
int64_t* sequences = NULL;
|
||||
int32_t* sequences = NULL;
|
||||
for (int i = 0; visible[i]; i++)
|
||||
{
|
||||
int64_t sequence = 0;
|
||||
int32_t sequence = 0;
|
||||
tf_ssb_db_get_latest_message_by_author(ssb, visible[i], &sequence, NULL, 0);
|
||||
sequences = tf_resize_vec(sequences, (i + 1) * sizeof(int64_t));
|
||||
sequences = tf_resize_vec(sequences, (i + 1) * sizeof(int32_t));
|
||||
sequences[i] = sequence;
|
||||
}
|
||||
|
||||
@@ -261,7 +259,7 @@ static void _tf_ssb_ebt_get_send_clock_work(tf_ssb_connection_t* connection, voi
|
||||
char id[k_id_base64_len] = "";
|
||||
if (tf_ssb_connection_get_id(connection, id, sizeof(id)))
|
||||
{
|
||||
int64_t sequence = 0;
|
||||
int32_t sequence = 0;
|
||||
tf_ssb_db_get_latest_message_by_author(ssb, id, &sequence, NULL, 0);
|
||||
uv_mutex_lock(&work->ebt->mutex);
|
||||
_ebt_add_to_clock(work, id, sequence, true, true);
|
||||
@@ -279,7 +277,7 @@ static void _tf_ssb_ebt_get_send_clock_work(tf_ssb_connection_t* connection, voi
|
||||
{
|
||||
requested = tf_resize_vec(requested, (requested_count + 1) * sizeof(tf_ssb_ebt_clock_entry_t));
|
||||
requested[requested_count] = (tf_ssb_ebt_clock_entry_t) { .value = -1 };
|
||||
snprintf(requested[requested_count].id, sizeof(requested[requested_count].id), "%s", entry->id);
|
||||
tf_string_set(requested[requested_count].id, sizeof(requested[requested_count].id), entry->id);
|
||||
requested_count++;
|
||||
}
|
||||
}
|
||||
@@ -342,7 +340,7 @@ tf_ssb_ebt_clock_t* tf_ssb_ebt_get_messages_to_send(tf_ssb_ebt_t* ebt)
|
||||
{
|
||||
clock = tf_resize_vec(clock, sizeof(tf_ssb_ebt_clock_t) + (count + 1) * sizeof(tf_ssb_ebt_clock_entry_t));
|
||||
clock->entries[count] = (tf_ssb_ebt_clock_entry_t) { .value = entry->in };
|
||||
snprintf(clock->entries[count].id, sizeof(clock->entries[count].id), "%s", entry->id);
|
||||
tf_string_set(clock->entries[count].id, sizeof(clock->entries[count].id), entry->id);
|
||||
clock->count = ++count;
|
||||
}
|
||||
}
|
||||
@@ -350,7 +348,7 @@ tf_ssb_ebt_clock_t* tf_ssb_ebt_get_messages_to_send(tf_ssb_ebt_t* ebt)
|
||||
return clock;
|
||||
}
|
||||
|
||||
void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int64_t sequence)
|
||||
void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int32_t sequence)
|
||||
{
|
||||
uv_mutex_lock(&ebt->mutex);
|
||||
ebt_entry_t* entry = _ebt_get_entry(ebt, id);
|
||||
@@ -365,7 +363,7 @@ void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int64_t seq
|
||||
uv_mutex_unlock(&ebt->mutex);
|
||||
}
|
||||
|
||||
void tf_ssb_ebt_set_messages_received(tf_ssb_ebt_t* ebt, const char* id, int64_t sequence)
|
||||
void tf_ssb_ebt_set_messages_received(tf_ssb_ebt_t* ebt, const char* id, int32_t sequence)
|
||||
{
|
||||
uv_mutex_lock(&ebt->mutex);
|
||||
ebt_entry_t* entry = _ebt_get_entry(ebt, id);
|
||||
|
@@ -19,7 +19,7 @@ typedef struct _tf_ssb_ebt_clock_entry_t
|
||||
/** The identity. */
|
||||
char id[k_id_base64_len];
|
||||
/** The sequence number. */
|
||||
int64_t value;
|
||||
int32_t value;
|
||||
} tf_ssb_ebt_clock_entry_t;
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ tf_ssb_ebt_clock_t* tf_ssb_ebt_get_messages_to_send(tf_ssb_ebt_t* ebt);
|
||||
** @param id The identity to update.
|
||||
** @param sequence The maximum sequence number sent.
|
||||
*/
|
||||
void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int64_t sequence);
|
||||
void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int32_t sequence);
|
||||
|
||||
/**
|
||||
** Update the clock state indicating the messages that have been received for an account.
|
||||
@@ -84,7 +84,7 @@ void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int64_t seq
|
||||
** @param id The identity to update.
|
||||
** @param sequence The maximum sequence number received.
|
||||
*/
|
||||
void tf_ssb_ebt_set_messages_received(tf_ssb_ebt_t* ebt, const char* id, int64_t sequence);
|
||||
void tf_ssb_ebt_set_messages_received(tf_ssb_ebt_t* ebt, const char* id, int32_t sequence);
|
||||
|
||||
/**
|
||||
** Destroy an EBT instance.
|
||||
|
@@ -142,8 +142,7 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
|
||||
JSPropertyDescriptor desc;
|
||||
if (JS_GetOwnProperty(context, &desc, files, ptab[i].atom) == 1)
|
||||
{
|
||||
JSValue key = JS_AtomToString(context, ptab[i].atom);
|
||||
const char* file_name = JS_ToCString(context, key);
|
||||
const char* file_name = JS_AtomToCString(context, ptab[i].atom);
|
||||
const char* blob_id = JS_ToCString(context, desc.value);
|
||||
|
||||
uint8_t* file_blob = NULL;
|
||||
@@ -156,7 +155,6 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
|
||||
}
|
||||
|
||||
JS_FreeCString(context, file_name);
|
||||
JS_FreeValue(context, key);
|
||||
JS_FreeCString(context, blob_id);
|
||||
JS_FreeValue(context, desc.value);
|
||||
JS_FreeValue(context, desc.setter);
|
||||
|
15
src/ssb.h
15
src/ssb.h
@@ -323,7 +323,7 @@ void tf_ssb_run(tf_ssb_t* ssb);
|
||||
** @param previous_sequence The sequence number of the previous message in the feed. Optional.
|
||||
** @return The signed message.
|
||||
*/
|
||||
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message, const char* previous_id, int64_t previous_sequence);
|
||||
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message, const char* previous_id, int32_t previous_sequence);
|
||||
|
||||
/**
|
||||
** Get the server's identity.
|
||||
@@ -651,7 +651,7 @@ void tf_ssb_remove_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_
|
||||
** @param id The message identifier.
|
||||
** @param user_data The user data.
|
||||
*/
|
||||
typedef void(tf_ssb_message_added_callback_t)(tf_ssb_t* ssb, const char* author, int64_t sequence, const char* id, void* user_data);
|
||||
typedef void(tf_ssb_message_added_callback_t)(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, void* user_data);
|
||||
|
||||
/**
|
||||
** Register a callback called when a message is added to the database.
|
||||
@@ -678,7 +678,7 @@ void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_ca
|
||||
** @param id The message identity added.
|
||||
** @param message_with_keys The message added in the format required if keys are requested.
|
||||
*/
|
||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int64_t sequence, const char* id, JSValue message_with_keys);
|
||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_with_keys);
|
||||
|
||||
/**
|
||||
** Record that a new blob was stored.
|
||||
@@ -1006,15 +1006,6 @@ void tf_ssb_record_thread_busy(tf_ssb_t* ssb, bool busy);
|
||||
*/
|
||||
float tf_ssb_get_average_thread_percent(tf_ssb_t* ssb);
|
||||
|
||||
/**
|
||||
** Register a callback to be called when the main thread blocks for an
|
||||
** unreasonable amount of time.
|
||||
** @param ssb The SSB instance.
|
||||
** @param callback The callback to call.
|
||||
** @param user_data User data to pass to the callback.
|
||||
*/
|
||||
void tf_ssb_set_hitch_callback(tf_ssb_t* ssb, void (*callback)(const char* name, uint64_t duration_ns, void* user_data), void* user_data);
|
||||
|
||||
/**
|
||||
** Get the queue of messages in the progress of being stored.
|
||||
** @param ssb The SSB instance.
|
||||
|
12
src/ssb.js.c
12
src/ssb.js.c
@@ -241,7 +241,7 @@ static JSValue _tf_ssb_deleteIdentity(JSContext* context, JSValueConst this_val,
|
||||
{
|
||||
delete_identity_t* work = tf_malloc(sizeof(delete_identity_t) + user_length + 1);
|
||||
*work = (delete_identity_t) { 0 };
|
||||
snprintf(work->id, sizeof(work->id), "%s", *id == '@' ? id + 1 : id);
|
||||
tf_string_set(work->id, sizeof(work->id), *id == '@' ? id + 1 : id);
|
||||
memcpy(work->user, user, user_length + 1);
|
||||
result = JS_NewPromiseCapability(context, work->promise);
|
||||
tf_ssb_run_work(ssb, _tf_ssb_delete_identity_work, _tf_ssb_delete_identity_after_work, work);
|
||||
@@ -353,7 +353,7 @@ static JSValue _tf_ssb_swap_with_server_identity(JSContext* context, JSValueCons
|
||||
swap_with_server_identity_t* work = tf_malloc(sizeof(swap_with_server_identity_t) + user_length + 1);
|
||||
*work = (swap_with_server_identity_t) { 0 };
|
||||
tf_ssb_whoami(ssb, work->server_id, sizeof(work->server_id));
|
||||
snprintf(work->id, sizeof(work->id), "%s", id);
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
memcpy(work->user, user, user_length + 1);
|
||||
result = JS_NewPromiseCapability(context, work->promise);
|
||||
tf_ssb_run_work(ssb, _tf_ssb_swap_with_server_identity_work, _tf_ssb_swap_with_server_identity_after_work, work);
|
||||
@@ -489,7 +489,7 @@ static JSValue _tf_ssb_getPrivateKey(JSContext* context, JSValueConst this_val,
|
||||
get_private_key_t* work = tf_malloc(sizeof(get_private_key_t) + user_length + 1);
|
||||
*work = (get_private_key_t) { .context = context };
|
||||
memcpy(work->user, user, user_length + 1);
|
||||
snprintf(work->id, sizeof(work->id), "%s", id);
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
JSValue result = JS_NewPromiseCapability(context, work->promise);
|
||||
tf_ssb_run_work(ssb, _tf_ssb_get_private_key_work, _tf_ssb_get_private_key_after_work, work);
|
||||
|
||||
@@ -696,7 +696,7 @@ typedef struct _append_message_t
|
||||
uint8_t private_key[crypto_sign_SECRETKEYBYTES];
|
||||
bool got_private_key;
|
||||
char previous_id[512];
|
||||
int64_t previous_sequence;
|
||||
int32_t previous_sequence;
|
||||
JSContext* context;
|
||||
JSValue promise[2];
|
||||
JSValue message;
|
||||
@@ -766,7 +766,7 @@ static JSValue _tf_ssb_appendMessageWithIdentity(JSContext* context, JSValueCons
|
||||
append_message_t* work = tf_malloc(sizeof(append_message_t) + user_length + 1);
|
||||
*work = (append_message_t) { .context = context, .message = JS_DupValue(context, argv[2]) };
|
||||
memcpy(work->user, user, user_length + 1);
|
||||
snprintf(work->id, sizeof(work->id), "%s", id);
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
|
||||
JS_FreeCString(context, id);
|
||||
JS_FreeCString(context, user);
|
||||
@@ -1604,7 +1604,7 @@ static void _tf_ssb_cleanup_value(tf_ssb_t* ssb, void* user_data)
|
||||
JS_FreeValue(tf_ssb_get_context(ssb), callback);
|
||||
}
|
||||
|
||||
static void _tf_ssb_on_message_added_callback(tf_ssb_t* ssb, const char* author, int64_t sequence, const char* id, void* user_data)
|
||||
static void _tf_ssb_on_message_added_callback(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, void* user_data)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue callback = JS_MKPTR(JS_TAG_OBJECT, user_data);
|
||||
|
171
src/ssb.rpc.c
171
src/ssb.rpc.c
@@ -16,7 +16,7 @@
|
||||
#include <time.h>
|
||||
|
||||
static void _tf_ssb_connection_send_history_stream(
|
||||
tf_ssb_connection_t* connection, int32_t request_number, const char* author, int64_t sequence, bool keys, bool live, bool end_request);
|
||||
tf_ssb_connection_t* connection, int32_t request_number, const char* author, int32_t sequence, bool keys, bool live, bool end_request);
|
||||
static void _tf_ssb_rpc_send_peers_exchange(tf_ssb_connection_t* connection);
|
||||
static void _tf_ssb_rpc_start_delete_blobs(tf_ssb_t* ssb, int delay_ms);
|
||||
static void _tf_ssb_rpc_start_delete_feeds(tf_ssb_t* ssb, int delay_ms);
|
||||
@@ -134,7 +134,7 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
||||
*work = (blobs_get_work_t) {
|
||||
.request_number = request_number,
|
||||
};
|
||||
snprintf(work->id, sizeof(work->id), "%s", id);
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
tf_ssb_connection_schedule_idle(connection, id, _tf_ssb_blobs_get_callback, work);
|
||||
|
||||
JS_FreeCString(context, id);
|
||||
@@ -184,7 +184,7 @@ static void _tf_ssb_rpc_blobs_has(tf_ssb_connection_t* connection, uint8_t flags
|
||||
*work = (blobs_has_work_t) {
|
||||
.request_number = request_number,
|
||||
};
|
||||
snprintf(work->id, sizeof(work->id), "%s", id_str);
|
||||
tf_string_set(work->id, sizeof(work->id), id_str);
|
||||
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_blobs_has_work, _tf_ssb_rpc_blobs_has_after_work, work);
|
||||
|
||||
JS_FreeCString(context, id_str);
|
||||
@@ -239,7 +239,7 @@ static void _tf_ssb_request_blob_wants_work(tf_ssb_connection_t* connection, voi
|
||||
{
|
||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
snprintf(work->out_id[work->out_id_count], sizeof(work->out_id[work->out_id_count]), "%s", (const char*)sqlite3_column_text(statement, 0));
|
||||
tf_string_set(work->out_id[work->out_id_count], sizeof(work->out_id[work->out_id_count]), (const char*)sqlite3_column_text(statement, 0));
|
||||
work->out_id_count++;
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ static void _tf_ssb_request_blob_wants_after_work(tf_ssb_connection_t* connectio
|
||||
}
|
||||
if (work->out_id_count)
|
||||
{
|
||||
snprintf(blob_wants->last_id, sizeof(blob_wants->last_id), "%s", work->out_id[work->out_id_count - 1]);
|
||||
tf_string_set(blob_wants->last_id, sizeof(blob_wants->last_id), work->out_id[work->out_id_count - 1]);
|
||||
}
|
||||
}
|
||||
tf_free(work);
|
||||
@@ -349,11 +349,6 @@ static void _tf_ssb_rpc_tunnel_cleanup(tf_ssb_t* ssb, void* user_data)
|
||||
static void _tf_ssb_rpc_tunnel_connect(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);
|
||||
if (!tf_ssb_is_room(ssb))
|
||||
{
|
||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "tunnel.connect");
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
||||
JSValue arg_array = JS_GetPropertyStr(context, args, "args");
|
||||
@@ -363,6 +358,12 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
|
||||
JSValue target = JS_GetPropertyStr(context, arg, "target");
|
||||
|
||||
if (JS_IsUndefined(origin) && !JS_IsUndefined(portal) && !JS_IsUndefined(target))
|
||||
{
|
||||
if (!tf_ssb_is_room(ssb))
|
||||
{
|
||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "tunnel.connect");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* target_str = JS_ToCString(context, target);
|
||||
|
||||
@@ -402,7 +403,8 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
|
||||
.request_number = -request_number,
|
||||
};
|
||||
tf_ssb_connection_add_request(connection, -request_number, "tunnel.connect", _tf_ssb_rpc_tunnel_callback, _tf_ssb_rpc_tunnel_cleanup, data0, target_connection);
|
||||
tf_ssb_connection_add_request(target_connection, tunnel_request_number, "tunnel.connect", _tf_ssb_rpc_tunnel_callback, _tf_ssb_rpc_tunnel_cleanup, data1, connection);
|
||||
tf_ssb_connection_add_request(
|
||||
target_connection, tunnel_request_number, "tunnel.connect", _tf_ssb_rpc_tunnel_callback, _tf_ssb_rpc_tunnel_cleanup, data1, connection);
|
||||
|
||||
JS_FreeValue(context, message);
|
||||
JS_FreeCString(context, portal_str);
|
||||
@@ -413,6 +415,7 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
|
||||
}
|
||||
JS_FreeCString(context, target_str);
|
||||
}
|
||||
}
|
||||
else if (!JS_IsUndefined(origin) && !JS_IsUndefined(portal) && !JS_IsUndefined(target))
|
||||
{
|
||||
const char* origin_str = JS_ToCString(context, origin);
|
||||
@@ -611,7 +614,7 @@ static void _tf_ssb_rpc_connection_blobs_get(tf_ssb_connection_t* connection, co
|
||||
{
|
||||
blobs_get_t* get = tf_malloc(sizeof(blobs_get_t) + size);
|
||||
*get = (blobs_get_t) { .ssb = tf_ssb_connection_get_ssb(connection), .connection = connection, .expected_size = size };
|
||||
snprintf(get->id, sizeof(get->id), "%s", blob_id);
|
||||
tf_string_set(get->id, sizeof(get->id), blob_id);
|
||||
memset(get->buffer, 0, size);
|
||||
|
||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||
@@ -713,7 +716,7 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(
|
||||
{
|
||||
for (uint32_t i = 0; i < plen; ++i)
|
||||
{
|
||||
JSValue key = JS_AtomToString(context, ptab[i].atom);
|
||||
const char* blob_id = JS_AtomToCString(context, ptab[i].atom);
|
||||
JSPropertyDescriptor desc;
|
||||
JSValue key_value = JS_NULL;
|
||||
if (JS_GetOwnProperty(context, &desc, args, ptab[i].atom) == 1)
|
||||
@@ -722,7 +725,6 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(
|
||||
JS_FreeValue(context, desc.setter);
|
||||
JS_FreeValue(context, desc.getter);
|
||||
}
|
||||
const char* blob_id = JS_ToCString(context, key);
|
||||
int64_t size = 0;
|
||||
JS_ToInt64(context, &size, key_value);
|
||||
if (--blob_wants->wants_sent == 0)
|
||||
@@ -736,18 +738,17 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(
|
||||
.connection = connection,
|
||||
.size = size,
|
||||
};
|
||||
snprintf(work->blob_id, sizeof(work->blob_id), "%s", blob_id);
|
||||
tf_string_set(work->blob_id, sizeof(work->blob_id), blob_id);
|
||||
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_connection_blobs_create_wants_work, _tf_ssb_rpc_connection_blobs_create_wants_after_work, work);
|
||||
}
|
||||
else
|
||||
{
|
||||
blob_get_t* get = tf_malloc(sizeof(blob_get_t));
|
||||
*get = (blob_get_t) { .size = size };
|
||||
snprintf(get->id, sizeof(get->id), "%s", blob_id);
|
||||
tf_string_set(get->id, sizeof(get->id), blob_id);
|
||||
tf_ssb_connection_schedule_idle(connection, blob_id, _tf_ssb_rpc_connection_blobs_get_idle, get);
|
||||
}
|
||||
JS_FreeCString(context, blob_id);
|
||||
JS_FreeValue(context, key);
|
||||
JS_FreeValue(context, key_value);
|
||||
}
|
||||
for (uint32_t i = 0; i < plen; ++i)
|
||||
@@ -862,13 +863,13 @@ typedef struct _tf_ssb_connection_send_history_stream_t
|
||||
{
|
||||
int32_t request_number;
|
||||
char author[k_id_base64_len];
|
||||
int64_t sequence;
|
||||
int32_t sequence;
|
||||
bool keys;
|
||||
bool live;
|
||||
bool end_request;
|
||||
|
||||
bool out_finished;
|
||||
int64_t out_max_sequence_seen;
|
||||
int32_t out_max_sequence_seen;
|
||||
char** out_messages;
|
||||
int out_messages_count;
|
||||
} tf_ssb_connection_send_history_stream_t;
|
||||
@@ -889,8 +890,8 @@ static void _tf_ssb_connection_send_history_stream_work(tf_ssb_connection_t* con
|
||||
"sequence < ?3 ORDER BY sequence",
|
||||
-1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, request->author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, request->sequence) == SQLITE_OK &&
|
||||
sqlite3_bind_int64(statement, 3, request->sequence + k_max) == SQLITE_OK)
|
||||
if (sqlite3_bind_text(statement, 1, request->author, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, request->sequence) == SQLITE_OK &&
|
||||
sqlite3_bind_int(statement, 3, request->sequence + k_max) == SQLITE_OK)
|
||||
{
|
||||
JSMallocFunctions funcs = { 0 };
|
||||
tf_get_js_malloc_functions(&funcs);
|
||||
@@ -901,7 +902,7 @@ static void _tf_ssb_connection_send_history_stream_work(tf_ssb_connection_t* con
|
||||
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
||||
{
|
||||
JSValue message = JS_UNDEFINED;
|
||||
request->out_max_sequence_seen = sqlite3_column_int64(statement, 3);
|
||||
request->out_max_sequence_seen = sqlite3_column_int(statement, 3);
|
||||
|
||||
JSValue formatted = tf_ssb_format_message(context, (const char*)sqlite3_column_text(statement, 0), (const char*)sqlite3_column_text(statement, 1),
|
||||
sqlite3_column_int64(statement, 3), sqlite3_column_double(statement, 4), (const char*)sqlite3_column_text(statement, 5),
|
||||
@@ -996,7 +997,7 @@ static void _tf_ssb_connection_send_history_stream_callback(tf_ssb_connection_t*
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_send_history_stream(
|
||||
tf_ssb_connection_t* connection, int32_t request_number, const char* author, int64_t sequence, bool keys, bool live, bool end_request)
|
||||
tf_ssb_connection_t* connection, int32_t request_number, const char* author, int32_t sequence, bool keys, bool live, bool end_request)
|
||||
{
|
||||
if (tf_ssb_connection_is_connected(connection) && !tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)) && !tf_ssb_connection_is_closing(connection))
|
||||
{
|
||||
@@ -1008,7 +1009,7 @@ static void _tf_ssb_connection_send_history_stream(
|
||||
.live = live,
|
||||
.end_request = end_request,
|
||||
};
|
||||
snprintf(async->author, sizeof(async->author), "%s", author);
|
||||
tf_string_set(async->author, sizeof(async->author), author);
|
||||
tf_ssb_connection_schedule_idle(connection, author, _tf_ssb_connection_send_history_stream_callback, async);
|
||||
}
|
||||
}
|
||||
@@ -1035,8 +1036,8 @@ static void _tf_ssb_rpc_createHistoryStream(
|
||||
JSValue live = JS_GetPropertyStr(context, arg, "live");
|
||||
bool is_keys = JS_IsUndefined(keys) || JS_ToBool(context, keys) > 0;
|
||||
bool is_live = JS_ToBool(context, live) > 0 && (tf_ssb_connection_get_flags(connection) & k_tf_ssb_connect_flag_one_shot) == 0;
|
||||
int64_t sequence = 0;
|
||||
JS_ToInt64(context, &sequence, seq);
|
||||
int32_t sequence = 0;
|
||||
JS_ToInt32(context, &sequence, seq);
|
||||
const char* author = JS_ToCString(context, id);
|
||||
|
||||
_tf_ssb_connection_send_history_stream(connection, -request_number, author, sequence, is_keys, is_live, true);
|
||||
@@ -1257,7 +1258,7 @@ typedef struct _invite_use_t
|
||||
;
|
||||
uint8_t private_key[512];
|
||||
char previous_id[64];
|
||||
int64_t previous_sequence;
|
||||
int32_t previous_sequence;
|
||||
|
||||
char host[256];
|
||||
int port;
|
||||
@@ -1337,7 +1338,7 @@ static void _tf_ssb_rpc_invite_use_callback(
|
||||
.ssb = ssb,
|
||||
.port = tf_ssb_connection_get_port(connection),
|
||||
};
|
||||
snprintf(work->host, sizeof(work->host), "%s", tf_ssb_connection_get_host(connection));
|
||||
tf_string_set(work->host, sizeof(work->host), tf_ssb_connection_get_host(connection));
|
||||
tf_ssb_whoami(ssb, work->author, sizeof(work->author));
|
||||
tf_ssb_get_private_key(ssb, work->private_key, sizeof(work->private_key));
|
||||
tf_ssb_connection_get_id(connection, work->pub, sizeof(work->pub));
|
||||
@@ -1481,12 +1482,47 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
|
||||
return;
|
||||
}
|
||||
int64_t start_ns = uv_hrtime();
|
||||
db = tf_ssb_acquire_db_writer(ssb);
|
||||
sqlite3_stmt* statement;
|
||||
int64_t now = (int64_t)time(NULL) * 1000ULL;
|
||||
int64_t timestamp = now - age * 1000ULL;
|
||||
sqlite3_stmt* statement;
|
||||
|
||||
char** ids = NULL;
|
||||
int ids_count = 0;
|
||||
|
||||
db = tf_ssb_acquire_db_reader(ssb);
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"SELECT blobs.id FROM blobs "
|
||||
"JOIN messages_refs ON blobs.id = messages_refs.ref "
|
||||
"JOIN messages ON messages.id = messages_refs.message "
|
||||
"WHERE blobs.created < ?1 / 1000 "
|
||||
"GROUP BY blobs.id HAVING MAX(messages.timestamp) < ?1 LIMIT ?2",
|
||||
-1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
const int k_limit = 128;
|
||||
if (sqlite3_bind_int64(statement, 1, timestamp) == SQLITE_OK && sqlite3_bind_int(statement, 2, k_limit) == SQLITE_OK)
|
||||
{
|
||||
int r = SQLITE_OK;
|
||||
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
||||
{
|
||||
ids = tf_realloc(ids, sizeof(char*) * (ids_count + 1));
|
||||
ids[ids_count++] = tf_strdup((const char*)sqlite3_column_text(statement, 0));
|
||||
}
|
||||
if (r != SQLITE_DONE)
|
||||
{
|
||||
tf_printf("_tf_ssb_rpc_delete_blobs_work: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
|
||||
int deleted = 0;
|
||||
if (ids_count)
|
||||
{
|
||||
db = tf_ssb_acquire_db_writer(ssb);
|
||||
if (sqlite3_prepare_v2(db, "DELETE FROM blob_wants_cache WHERE source IS NULL and timestamp < ?1", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_int64(statement, 1, timestamp) == SQLITE_OK)
|
||||
@@ -1498,16 +1534,11 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"DELETE FROM blobs WHERE blobs.id IN ("
|
||||
" SELECT blobs.id FROM blobs "
|
||||
" JOIN messages_refs ON blobs.id = messages_refs.ref "
|
||||
" JOIN messages ON messages.id = messages_refs.message "
|
||||
" WHERE blobs.created < ?1 / 1000 "
|
||||
" GROUP BY blobs.id HAVING MAX(messages.timestamp) < ?1 LIMIT ?2)",
|
||||
-1, &statement, NULL) == SQLITE_OK)
|
||||
if (sqlite3_prepare_v2(db, "DELETE FROM blobs WHERE blobs.id = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_int64(statement, 1, timestamp) == SQLITE_OK && sqlite3_bind_int(statement, 2, k_limit) == SQLITE_OK)
|
||||
for (int i = 0; i < ids_count; i++)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, ids[i], -1, NULL) == SQLITE_OK)
|
||||
{
|
||||
int r = sqlite3_step(statement);
|
||||
if (r != SQLITE_DONE)
|
||||
@@ -1516,16 +1547,21 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("_tf_ssb_rpc_delete_blobs_work: %d rows\n", sqlite3_changes(db));
|
||||
deleted += sqlite3_changes(db);
|
||||
}
|
||||
deleted = sqlite3_changes(db);
|
||||
}
|
||||
sqlite3_reset(statement);
|
||||
tf_free(ids[i]);
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
tf_free(ids);
|
||||
}
|
||||
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
|
||||
tf_printf("Deleted %d blobs in %d ms.\n", deleted, (int)delete->duration_ms);
|
||||
}
|
||||
@@ -1583,15 +1619,39 @@ static void _tf_ssb_rpc_delete_feeds_work(tf_ssb_t* ssb, void* user_data)
|
||||
JS_FreeValue(context, json);
|
||||
JS_FreeValue(context, array);
|
||||
|
||||
db = tf_ssb_acquire_db_writer(ssb);
|
||||
sqlite3_stmt* statement;
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"DELETE FROM messages WHERE id IN ("
|
||||
" SELECT id FROM messages WHERE author NOT IN (SELECT value FROM json_each(?)) ORDER BY rowid DESC LIMIT 1024"
|
||||
")",
|
||||
-1, &statement, NULL) == SQLITE_OK)
|
||||
|
||||
char** ids = NULL;
|
||||
int ids_count = 0;
|
||||
|
||||
db = tf_ssb_acquire_db_reader(ssb);
|
||||
if (sqlite3_prepare_v2(db, "SELECT id FROM messages WHERE author NOT IN (SELECT value FROM json_each(?)) ORDER BY rowid DESC LIMIT 1024", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, arg, -1, NULL) == SQLITE_OK)
|
||||
{
|
||||
int r = SQLITE_OK;
|
||||
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
||||
{
|
||||
ids = tf_realloc(ids, sizeof(char*) * (ids_count + 1));
|
||||
ids[ids_count++] = tf_strdup((const char*)sqlite3_column_text(statement, 0));
|
||||
}
|
||||
if (r != SQLITE_DONE)
|
||||
{
|
||||
tf_printf("deleting messages: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
|
||||
if (ids_count)
|
||||
{
|
||||
db = tf_ssb_acquire_db_writer(ssb);
|
||||
if (sqlite3_prepare_v2(db, "DELETE FROM messages WHERE id = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
for (int i = 0; i < ids_count; i++)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, ids[i], -1, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_step(statement) != SQLITE_DONE)
|
||||
{
|
||||
@@ -1599,12 +1659,17 @@ static void _tf_ssb_rpc_delete_feeds_work(tf_ssb_t* ssb, void* user_data)
|
||||
}
|
||||
else
|
||||
{
|
||||
delete->deleted += sqlite3_changes(db);
|
||||
delete->deleted++;
|
||||
}
|
||||
}
|
||||
sqlite3_reset(statement);
|
||||
tf_free(ids[i]);
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
tf_free(ids);
|
||||
}
|
||||
|
||||
JS_FreeCString(context, arg);
|
||||
|
||||
@@ -1716,7 +1781,7 @@ static void _tf_ssb_rpc_peers_exchange_internal(
|
||||
{
|
||||
for (uint32_t i = 0; i < plen; ++i)
|
||||
{
|
||||
JSValue key = JS_AtomToString(context, ptab[i].atom);
|
||||
const char* connection = JS_AtomToCString(context, ptab[i].atom);
|
||||
JSPropertyDescriptor desc;
|
||||
JSValue key_value = JS_NULL;
|
||||
if (JS_GetOwnProperty(context, &desc, args, ptab[i].atom) == 1)
|
||||
@@ -1725,12 +1790,10 @@ static void _tf_ssb_rpc_peers_exchange_internal(
|
||||
JS_FreeValue(context, desc.setter);
|
||||
JS_FreeValue(context, desc.getter);
|
||||
}
|
||||
const char* connection = JS_ToCString(context, key);
|
||||
int64_t timestamp = 0;
|
||||
JS_ToInt64(context, ×tamp, key_value);
|
||||
/* ADD BROADCAST connection: timestamp */
|
||||
JS_FreeCString(context, connection);
|
||||
JS_FreeValue(context, key);
|
||||
JS_FreeValue(context, key_value);
|
||||
}
|
||||
for (uint32_t i = 0; i < plen; ++i)
|
||||
@@ -1781,7 +1844,7 @@ typedef struct _invite_t
|
||||
int32_t request_number;
|
||||
bool accepted;
|
||||
char previous_id[256];
|
||||
int64_t previous_sequence;
|
||||
int32_t previous_sequence;
|
||||
char* message;
|
||||
} invite_t;
|
||||
|
||||
@@ -1875,7 +1938,7 @@ static void _tf_ssb_rpc_invite_use(tf_ssb_connection_t* connection, uint8_t flag
|
||||
JSValue feed = JS_GetPropertyStr(context, object, "feed");
|
||||
tf_ssb_connection_get_id(connection, work->invite_public_key, sizeof(work->invite_public_key));
|
||||
const char* id = JS_ToCString(context, feed);
|
||||
snprintf(work->id, sizeof(work->id), "%s", id);
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
JS_FreeCString(context, id);
|
||||
JS_FreeValue(context, feed);
|
||||
JS_FreeValue(context, object);
|
||||
@@ -1883,7 +1946,7 @@ 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);
|
||||
}
|
||||
|
||||
static void _tf_ssb_rpc_message_added_callback(tf_ssb_t* ssb, const char* author, int64_t sequence, const char* id, void* user_data)
|
||||
static void _tf_ssb_rpc_message_added_callback(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, void* user_data)
|
||||
{
|
||||
tf_ssb_connection_t* connections[256];
|
||||
int count = tf_ssb_get_connections(ssb, connections, tf_countof(connections));
|
||||
|
@@ -114,7 +114,7 @@ static int _ssb_test_count_messages(tf_ssb_t* ssb)
|
||||
return count.count;
|
||||
}
|
||||
|
||||
static void _message_added(tf_ssb_t* ssb, const char* author, int64_t sequence, const char* id, void* user_data)
|
||||
static void _message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, void* user_data)
|
||||
{
|
||||
++*(int*)user_data;
|
||||
}
|
||||
@@ -811,7 +811,7 @@ static void _break_in_a_bit(tf_ssb_t* ssb, tf_ssb_connection_t* connection, cons
|
||||
.data = data,
|
||||
},
|
||||
};
|
||||
snprintf(data->id, sizeof(data->id), "%s", id);
|
||||
tf_string_set(data->id, sizeof(data->id), id);
|
||||
uv_timer_init(tf_ssb_get_loop(ssb), &data->timer);
|
||||
uv_timer_start(&data->timer, _close_callback, 3000, 0);
|
||||
}
|
||||
@@ -1046,11 +1046,11 @@ void tf_ssb_test_publish(const tf_test_options_t* options)
|
||||
static void _test_print_identity(const char* identity, void* user_data)
|
||||
{
|
||||
tf_ssb_t* ssb = user_data;
|
||||
int64_t sequence = -1;
|
||||
int32_t sequence = -1;
|
||||
char id[k_id_base64_len] = { 0 };
|
||||
snprintf(id, sizeof(id), "@%s", identity);
|
||||
tf_ssb_db_get_latest_message_by_author(ssb, id, &sequence, NULL, 0);
|
||||
tf_printf("IDENTITY %s: %d\n", id, (int)sequence);
|
||||
tf_printf("IDENTITY %s: %d\n", id, sequence);
|
||||
}
|
||||
|
||||
void tf_ssb_test_replicate(const tf_test_options_t* options)
|
||||
@@ -1154,7 +1154,7 @@ void tf_ssb_test_replicate(const tf_test_options_t* options)
|
||||
JSValue obj = JS_NewObject(context1);
|
||||
JS_SetPropertyStr(context1, obj, "type", JS_NewString(context1, "contact"));
|
||||
char self[k_id_base64_len];
|
||||
snprintf(self, sizeof(self), "%s", id1);
|
||||
tf_string_set(self, sizeof(self), id1);
|
||||
char contact[k_id_base64_len];
|
||||
snprintf(contact, sizeof(contact), "@%s", public[0]);
|
||||
JS_SetPropertyStr(context1, obj, "contact", JS_NewString(context1, contact));
|
||||
@@ -1377,6 +1377,8 @@ void tf_ssb_test_invite(const tf_test_options_t* options)
|
||||
while (count0 != 3 || count1 != 3)
|
||||
{
|
||||
uv_run(&loop, UV_RUN_ONCE);
|
||||
|
||||
tf_printf("count0=%d count1=%d\n", count0, count1);
|
||||
}
|
||||
tf_ssb_set_main_thread(ssb0, false);
|
||||
tf_ssb_set_main_thread(ssb1, false);
|
||||
@@ -1434,9 +1436,9 @@ void tf_ssb_test_triggers(const tf_test_options_t* options)
|
||||
clock_gettime(CLOCK_REALTIME, &end_time);
|
||||
tf_printf("insert = %f seconds\n", (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec - start_time.tv_nsec) / 1e9);
|
||||
|
||||
int64_t max_sequence = 0;
|
||||
int32_t max_sequence = 0;
|
||||
tf_ssb_db_get_latest_message_by_author(ssb0, id0, &max_sequence, NULL, 0);
|
||||
tf_printf("max_sequence=%" PRId64 "\n", max_sequence);
|
||||
tf_printf("max_sequence=%d\n", max_sequence);
|
||||
assert(max_sequence == 5);
|
||||
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb0);
|
||||
@@ -1445,7 +1447,7 @@ void tf_ssb_test_triggers(const tf_test_options_t* options)
|
||||
|
||||
max_sequence = 0;
|
||||
tf_ssb_db_get_latest_message_by_author(ssb0, id0, &max_sequence, NULL, 0);
|
||||
tf_printf("max_sequence=%" PRId64 "\n", max_sequence);
|
||||
tf_printf("max_sequence=%d\n", max_sequence);
|
||||
assert(max_sequence == 4);
|
||||
|
||||
tf_ssb_acquire_db_writer(ssb0);
|
||||
@@ -1454,7 +1456,7 @@ void tf_ssb_test_triggers(const tf_test_options_t* options)
|
||||
|
||||
max_sequence = 0;
|
||||
tf_ssb_db_get_latest_message_by_author(ssb0, id0, &max_sequence, NULL, 0);
|
||||
tf_printf("max_sequence=%" PRId64 "\n", max_sequence);
|
||||
tf_printf("max_sequence=%d\n", max_sequence);
|
||||
assert(max_sequence == 0);
|
||||
|
||||
uv_run(&loop, UV_RUN_DEFAULT);
|
||||
@@ -1619,7 +1621,7 @@ void tf_ssb_test_following_perf(const tf_test_options_t* options)
|
||||
|
||||
uint64_t start = uv_hrtime();
|
||||
int count = 0;
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const char** ids = tf_ssb_db_get_all_visible_identities(ssb, 2);
|
||||
while (ids[count])
|
||||
|
63
src/task.c
63
src/task.c
@@ -84,16 +84,10 @@ typedef struct _promise_stack_t
|
||||
uint32_t hash;
|
||||
int count;
|
||||
const char* stack;
|
||||
void* cstack[32];
|
||||
void* cstack[31];
|
||||
int cstack_count;
|
||||
} promise_stack_t;
|
||||
|
||||
typedef struct _hitch_t
|
||||
{
|
||||
char name[256];
|
||||
uint64_t duration_ns;
|
||||
} hitch_t;
|
||||
|
||||
typedef struct _timeout_t timeout_t;
|
||||
|
||||
typedef struct _timeout_t
|
||||
@@ -170,8 +164,6 @@ typedef struct _tf_task_t
|
||||
|
||||
timeout_t* timeouts;
|
||||
|
||||
hitch_t hitches[32];
|
||||
|
||||
uint64_t last_gc_ns;
|
||||
int64_t last_gc_duration_ns;
|
||||
} tf_task_t;
|
||||
@@ -558,6 +550,7 @@ static JSValue _task_invokeExport_internal(tf_taskstub_t* from, tf_task_t* to, e
|
||||
}
|
||||
|
||||
result = JS_Call(to->_context, function, this_val, length - 1, argument_array);
|
||||
tf_task_check_jobs(to);
|
||||
tf_trace_end(to->_trace);
|
||||
|
||||
JS_FreeValue(to->_context, this_val);
|
||||
@@ -930,28 +923,6 @@ char* tf_task_get_debug(tf_task_t* task)
|
||||
return result;
|
||||
}
|
||||
|
||||
char* tf_task_get_hitches(tf_task_t* task)
|
||||
{
|
||||
JSContext* context = task->_context;
|
||||
tf_trace_begin(task->_trace, __func__);
|
||||
JSValue object = JS_NewObject(context);
|
||||
for (int i = 0; i < tf_countof(task->hitches); i++)
|
||||
{
|
||||
if (*task->hitches[i].name)
|
||||
{
|
||||
JS_SetPropertyStr(context, object, task->hitches[i].name, JS_NewFloat64(context, task->hitches[i].duration_ns / 1e9));
|
||||
}
|
||||
}
|
||||
JSValue json = JS_JSONStringify(context, object, JS_NULL, JS_NewInt32(context, 2));
|
||||
const char* string = JS_ToCString(context, json);
|
||||
char* result = tf_strdup(string);
|
||||
JS_FreeCString(context, string);
|
||||
JS_FreeValue(context, json);
|
||||
JS_FreeValue(context, object);
|
||||
tf_trace_end(task->_trace);
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValue _tf_task_getFile(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
tf_task_t* task = JS_GetContextOpaque(context);
|
||||
@@ -1196,7 +1167,7 @@ static JSValue _tf_task_executeSource(tf_task_t* task, const char* source, const
|
||||
JSValue result = JS_Eval(task->_context, source, strlen(source), name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_ASYNC);
|
||||
if (!*task->_scriptName)
|
||||
{
|
||||
snprintf(task->_scriptName, sizeof(task->_scriptName), "%s", name);
|
||||
tf_string_set(task->_scriptName, sizeof(task->_scriptName), name);
|
||||
}
|
||||
tf_trace_end(task->_trace);
|
||||
return result;
|
||||
@@ -1250,6 +1221,7 @@ static void _add_promise_stack(tf_task_t* task, uint32_t hash, const char* stack
|
||||
{
|
||||
memmove(task->_promise_stacks + index + 1, task->_promise_stacks + index, sizeof(promise_stack_t) * (task->_promise_stack_count - index));
|
||||
}
|
||||
count = tf_min(count, tf_countof(task->_promise_stacks[index].cstack));
|
||||
task->_promise_stacks[index] = (promise_stack_t) { .hash = hash, .stack = tf_strdup(stack), .count = 1, .cstack_count = count };
|
||||
memcpy(task->_promise_stacks[index].cstack, buffer, sizeof(void*) * count);
|
||||
task->_promise_stack_count++;
|
||||
@@ -1291,7 +1263,7 @@ JSValue tf_task_allocate_promise(tf_task_t* task, promiseid_t* out_promise)
|
||||
size_t length = 0;
|
||||
const char* stack = JS_ToCStringLen(task->_context, &length, stack_value);
|
||||
stack_hash = tf_util_fnv32a((const void*)stack, (int)length, 0);
|
||||
void* buffer[32];
|
||||
void* buffer[31];
|
||||
int count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer));
|
||||
stack_hash = tf_util_fnv32a((const void*)buffer, sizeof(void*) * count, stack_hash);
|
||||
_add_promise_stack(task, stack_hash, stack, buffer, count);
|
||||
@@ -1666,24 +1638,6 @@ static void _tf_task_trace_to_parent(tf_trace_t* trace, const char* buffer, size
|
||||
tf_packetstream_send(tf_taskstub_get_stream(task->_parent), kTaskTrace, buffer, size);
|
||||
}
|
||||
|
||||
static void _tf_task_record_hitch(const char* name, uint64_t duration_ns, void* user_data)
|
||||
{
|
||||
tf_task_t* task = user_data;
|
||||
for (int i = 0; i < tf_countof(task->hitches); i++)
|
||||
{
|
||||
if (duration_ns > task->hitches[i].duration_ns)
|
||||
{
|
||||
if (i + 1 < tf_countof(task->hitches))
|
||||
{
|
||||
memmove(task->hitches + i + 1, task->hitches + i, sizeof(hitch_t) * (tf_countof(task->hitches) - i - 1));
|
||||
}
|
||||
snprintf(task->hitches[i].name, sizeof(task->hitches[i].name), "%s", name);
|
||||
task->hitches[i].duration_ns = duration_ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tf_task_activate(tf_task_t* task)
|
||||
{
|
||||
assert(!task->_activated);
|
||||
@@ -1717,7 +1671,6 @@ void tf_task_activate(tf_task_t* task)
|
||||
tf_ssb_set_trace(task->_ssb, task->_trace);
|
||||
tf_ssb_register(context, task->_ssb);
|
||||
tf_api_register(context);
|
||||
tf_ssb_set_hitch_callback(task->_ssb, _tf_task_record_hitch, task);
|
||||
|
||||
if (task->_args)
|
||||
{
|
||||
@@ -2015,7 +1968,7 @@ void tf_task_set_ssb_network_key(tf_task_t* task, const char* network_key)
|
||||
|
||||
void tf_task_set_db_path(tf_task_t* task, const char* db_path)
|
||||
{
|
||||
snprintf(task->_db_path, sizeof(task->_db_path), "%s", db_path);
|
||||
tf_string_set(task->_db_path, sizeof(task->_db_path), db_path);
|
||||
}
|
||||
|
||||
void tf_task_set_zip_path(tf_task_t* task, const char* zip_path)
|
||||
@@ -2025,7 +1978,7 @@ void tf_task_set_zip_path(tf_task_t* task, const char* zip_path)
|
||||
unzClose(task->_zip);
|
||||
task->_zip = NULL;
|
||||
}
|
||||
snprintf(task->_zip_path, sizeof(task->_zip_path), "%s", zip_path);
|
||||
tf_string_set(task->_zip_path, sizeof(task->_zip_path), zip_path);
|
||||
if (zip_path)
|
||||
{
|
||||
task->_zip = unzOpen(zip_path);
|
||||
@@ -2035,7 +1988,7 @@ void tf_task_set_zip_path(tf_task_t* task, const char* zip_path)
|
||||
|
||||
void tf_task_set_root_path(tf_task_t* task, const char* path)
|
||||
{
|
||||
snprintf(task->_root_path, sizeof(task->_root_path), "%s", path ? path : "");
|
||||
tf_string_set(task->_root_path, sizeof(task->_root_path), path ? path : "");
|
||||
}
|
||||
|
||||
const char* tf_task_get_zip_path(tf_task_t* task)
|
||||
|
@@ -319,13 +319,6 @@ bool tf_task_send_error_to_parent(tf_task_t* task, JSValue error);
|
||||
*/
|
||||
char* tf_task_get_debug(tf_task_t* task);
|
||||
|
||||
/**
|
||||
** Get a report of hitches that occurred.
|
||||
** @param task The task.
|
||||
** @return A JSON report of recent hitches that must be freed with tf_free().
|
||||
*/
|
||||
char* tf_task_get_hitches(tf_task_t* task);
|
||||
|
||||
/**
|
||||
** A callback used to start an Android service.
|
||||
** @param pipe_fd A file descriptor with which to communicate with the invoking
|
||||
|
@@ -104,7 +104,7 @@ void tf_trace_destroy(tf_trace_t* trace)
|
||||
|
||||
void tf_trace_set_process_name(tf_trace_t* trace, const char* name)
|
||||
{
|
||||
snprintf(trace->process_name, sizeof(trace->process_name), "%s", name);
|
||||
tf_string_set(trace->process_name, sizeof(trace->process_name), name);
|
||||
}
|
||||
|
||||
void tf_trace_raw(tf_trace_t* trace, const char* buffer, size_t size)
|
||||
|
@@ -500,11 +500,12 @@ void tf_util_document_settings(const char* line_prefix)
|
||||
JSValue tf_util_new_uint8_array(JSContext* context, const uint8_t* data, size_t size)
|
||||
{
|
||||
JSValue array_buffer = JS_NewArrayBufferCopy(context, data, size);
|
||||
JSValue global = JS_GetGlobalObject(context);
|
||||
JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array");
|
||||
JSValue result = JS_CallConstructor(context, constructor, 1, &array_buffer);
|
||||
JS_FreeValue(context, constructor);
|
||||
JS_FreeValue(context, global);
|
||||
JSValue args[] = {
|
||||
array_buffer,
|
||||
JS_NewInt64(context, 0),
|
||||
JS_NewInt64(context, size),
|
||||
};
|
||||
JSValue result = JS_NewTypedArray(context, tf_countof(args), args, JS_TYPED_ARRAY_UINT8C);
|
||||
JS_FreeValue(context, array_buffer);
|
||||
return result;
|
||||
}
|
||||
@@ -612,7 +613,7 @@ static int _tf_util_backtrace_single_callback(void* data, uintptr_t pc, const ch
|
||||
{
|
||||
char** stack = data;
|
||||
char line[256];
|
||||
int length = snprintf(line, sizeof(line), "%s", function);
|
||||
int length = (int)tf_string_set(line, sizeof(line), function);
|
||||
int current = *stack ? strlen(*stack) : 0;
|
||||
*stack = tf_resize_vec(*stack, current + length + 1);
|
||||
memcpy(*stack + current, line, length + 1);
|
||||
@@ -700,3 +701,18 @@ uint32_t tf_util_fnv32a(const void* buffer, int length, uint32_t start)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t tf_string_set(char* buffer, size_t size, const char* string)
|
||||
{
|
||||
size_t length = string ? strlen(string) : 0;
|
||||
length = tf_min(length, size - 1);
|
||||
if (size)
|
||||
{
|
||||
if (length)
|
||||
{
|
||||
memcpy(buffer, string, length);
|
||||
}
|
||||
buffer[length] = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
@@ -233,4 +233,13 @@ bool tf_util_is_mobile();
|
||||
*/
|
||||
uint32_t tf_util_fnv32a(const void* buffer, int length, uint32_t start);
|
||||
|
||||
/**
|
||||
** Populate a string buffer, truncating if necessary.
|
||||
** @param buffer The buffer.
|
||||
** @param size The size of the buffer.
|
||||
** @param string The value to set.
|
||||
** @return The number of bytes set, not including the NULL terminator.
|
||||
*/
|
||||
size_t tf_string_set(char* buffer, size_t size, const char* string);
|
||||
|
||||
/** @} */
|
||||
|
@@ -1,2 +1,2 @@
|
||||
#define VERSION_NUMBER "0.0.32-wip"
|
||||
#define VERSION_NUMBER "0.0.32"
|
||||
#define VERSION_NAME "This program kills fascists."
|
||||
|
Reference in New Issue
Block a user