24 Commits

Author SHA1 Message Date
8f51eb63b0 ssb: More experimenting with the unread status strategy.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 22m35s
2024-12-26 19:36:04 -05:00
855f5f7af4 ssb: Before destroying a connection, show a message on why it is going away in the UI.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 20m6s
2024-12-24 17:23:22 -05:00
c85dd2655c ssb: Strip out the old disconnection debug information.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 20m15s
2024-12-24 16:44:52 -05:00
fb0e4060cd ssb: Instrument some more callbacks for hitches.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2024-12-24 16:33:08 -05:00
707b4990a6 build: Not all the toolchains support -Oz. Oh well.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 20m3s
2024-12-24 15:01:09 -05:00
9c8b922069 build: Use all the tricks to make release smaller on all the platforms.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 2m15s
2024-12-24 14:47:33 -05:00
d4b421421d ssb: prettier. 2024-12-24 14:22:24 -05:00
58e9646fa6 ssb: Populate reply information in posts.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 21m33s
2024-12-24 13:09:27 -05:00
500f172561 ssb: Double down on a loading indicator.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 21m29s
2024-12-24 12:45:25 -05:00
68f6c90ea4 ssb: Get saving the about cache off of the main load path.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 21m31s
2024-12-24 12:05:31 -05:00
41e91f2922 ssb: Consolidate global settings helpers.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 21m28s
2024-12-24 11:16:52 -05:00
999117cfeb clean: Remove a file I sloppily added. 2024-12-24 10:45:47 -05:00
6185df512f build: Add help for armdebug/release, and fix some make help alignment. 2024-12-24 10:39:11 -05:00
0cbf66c007 build: Let's try to artifact the x86_64 + ARM linux executables.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 21m30s
2024-12-24 10:31:09 -05:00
cd378b721d build: Support and test cross-compiling for linux-aarch64.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 22m13s
2024-12-24 10:01:14 -05:00
547d38d1ef ssb: Put the database in (ie, ~/.local/share/tildefriends/db.sqlite) by default. Unless it already exists in the working directory, so that nobody worries they've lost it. #91
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 17m48s
2024-12-23 16:32:30 -05:00
dca56af5b9 build: Let's go static openssl on macos, too.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 18m0s
2024-12-23 14:41:31 -05:00
224442772e build: Let's try a thing. Use our own static openssl libraries built in-tree.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 17m49s
2024-12-23 14:22:27 -05:00
003951fdf7 ssb: Load more context for mentions.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 16m39s
2024-12-23 13:32:36 -05:00
d51b3da1b4 ssb: Fix channel cycling key shortcut.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2024-12-23 13:18:30 -05:00
69f4af84db ssb: Fix weird sidebar sizing.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2024-12-23 13:07:33 -05:00
771759b252 ssb: Show drafts in the sidebar.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 16m22s
2024-12-23 12:25:52 -05:00
20c7a71db6 ssb: Add a checkbox to reply in a new thread. #47 Also, it's crab time. I'm sorry it took me so long.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 16m53s
2024-12-23 12:06:32 -05:00
8475ee0985 build: Let's start work on 0.0.27. 2024-12-23 11:23:51 -05:00
25 changed files with 597 additions and 378 deletions

View File

@ -24,15 +24,14 @@ jobs:
uses: android-actions/setup-android@v3
with:
packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264'
- run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64 libgpgme11
- run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64 libgpgme11 gcc-aarch64-linux-gnu
- run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all docs
- run: docker build .
- uses: actions/upload-artifact@v3
with:
path: out/TildeFriends-release.fdroid.apk
- uses: actions/upload-artifact@v3
with:
path: out/winrelease/tildefriends.exe
- uses: actions/upload-artifact@v3
with:
path: out/tildefriends-x86_64.AppImage
path: |
out/TildeFriends-release.fdroid.apk
out/winrelease/tildefriends.exe
out/tildefriends-x86_64.AppImage
out/release/tildefriends.standalone
out/armrelease/tildefriends.standalone

View File

@ -16,8 +16,8 @@ MAKEFLAGS += --no-builtin-rules
## LD := Linker.
## ANDROID_SDK := Path to the Android SDK.
VERSION_CODE := 31
VERSION_NUMBER := 0.0.26
VERSION_CODE := 32
VERSION_NUMBER := 0.0.27-wip
VERSION_NAME := This program kills fascists.
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3470200.zip
@ -34,6 +34,7 @@ ANDROID_SDK ?= ~/Android/Sdk
BUNDLETOOL = out/bundletool.jar
HAVE_WIN := 0
HAVE_CROSS_AARCH64 := 0
export SOURCE_DATE_EPOCH=1
export TZ=UTC
@ -45,6 +46,9 @@ BUILD_TYPES := debug release
HAVE_ANDROID = $(if $(shell which $(ANDROID_SDK)/platform-tools/adb),1,0)
HAVE_LINUX_IOS = $(if $(shell which deps/ios_toolchain/target/bin deps/ios_toolchain/target/bin/arm-apple-darwin11-clang),1,0)
HAVE_WIN = $(if $(shell which x86_64-w64-mingw32-gcc-win32),1,0)
ifneq ($(UNAME_M),aarch64)
HAVE_CROSS_AARCH64 = $(if $(shell which aarch64-linux-gnu-gcc),1,0)
endif
else ifeq ($(UNAME_S),Haiku)
BUILD_TYPES := debug release
CFLAGS += -Dstatic_assert=_Static_assert
@ -125,6 +129,13 @@ ifeq ($(HAVE_WIN),1)
BUILD_TYPES += windebug winrelease
endif
AARCH64_TARGETS := \
out/armdebug/tildefriends \
out/armrelease/tildefriends
ifeq ($(HAVE_CROSS_AARCH64),1)
BUILD_TYPES += armdebug armrelease
endif
LINUX_TARGETS := \
out/debug/tildefriends \
out/release/tildefriends
@ -149,6 +160,9 @@ all: $(IOS_APPS) \
out/tildefriends-iossimdebug.app/tildefriends \
out/tildefriends-iossimrelease.app/tildefriends
endif
ifeq ($(HAVE_CROSS_AARCH64),1)
all: out/armrelease/tildefriends.standalone
endif
DEBUG_TARGETS := \
out/debug/tildefriends \
@ -159,7 +173,8 @@ DEBUG_TARGETS := \
out/androiddebug/tildefriends \
out/androiddebug-armv7a/tildefriends \
out/androiddebug-x86_64/tildefriends \
out/androiddebug-x86/tildefriends
out/androiddebug-x86/tildefriends \
out/armdebug/tildefriends
RELEASE_TARGETS := \
out/release/tildefriends \
out/winrelease/tildefriends.exe \
@ -169,7 +184,8 @@ RELEASE_TARGETS := \
out/androidrelease/tildefriends \
out/androidrelease-armv7a/tildefriends \
out/androidrelease-x86_64/tildefriends \
out/androidrelease-x86/tildefriends
out/androidrelease-x86/tildefriends \
out/armrelease/tildefriends
ALL_TARGETS = $(DEBUG_TARGETS) $(RELEASE_TARGETS)
ANDROID_RELEASE_TARGETS := $(filter-out $(DEBUG_TARGETS),$(ANDROID_TARGETS))
NONANDROID_RELEASE_TARGETS := $(filter-out $(ANDROID_ARM64_TARGETS),$(RELEASE_TARGETS))
@ -192,11 +208,14 @@ $(ANDROID_TARGETS): CFLAGS += \
-Wno-unknown-warning-option
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
$(DEBUG_TARGETS): LDFLAGS += -Og
$(RELEASE_TARGETS): CFLAGS += \
-DNDEBUG \
-flto
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -O3
$(ANDROID_RELEASE_TARGETS): CFLAGS += -Oz
$(ANDROID_RELEASE_TARGETS): LDFLAGS += -Oz
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -Os
$(NONANDROID_RELEASE_TARGETS): LDFLAGS += -Os
$(WINDOWS_TARGETS): CC = x86_64-w64-mingw32-gcc-win32
$(WINDOWS_TARGETS): AS = $(CC)
$(WINDOWS_TARGETS): CFLAGS += \
@ -208,6 +227,10 @@ $(WINDOWS_TARGETS): LDFLAGS += \
-static \
-lm \
-Ldeps/openssl/mingw64/usr/local/lib
$(AARCH64_TARGETS): CC = aarch64-linux-gnu-gcc
$(AARCH64_TARGETS): AS = $(CC)
$(AARCH64_TARGETS): CFLAGS += -Ideps/openssl/Linux/aarch64/usr/local/include
$(AARCH64_TARGETS): LDFLAGS += -Ldeps/openssl/Linux/aarch64/usr/local/lib
ifeq ($(UNAME_S),Darwin)
$(MACOS_TARGETS): CC = xcrun clang
$(IOS_TARGETS): IOS_SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path)
@ -242,10 +265,12 @@ $(IOS_TARGETS): CFLAGS += -miphoneos-version-min=9.0 -Ideps/openssl/ios/ios64-xc
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=9.0 -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
$(LINUX_TARGETS) $(MACOS_TARGETS): CFLAGS += -Ideps/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/include
$(LINUX_TARGETS) $(MACOS_TARGETS): LDFLAGS += -Ldeps/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib
ifeq ($(UNAME_M),x86_64)
ifeq ($(UNAME_S),Linux)
all: appimage
all: appimage out/release/tildefriends.standalone
endif
ifneq ($(UNAME_S),Haiku)
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
@ -260,7 +285,7 @@ endif
get_objs = \
$(foreach build_type,$(BUILD_TYPES),$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)))))) \
$(foreach build_type,debug release,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
$(foreach build_type,debug release armdebug armrelease,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
$(foreach build_type,windebug winrelease,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_win))))) \
$(foreach build_type,androiddebug androidrelease androiddebug-x86 androidrelease-x86 androiddebug-x86_64 androidrelease-x86_64 androiddebug-armv7a androiddebug-armv7a,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_android))))) \
$(foreach build_type,androiddebug androidrelease androiddebug-x86 androidrelease-x86 androiddebug-x86_64 androidrelease-x86_64 androiddebug-armv7a androidrelease-armv7a,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
@ -725,7 +750,7 @@ $(MINIUNZIP_OBJS): CFLAGS += \
LDFLAGS += \
-pthread \
-lm
$(LINUX_TARGETS) $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
$(LINUX_TARGETS) $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS) $(AARCH64_TARGETS): LDFLAGS += \
-lssl \
-lcrypto
ifneq ($(UNAME_S),Haiku)
@ -765,6 +790,8 @@ $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
##
debug: ## Build a debug executable for the current platform.
release: ## Build a release executable for the current platform.
armdebug: ## Cross-compile aarch64 debug on Linux.
armrelease: ## Cross-compile aarch64 release on Linux.
all: $(BUILD_TYPES) ## Build all targets that appear possible to build on this machine.
unix: debug release ## Build all UNIX targets.
win: windebug winrelease ## Build all Windows targets.
@ -1106,6 +1133,27 @@ $(ANDROID_DEPS):
+@ANDROID_NDK_ROOT=$(ANDROID_NDK) tools/ssl-android
$(filter $(BUILD_DIR)/android%,$(APP_OBJS)): | $(ANDROID_DEPS)
ifeq ($(UNAME_S),Linux)
LOCAL_DEPS := deps/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib/libssl.a
$(LOCAL_DEPS):
+@tools/ssl-local
$(filter $(BUILD_DIR)/debug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/release/%,$(APP_OBJS)): | $(LOCAL_DEPS)
ifeq ($(HAVE_CROSS_AARCH64),1)
LOCAL_DEPS := deps/openssl/$(UNAME_S)/aarch64/usr/local/lib/libssl.a
$(LOCAL_DEPS):
+@OPTIONS=--cross-compile-prefix=aarch64-linux-gnu- BUILD_TARGET=aarch64 tools/ssl-local
$(filter $(BUILD_DIR)/armdebug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/armrelease/%,$(APP_OBJS)): | $(LOCAL_DEPS)
endif
endif
ifeq ($(UNAME_S),Darwin)
LOCAL_DEPS := deps/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib/libssl.a
$(LOCAL_DEPS):
+@tools/ssl-local
$(filter $(BUILD_DIR)/macosdebug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/macosrelease/%,$(APP_OBJS)): | $(LOCAL_DEPS)
endif
ifeq ($(HAVE_WIN),1)
WINDOWS_DEPS := deps/openssl/mingw64/usr/local/lib/libssl.a
$(WINDOWS_DEPS):
@ -1198,7 +1246,7 @@ tarball: ## Build an all-inclusive source tarball (.tar.xz).
.PHONY: tarball
dist: ## Build versions of all distributables for release.
dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe) out/TildeFriends-release.fdroid.apk appimage tarball
dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe) out/TildeFriends-release.fdroid.apk appimage tarball out/release/tildefriends.standalone $(if $(HAVE_CROSS_AARCH64), out/armrelease/tildefriends.standalone)
@mkdir -p dist/
@echo "[cp] tildefriends-$(VERSION_NUMBER).tar.xz"
@cp out/tildefriends-$(VERSION_NUMBER).tar.xz dist/tildefriends-$(VERSION_NUMBER).tar.xz
@ -1216,6 +1264,10 @@ dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefrien
@cp out/TildeFriends-release.fdroid.apk dist/TildeFriends-$(VERSION_NUMBER).fdroid.apk
@echo "[cp] TildeFriends-x86_64-$(VERSION_NUMBER).AppImage"
@cp out/tildefriends-x86_64.AppImage dist/TildeFriends-x86_64-$(VERSION_NUMBER).AppImage
@echo "[cp] tildefriends-linux-$(UNAME_M)-$(VERSION_NUMBER)"
@cp out/release/tildefriends.standalone dist/tildefriends-linux-$(UNAME_M)-$(VERSION_NUMBER)
@test $(HAVE_CROSS_AARCH64) && echo "[cp] tildefriends-linux-aarch64-$(VERSION_NUMBER)"
@test $(HAVE_CROSS_AARCH64) && cp out/armrelease/tildefriends.standalone dist/tildefriends-linux-aarch64-$(VERSION_NUMBER)
.PHONY: dist
dist-test: dist ## Exercise some built distributable files, making sure they work as intended.
@ -1258,7 +1310,7 @@ help: ## Display this help message.
/^##/ { sub(/^## ?/, ""); print $$0 } \
/^[[:alnum:]-]+:.*##/ { \
sub(/:.*##\s?/, ":"); \
printf " %s%-20s%s %s%s%s\n", G, $$1, R, O, $$2, R \
printf " %s%-21s%s %s%s%s\n", G, $$1, R, O, $$2, R \
} \
' < $(filter-out %.d,$(MAKEFILE_LIST))
@echo "" # Blank line.

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🐌",
"previous": "&q/1uGp0jMvsYGW7Gj8E33kf6UFo/uNYDXg3zo1sVKQg=.sha256"
"emoji": "🦀",
"previous": "&Us7cb8UfbwNoFVPQXDnGBdGDmxQwPdNwcNjaiai80YA=.sha256"
}

View File

@ -112,26 +112,24 @@ class TfElement extends LitElement {
keydown(event) {
if (event.altKey && event.key == 'ArrowUp') {
this.next_channel(1);
this.next_channel(-1);
event.preventDefault();
} else if (event.altKey && event.key == 'ArrowDown') {
this.next_channel(-1);
this.next_channel(1);
event.preventDefault();
}
}
next_channel(delta) {
let channel_names = ['', '@'].concat(this.channels);
let channel_names = ['', '@', '🔐', ...this.channels.map((x) => '#' + x)];
let index = channel_names.indexOf(this.hash.substring(1));
if (index != -1) {
index += delta;
this.set_hash(
'#' +
encodeURIComponent(
channel_names[(index + channel_names.length) % channel_names.length]
)
);
}
index = index != -1 ? index + delta : 0;
tfrpc.rpc.setHash(
'#' +
encodeURIComponent(
channel_names[(index + channel_names.length) % channel_names.length]
)
);
}
set_hash(hash) {
@ -150,6 +148,7 @@ class TfElement extends LitElement {
async fetch_about(ids, users) {
const k_cache_version = 1;
let cache = await tfrpc.rpc.databaseGet('about');
let original_cache = cache;
cache = cache ? JSON.parse(cache) : {};
if (cache.version !== k_cache_version) {
cache = {
@ -215,7 +214,13 @@ class TfElement extends LitElement {
}
}
cache.last_row_id = max_row_id;
await tfrpc.rpc.databaseSet('about', JSON.stringify(cache));
let new_cache = JSON.stringify(cache);
if (new_cache !== original_cache) {
let start_time = new Date();
tfrpc.rpc.databaseSet('about', new_cache).then(function () {
console.log('saving about took', (new Date() - start_time) / 1000);
});
}
users = users || {};
for (let id of Object.keys(cache.about)) {
users[id] = Object.assign(users[id] || {}, cache.about[id]);
@ -313,6 +318,7 @@ class TfElement extends LitElement {
UNION
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
UNION
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
JOIN messages ON messages.rowid = messages_fts.rowid
@ -538,16 +544,15 @@ class TfElement extends LitElement {
)}
</div>
`;
let contents = !this.loaded
? this.loading
let contents =
!this.loaded || this.loading
? html`<div
class="w3-panel w3-theme-l5 w3-card-4 w3-padding-large w3-round-xlarge"
>
Loading...
</div>
${this.render_tab()}`
: html`<div>Select or create an identity.</div>`
: this.render_tab();
class="w3-display-middle w3-panel w3-theme-l5 w3-card-4 w3-padding-large w3-round-xlarge w3-xlarge"
>
<span class="w3-spin" style="display: inline-block">🦀</span>
Loading...
</div>`
: this.render_tab();
return html`
<div
style="width: 100vw; min-height: 100vh; height: 100%"

View File

@ -15,6 +15,7 @@ class TfComposeElement extends LitElement {
drafts: {type: Object},
author: {type: String},
channel: {type: String},
new_thread: {type: Boolean},
};
}
@ -28,6 +29,7 @@ class TfComposeElement extends LitElement {
this.apps = undefined;
this.drafts = {};
this.author = undefined;
this.new_thread = false;
}
process_text(text) {
@ -200,9 +202,23 @@ class TfComposeElement extends LitElement {
channel: this.channel,
};
if (this.root || this.branch) {
message.root = this.root;
message.root = this.new_thread ? (this.branch ?? this.root) : this.root;
message.branch = this.branch;
}
let reply = Object.fromEntries(
(
await tfrpc.rpc.query(
`
SELECT messages.id, messages.author FROM messages
JOIN json_each(?) AS refs ON messages.id = refs.value
`,
[JSON.stringify([this.root, this.branch])]
)
).map((row) => [row.id, row.author])
);
if (Object.keys(reply).length) {
message.reply = reply;
}
if (Object.values(draft.mentions || {}).length) {
message.mentions = Object.values(draft.mentions);
}
@ -469,6 +485,20 @@ class TfComposeElement extends LitElement {
}
}
render_new_thread() {
let self = this;
if (
this.root !== undefined &&
this.branch !== undefined &&
this.root != this.branch
) {
return html`
<input type="checkbox" class="w3-check w3-theme-d1" id="new_thread" @change=${() => (self.new_thread = !self.new_thread)} ?checked=${self.new_thread}></input>
<label for="new_thread">New Thread</label>
`;
}
}
get_draft() {
return this.drafts[this.branch || ''] || {};
}
@ -563,6 +593,7 @@ class TfComposeElement extends LitElement {
self.render_mention(x)
)}
${this.render_attach_app()} ${this.render_content_warning()}
${this.render_new_thread()}
<button class="w3-button w3-theme-d1" id="submit" @click=${this.submit}>
Submit
</button>

View File

@ -210,7 +210,7 @@ class TfNewsElement extends LitElement {
channel=${this.channel}
channel_unread=${this.channel_unread}
></tf-message>
${x.rowid == unread_rowid && x != final_messages[0]
${x.rowid == unread_rowid
? html`<div style="display: flex; flex-direction: row">
<div
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"

View File

@ -175,6 +175,9 @@ class TfTabConnectionsElement extends LitElement {
.map((x) => html`<li>${this.render_connection(x)}</li>`)}
${this.render_room_peers(connection.id)}
</ul>
<div ?hidden=${!connection.destroy_reason} class="w3-panel w3-red">
<p>${connection.destroy_reason}</p>
</div>
`;
}

View File

@ -51,15 +51,21 @@ class TfTabNewsFeedElement extends LitElement {
if (this.hash == '#@') {
result = await tfrpc.rpc.query(
`
WITH mentions AS (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(?1)
JOIN messages ON messages.rowid = messages_fts.rowid
JOIN json_each(?2) AS following ON messages.author = following.value
WHERE
messages.author != ?1 AND
messages.timestamp >= ?3 AND
messages.timestamp < ?4
ORDER BY timestamp DESC limit 20)
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(?1)
JOIN messages ON messages.rowid = messages_fts.rowid
JOIN json_each(?2) AS following ON messages.author = following.value
WHERE
messages.author != ?1 AND
messages.timestamp >= ?3 AND
messages.timestamp < ?4
ORDER BY timestamp DESC limit 20
FROM mentions
JOIN messages_refs ON mentions.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
UNION
SELECT * FROM mentions
`,
[
'"' + this.whoami.replace('"', '""') + '"',

View File

@ -176,7 +176,7 @@ class TfTabNewsElement extends LitElement {
return html`
<div
class="w3-sidebar w3-bar-block w3-theme-d1 w3-collapse w3-animate-left"
style="width: 2in; left: 0; z-index: 5"
style="width: 2in; left: 0; z-index: 5; box-sizing: border-box"
id="sidebar"
>
<div
@ -216,6 +216,18 @@ class TfTabNewsElement extends LitElement {
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined}
>🔐private ${this.unread_status('🔐')}</a
>
${Object.keys(this.drafts)
.sort()
.map(
(x) => html`
<a
href=${'#' + encodeURIComponent(x)}
class="w3-bar-item w3-button"
style="text-wrap: nowrap; text-overflow: ellipsis"
>📝 ${this.drafts[x]?.text ?? x}</a
>
`
)}
${this.channels.map(
(x) => html`
<a

View File

@ -21,14 +21,14 @@
}:
pkgs.stdenv.mkDerivation rec {
pname = "tildefriends";
version = "0.0.25";
version = "0.0.26";
src = pkgs.fetchFromGitea {
domain = "dev.tildefriends.net";
owner = "cory";
repo = "tildefriends";
rev = "v${version}";
hash = "sha256-Rfk+CUhi+Ss0z70CCgmtVM/w4nCL1GX/MsD4sPYIa5s=";
hash = "sha256-XJ7M++risfsRn9GkS1zjTQpqqV5S09uyimeVzU9hGGg=";
fetchSubmodules = true;
};

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unprompted.tildefriends"
android:versionCode="31"
android:versionName="0.0.26">
android:versionCode="32"
android:versionName="0.0.27-wip">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application

View File

@ -738,25 +738,6 @@ static void _httpd_endpoint_mem(tf_http_request_t* request)
tf_free(response);
}
static void _httpd_endpoint_disconnections(tf_http_request_t* request)
{
if (_httpd_redirect(request))
{
return;
}
tf_task_t* task = request->user_data;
char* response = tf_task_get_disconnections(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 void _httpd_endpoint_hitches(tf_http_request_t* request)
{
if (_httpd_redirect(request))
@ -2317,7 +2298,6 @@ void tf_httpd_register(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, "/disconnections", _httpd_endpoint_disconnections, 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);

View File

@ -25,6 +25,7 @@
#if defined(__linux__)
#include <sys/prctl.h>
#include <sys/stat.h>
#endif
#if defined(__APPLE__)
@ -41,7 +42,102 @@
struct backtrace_state* g_backtrace_state;
const char* k_db_path_default = "db.sqlite";
#if !defined(TARGET_OS_IPHONE)
static const char* _get_db_path()
{
const char* k_db_path_default = "db.sqlite";
#if defined(__linux__)
if (stat(k_db_path_default, &(struct stat) { 0 }) == 0)
{
return tf_strdup(k_db_path_default);
}
else
{
char buffer[32];
char* data_home = NULL;
size_t size = sizeof(buffer);
int r = uv_os_getenv("XDG_DATA_HOME", buffer, &size);
if (r == 0 || r == UV_ENOBUFS)
{
size++;
data_home = alloca(size);
if (uv_os_getenv("XDG_DATA_HOME", data_home, &size) != 0)
{
data_home = NULL;
}
}
if (!data_home)
{
size = sizeof(buffer);
r = uv_os_getenv("HOME", buffer, &size);
if (r == 0 || r == UV_ENOBUFS)
{
size++;
char* home = alloca(size);
r = uv_os_getenv("HOME", home, &size);
if (r == 0)
{
size = snprintf(NULL, 0, "%s/.local/share", home) + 1;
data_home = alloca(size);
snprintf(data_home, size, "%s/.local/share", home);
}
}
}
if (data_home)
{
size = snprintf(NULL, 0, "%s/tildefriends/db.sqlite", data_home) + 1;
char* path = alloca(size);
snprintf(path, size, "%s/tildefriends/db.sqlite", data_home);
return tf_strdup(path);
}
}
#endif
return tf_strdup(k_db_path_default);
}
static void _create_directories_for_file(const char* path, int mode)
{
if (stat(path, &(struct stat) { 0 }) == 0)
{
/* It already exists. OK. */
return;
}
size_t length = strlen(path) + 1;
char* copy = alloca(length);
memcpy(copy, path, length);
#if defined(_WIN32)
for (char* c = copy; *c; c++)
{
if (*c == '\\')
{
*c = '/';
}
}
#endif
char* slash = copy;
while (slash)
{
slash = strchr(slash + 1, '/');
if (slash)
{
*slash = '\0';
#if defined(_WIN32)
if (mkdir(copy) == 0)
#else
if (mkdir(copy, mode) == 0)
#endif
{
tf_printf("Created directory %s.\n", copy);
}
*slash = '/';
}
}
}
#endif
#if !TARGET_OS_IPHONE && !defined(__ANDROID__)
static int _tf_command_export(const char* file, int argc, char* argv[]);
@ -131,7 +227,8 @@ static int _tf_command_test(const char* file, int argc, char* argv[])
static int _tf_command_import(const char* file, int argc, char* argv[])
{
const char* user = "import";
const char* db_path = k_db_path_default;
const char* default_db_path = _get_db_path();
const char* db_path = default_db_path;
bool show_usage = false;
while (!show_usage)
@ -169,11 +266,13 @@ static int _tf_command_import(const char* file, int argc, char* argv[])
tf_printf("\n%s import [options] [paths...]\n\n", file);
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", k_db_path_default);
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");
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
_create_directories_for_file(db_path, 0700);
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
if (optind < argc)
{
@ -189,13 +288,15 @@ static int _tf_command_import(const char* file, int argc, char* argv[])
tf_ssb_import(ssb, user, "apps");
}
tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return EXIT_SUCCESS;
}
static int _tf_command_export(const char* file, int argc, char* argv[])
{
const char* user = "core";
const char* db_path = k_db_path_default;
const char* default_db_path = _get_db_path();
const char* db_path = default_db_path;
bool show_usage = false;
while (!show_usage)
@ -233,10 +334,11 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
tf_printf("\n%s export [options] [paths...]\n\n", file);
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", k_db_path_default);
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");
tf_printf("\n");
tf_printf("paths Paths of apps to export (example: /~core/ssb /~user/app).\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
@ -271,6 +373,7 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
}
}
tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return EXIT_SUCCESS;
}
@ -298,7 +401,8 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
{
const char* user = NULL;
const char* identity = NULL;
const char* db_path = k_db_path_default;
const char* default_db_path = _get_db_path();
const char* db_path = default_db_path;
const char* content = NULL;
bool show_usage = false;
@ -346,14 +450,16 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
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");
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
tf_printf(" -c, --content json JSON content of message to publish.\n");
tf_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
int result = EXIT_FAILURE;
tf_printf("Posting %s as account %s belonging to %s...\n", content, identity, user);
_create_directories_for_file(db_path, 0700);
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
uint8_t private_key[512] = { 0 };
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
@ -386,12 +492,14 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
}
tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return result;
}
static int _tf_command_store_blob(const char* file, int argc, char* argv[])
{
const char* db_path = k_db_path_default;
const char* default_db_path = _get_db_path();
const char* db_path = default_db_path;
const char* file_path = NULL;
bool show_usage = false;
@ -429,9 +537,10 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
{
tf_printf("\n%s store_blob [options]\n\n", file);
tf_printf("options:\n");
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
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");
tf_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
@ -441,6 +550,7 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
if (!blob_file)
{
tf_printf("Failed to open %s: %s.\n", file_path, strerror(errno));
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
@ -464,11 +574,13 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
tf_printf("Failed to read %s: %s.\n", file_path, strerror(errno));
fclose(blob_file);
tf_free(data);
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
fclose(blob_file);
char id[256];
_create_directories_for_file(db_path, 0700);
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
if (tf_ssb_db_blob_store(ssb, (const uint8_t*)data, size, id, sizeof(id), NULL))
{
@ -476,13 +588,15 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
}
tf_ssb_destroy(ssb);
tf_free(data);
tf_free((void*)default_db_path);
return EXIT_SUCCESS;
}
static int _tf_command_verify(const char* file, int argc, char* argv[])
{
const char* identity = NULL;
const char* db_path = k_db_path_default;
const char* default_db_path = _get_db_path();
const char* db_path = default_db_path;
bool show_usage = false;
while (!show_usage)
@ -520,8 +634,9 @@ static int _tf_command_verify(const char* file, int argc, char* argv[])
tf_printf("\n%s import [options] [paths...]\n\n", file);
tf_printf("options:\n");
tf_printf(" -i, --identity identity Identity to verify.\n");
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
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");
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
@ -529,6 +644,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[])
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
bool verified = tf_ssb_db_verify(ssb, identity);
tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return verified ? EXIT_SUCCESS : EXIT_FAILURE;
}
#endif
@ -673,13 +789,14 @@ static void _shed_privileges()
static int _tf_command_run(const char* file, int argc, char* argv[])
{
const char* default_db_path = _get_db_path();
tf_run_args_t args = {
.count = 1,
.script = "core/core.js",
.http_port = 12345,
.https_port = 12346,
.ssb_port = 8008,
.db_path = k_db_path_default,
.db_path = default_db_path,
};
bool show_usage = false;
@ -764,7 +881,7 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
tf_printf(" -b, --ssb-port port Port on which to run SSB (default: 8008, 0 disables).\n");
tf_printf(" -p, --http-port port Port on which to run Tilde Friends web server (default: 12345).\n");
tf_printf(" -q, --https-port port Port on which to run secure Tilde Friends web server (default: 12346).\n");
tf_printf(" -d, --db-path path SQLite database path (default: %s).\n", k_db_path_default);
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");
tf_printf(" -n, --count count Number of instances to run.\n");
tf_printf(" -a, --args args Arguments of the format key=value,foo=bar,verbose=true.\n");
@ -772,6 +889,7 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
tf_printf(" -z, --zip path Zip archive from which to load files.\n");
tf_printf(" -v, --verbose Log raw messages.\n");
tf_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE;
}
@ -780,6 +898,7 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
setpgid(0, 0);
#endif
_create_directories_for_file(args.db_path, 0700);
if (args.count == 1)
{
result = _tf_run_task(&args, 0);
@ -807,6 +926,7 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
tf_free(data);
tf_free(threads);
}
tf_free((void*)default_db_path);
return result;
}
@ -1088,7 +1208,7 @@ void tf_run_thread_start(const char* zip_path)
.http_port = 12345,
.https_port = 12346,
.ssb_port = 8008,
.db_path = k_db_path_default,
.db_path = "db.sqlite",
.one_proc = true,
.zip = zip_path,
};

269
src/ssb.c
View File

@ -71,8 +71,6 @@ enum
{
k_connections_changed_callbacks_max = 8,
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024,
k_debug_close_message_count = 256,
k_debug_close_connection_count = 32,
k_seed_expire_seconds = 10 * 60,
k_seed_check_interval_seconds = 5 * 60,
k_udp_discovery_expires_seconds = 10,
@ -84,24 +82,6 @@ typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t;
typedef struct _tf_ssb_connection_t tf_ssb_connection_t;
typedef struct _tf_ssb_request_t tf_ssb_request_t;
typedef struct _tf_ssb_debug_message_t
{
bool outgoing;
int flags;
int32_t request_number;
time_t timestamp;
size_t size;
uint8_t data[];
} tf_ssb_debug_message_t;
typedef struct _tf_ssb_debug_close_t
{
char id[k_id_base64_len];
char tunnel[k_id_base64_len];
char reason[128];
tf_ssb_debug_message_t* messages[k_debug_close_message_count];
} tf_ssb_debug_close_t;
typedef struct _tf_ssb_request_t
{
char name[256];
@ -218,7 +198,6 @@ typedef struct _tf_ssb_t
uint8_t priv[crypto_sign_SECRETKEYBYTES];
bool verbose;
bool store_debug_messages;
bool shutting_down;
bool shutting_down_deferred;
@ -252,8 +231,6 @@ typedef struct _tf_ssb_t
tf_ssb_broadcasts_changed_callback_node_t* broadcasts_changed;
int broadcasts_changed_count;
tf_ssb_debug_close_t debug_close[k_debug_close_connection_count];
int32_t thread_busy_count;
int32_t thread_busy_max;
@ -296,6 +273,7 @@ typedef struct _tf_ssb_connection_t
uv_async_t async;
uv_async_t scheduled_async;
uv_timer_t handshake_timer;
uv_timer_t linger_timer;
bool closing;
tf_ssb_connection_t* tunnel_connection;
@ -356,7 +334,6 @@ typedef struct _tf_ssb_connection_t
tf_ssb_connection_scheduled_t* scheduled;
int scheduled_count;
tf_ssb_debug_message_t* debug_messages[k_debug_close_message_count];
int ref_count;
int read_back_pressure;
@ -375,6 +352,8 @@ 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_close(tf_ssb_connection_t* connection, const char* reason);
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason);
@ -415,63 +394,6 @@ static const char* _tf_ssb_connection_state_to_string(tf_ssb_state_t state)
}
}
static void _tf_ssb_add_debug_close(tf_ssb_t* ssb, tf_ssb_connection_t* connection, const char* reason)
{
if (!ssb->store_debug_messages)
{
return;
}
for (int i = 0; i < k_debug_close_message_count; i++)
{
tf_free(ssb->debug_close[k_debug_close_connection_count - 1].messages[i]);
}
for (int i = k_debug_close_connection_count - 1; i > 0; i--)
{
ssb->debug_close[i] = ssb->debug_close[i - 1];
}
tf_ssb_id_bin_to_str(ssb->debug_close[0].id, sizeof(ssb->debug_close[0].id), connection->serverpub);
if (connection->tunnel_connection)
{
tf_ssb_id_bin_to_str(ssb->debug_close[0].tunnel, sizeof(ssb->debug_close[0].tunnel), connection->tunnel_connection->serverpub);
}
else
{
memset(ssb->debug_close[0].tunnel, 0, sizeof(ssb->debug_close[0].tunnel));
}
memcpy(ssb->debug_close[0].messages, connection->debug_messages, sizeof(connection->debug_messages));
memset(connection->debug_messages, 0, sizeof(connection->debug_messages));
snprintf(ssb->debug_close[0].reason, sizeof(ssb->debug_close[0].reason), "%s", reason);
}
static void _tf_ssb_connection_add_debug_message(tf_ssb_connection_t* connection, bool outgoing, int flags, int32_t request_number, const uint8_t* data, size_t size)
{
if (!connection->ssb->store_debug_messages)
{
return;
}
if (connection->debug_messages[k_debug_close_message_count - 1])
{
tf_free(connection->debug_messages[k_debug_close_message_count - 1]);
}
for (int i = k_debug_close_message_count - 1; i > 0; i--)
{
connection->debug_messages[i] = connection->debug_messages[i - 1];
}
tf_ssb_debug_message_t* message = tf_malloc(sizeof(tf_ssb_debug_message_t) + size);
*message = (tf_ssb_debug_message_t) {
.outgoing = outgoing,
.flags = flags,
.request_number = request_number,
.timestamp = time(NULL),
.size = size,
};
memcpy(message + 1, data, size);
connection->debug_messages[0] = message;
}
static void _tf_ssb_connection_send_close(tf_ssb_connection_t* connection)
{
uint8_t message_enc[34];
@ -497,7 +419,6 @@ static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char
else if (connection->state == k_tf_ssb_state_verified || connection->state == k_tf_ssb_state_server_verified)
{
tf_printf("Connection %s %p is closing: %s.\n", connection->name, connection, reason);
_tf_ssb_add_debug_close(connection->ssb, connection, reason);
connection->state = k_tf_ssb_state_closing;
_tf_ssb_connection_send_close(connection);
}
@ -679,7 +600,9 @@ static void _tf_ssb_connection_dispatch_scheduled(tf_ssb_connection_t* connectio
memmove(connection->scheduled, connection->scheduled + 1, sizeof(tf_ssb_connection_scheduled_t) * (connection->scheduled_count - 1));
connection->scheduled_count--;
tf_trace_begin(connection->ssb->trace, "scheduled callback");
PRE_CALLBACK(connection->ssb, scheduled.callback);
scheduled.callback(connection, scheduled.user_data);
POST_CALLBACK(connection->ssb, scheduled.callback);
tf_trace_end(connection->ssb->trace);
}
}
@ -921,7 +844,6 @@ bool tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags,
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false", (flags & k_ssb_rpc_flag_stream) ? "true" : "false", k_ssb_type_names[flags & k_ssb_rpc_mask_type],
request_number, size, (flags & k_ssb_rpc_mask_type) == k_ssb_rpc_flag_binary ? 0 : (int)size, message);
}
_tf_ssb_connection_add_debug_message(connection, true, flags & k_ssb_rpc_mask_send, request_number, message, size);
_tf_ssb_connection_box_stream_send(connection, combined, 1 + 2 * sizeof(uint32_t) + size);
tf_free(combined);
connection->ssb->rpc_out++;
@ -1360,7 +1282,9 @@ 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;
}
@ -1653,7 +1577,6 @@ static void _tf_ssb_name_to_string(JSContext* context, JSValue object, char* buf
static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size)
{
connection->ssb->rpc_in++;
_tf_ssb_connection_add_debug_message(connection, false, flags, request_number, message, size);
bool close_connection = false;
if (size == 0)
{
@ -1917,19 +1840,32 @@ JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* pr
return root;
}
static void _tf_ssb_connection_linger_timer(uv_timer_t* timer)
{
tf_ssb_connection_t* connection = timer->data;
uv_close((uv_handle_t*)&connection->linger_timer, _tf_ssb_connection_on_close);
}
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason)
{
tf_ssb_t* ssb = connection->ssb;
connection->closing = true;
if (!connection->closing)
{
connection->closing = true;
uv_timer_start(&connection->linger_timer, _tf_ssb_connection_linger_timer, 5000, 0);
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_update, connection);
}
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;
}
if (!connection->destroy_reason)
{
connection->destroy_reason = reason;
connection->destroy_reason = tf_strdup(reason);
}
_tf_ssb_connection_dispatch_scheduled(connection);
tf_free(connection->scheduled);
@ -1955,14 +1891,6 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
tf_ssb_connection_remove_request(*it, (*it)->requests[i].request_number);
}
}
if (*it == connection)
{
*it = connection->next;
connection->next = NULL;
ssb->connections_count--;
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_remove, connection);
break;
}
}
bool again = true;
while (again)
@ -2010,22 +1938,29 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
}
if (JS_IsUndefined(connection->object) && !connection->async.data && !connection->scheduled_async.data && !connection->tcp.data && !connection->connect.data &&
!connection->handshake_timer.data && connection->ref_count == 0)
!connection->handshake_timer.data && !connection->linger_timer.data && connection->ref_count == 0)
{
tf_free(connection->message_requests);
connection->message_requests = NULL;
connection->message_requests_count = 0;
for (int i = 0; i < k_debug_close_message_count; i++)
for (tf_ssb_connection_t** it = &connection->ssb->connections; *it; it = &(*it)->next)
{
tf_free(connection->debug_messages[i]);
connection->debug_messages[i] = NULL;
if (*it == connection)
{
*it = connection->next;
connection->next = NULL;
ssb->connections_count--;
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_remove, connection);
break;
}
}
if (--connection->ssb->connection_ref_count == 0 && connection->ssb->shutting_down_deferred)
{
tf_ssb_destroy(connection->ssb);
}
tf_free((void*)connection->destroy_reason);
tf_free(connection);
}
}
@ -2290,7 +2225,6 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
char buffer[8] = { 0 };
size_t buffer_size = sizeof(buffer);
ssb->store_debug_messages = uv_os_getenv("TF_DEBUG_CLOSE", buffer, &buffer_size) == 0 && strcmp(buffer, "1") == 0;
buffer_size = sizeof(buffer);
ssb->verbose = uv_os_getenv("TF_SSB_VERBOSE", buffer, &buffer_size) == 0 && strcmp(buffer, "1") == 0;
@ -2684,13 +2618,6 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
ssb->broadcasts_count--;
tf_free(broadcast);
}
for (int i = 0; i < k_debug_close_connection_count; i++)
{
for (int j = 0; j < k_debug_close_message_count; j++)
{
tf_free(ssb->debug_close[i].messages[j]);
}
}
for (int i = 0; i < ssb->db_readers_count; i++)
{
sqlite3_close(ssb->db_readers[i]);
@ -2813,6 +2740,9 @@ static tf_ssb_connection_t* _tf_ssb_connection_create(
uv_timer_init(ssb->loop, &connection->handshake_timer);
uv_timer_start(&connection->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
connection->linger_timer.data = connection;
uv_timer_init(ssb->loop, &connection->linger_timer);
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
JS_SetOpaque(connection->object, connection);
char public_key_str[k_id_base64_len] = { 0 };
@ -2886,6 +2816,9 @@ tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char*
uv_timer_init(ssb->loop, &tunnel->handshake_timer);
uv_timer_start(&tunnel->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
tunnel->linger_timer.data = tunnel;
uv_timer_init(ssb->loop, &tunnel->linger_timer);
tunnel->object = JS_NewObjectClass(ssb->context, _connection_class_id);
JS_SetOpaque(tunnel->object, tunnel);
JS_SetPropertyStr(context, tunnel->object, "id", JS_NewString(context, target_id));
@ -3046,6 +2979,9 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
uv_timer_init(ssb->loop, &connection->handshake_timer);
uv_timer_start(&connection->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
connection->linger_timer.data = connection;
uv_timer_init(ssb->loop, &connection->linger_timer);
struct sockaddr_storage addr = { 0 };
int size = sizeof(addr);
if (uv_tcp_getpeername(&connection->tcp, (struct sockaddr*)&addr, &size) == 0)
@ -3306,7 +3242,9 @@ 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);
}
}
@ -3410,7 +3348,9 @@ 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);
}
}
@ -3718,7 +3658,9 @@ void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* id, JSValue message_
{
next = node->next;
tf_trace_begin(ssb->trace, "message added callback");
PRE_CALLBACK(ssb, node->callback);
node->callback(ssb, id, node->user_data);
POST_CALLBACK(ssb, node->callback);
tf_trace_end(ssb->trace);
}
@ -3794,7 +3736,9 @@ 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);
}
}
@ -3952,44 +3896,6 @@ void tf_ssb_connection_set_ebt_request_number(tf_ssb_connection_t* connection, i
connection->ebt_request_number = request_number;
}
JSValue tf_ssb_get_disconnection_debug(tf_ssb_t* ssb, JSContext* context)
{
JSValue result = JS_NewObject(context);
JSValue disconnections = JS_NewArray(context);
for (int i = 0; i < k_debug_close_connection_count; i++)
{
JSValue disconnection = JS_NewObject(context);
if (*ssb->debug_close[i].id)
{
JS_SetPropertyStr(context, disconnection, "id", JS_NewString(context, ssb->debug_close[i].id));
if (*ssb->debug_close[i].tunnel)
{
JS_SetPropertyStr(context, disconnection, "tunnel", JS_NewString(context, ssb->debug_close[i].tunnel));
}
JS_SetPropertyStr(context, disconnection, "reason", JS_NewString(context, ssb->debug_close[i].reason));
JSValue messages = JS_NewArray(context);
for (int j = 0; j < k_debug_close_message_count; j++)
{
if (ssb->debug_close[i].messages[j])
{
JSValue message = JS_NewObject(context);
JS_SetPropertyStr(context, message, "direction", JS_NewString(context, ssb->debug_close[i].messages[j]->outgoing ? "out" : "in"));
JS_SetPropertyStr(context, message, "flags", JS_NewInt32(context, ssb->debug_close[i].messages[j]->flags));
JS_SetPropertyStr(context, message, "request_number", JS_NewInt32(context, ssb->debug_close[i].messages[j]->request_number));
JS_SetPropertyStr(context, message, "timestamp", JS_NewFloat64(context, ssb->debug_close[i].messages[j]->timestamp));
JS_SetPropertyStr(
context, message, "payload", JS_NewStringLen(context, (const char*)ssb->debug_close[i].messages[j]->data, ssb->debug_close[i].messages[j]->size));
JS_SetPropertyUint32(context, messages, j, message);
}
}
JS_SetPropertyStr(context, disconnection, "messages", messages);
}
JS_SetPropertyUint32(context, disconnections, i, disconnection);
}
JS_SetPropertyStr(context, result, "disconnections", disconnections);
return result;
}
void tf_ssb_record_thread_busy(tf_ssb_t* ssb, bool busy)
{
int32_t busy_value = __atomic_add_fetch(&ssb->thread_busy_count, busy ? 1 : -1, __ATOMIC_RELAXED);
@ -4071,7 +3977,9 @@ 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--;
@ -4138,7 +4046,9 @@ 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);
@ -4222,63 +4132,19 @@ typedef struct _update_settings_t
char room_name[1024];
} update_settings_t;
static bool _get_global_setting_string(tf_ssb_t* ssb, const char* name, char* out_value, size_t size)
{
bool result = false;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
snprintf(out_value, size, "%s", sqlite3_column_text(statement, 0));
result = true;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool default_value)
{
bool result = default_value;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
result = sqlite3_column_int(statement, 0) != 0;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static void _tf_ssb_update_settings_work(tf_ssb_t* ssb, void* user_data)
{
update_settings_t* update = user_data;
update->is_room = _get_global_setting_bool(ssb, "room", true);
update->is_replicator = _get_global_setting_bool(ssb, "replicator", true);
update->is_peer_exchange = _get_global_setting_bool(ssb, "peer_exchange", true);
_get_global_setting_string(ssb, "room_name", update->room_name, sizeof(update->room_name));
_get_global_setting_string(ssb, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
update->is_room = true;
update->is_replicator = true;
update->is_peer_exchange = true;
tf_ssb_db_get_global_setting_bool(db, "room", &update->is_room);
tf_ssb_db_get_global_setting_bool(db, "replicator", &update->is_replicator);
tf_ssb_db_get_global_setting_bool(db, "peer_exchange", &update->is_peer_exchange);
tf_ssb_db_get_global_setting_string(db, "room_name", update->room_name, sizeof(update->room_name));
tf_ssb_db_get_global_setting_string(db, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
tf_ssb_release_db_reader(ssb, db);
}
static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void* user_data)
@ -4321,7 +4187,9 @@ void tf_ssb_set_verbose(tf_ssb_t* ssb, bool verbose)
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);
}
@ -4423,6 +4291,11 @@ void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int d
uv_async_send(&connection->scheduled_async);
}
const char* tf_ssb_connection_get_destroy_reason(tf_ssb_connection_t* connection)
{
return connection ? connection->destroy_reason : NULL;
}
void tf_ssb_sync_start(tf_ssb_t* ssb)
{
tf_ssb_connections_sync_start(ssb->connections_tracker);

View File

@ -1681,34 +1681,13 @@ bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* con
return result;
}
static bool _tf_ssb_db_get_global_setting_bool(sqlite3* db, const char* name, bool default_value)
{
bool result = default_value;
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL)
{
result = sqlite3_column_int(statement, 0) != 0;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
return result;
}
bool tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password)
{
bool result = false;
JSValue users_array = JS_UNDEFINED;
bool registration_allowed = _tf_ssb_db_get_global_setting_bool(db, "account_registration", true);
bool registration_allowed = true;
tf_ssb_db_get_global_setting_bool(db, "account_registration", &registration_allowed);
if (registration_allowed)
{
sqlite3_stmt* statement = NULL;
@ -2030,3 +2009,72 @@ bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, sqlite3* db, const char* id, c
}
return has_permission;
}
bool tf_ssb_db_get_global_setting_bool(sqlite3* db, const char* name, bool* out_value)
{
bool result = false;
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
*out_value = sqlite3_column_int(statement, 0) != 0;
result = true;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
return result;
}
bool tf_ssb_db_get_global_setting_int64(sqlite3* db, const char* name, int64_t* out_value)
{
bool result = false;
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL)
{
*out_value = sqlite3_column_int64(statement, 0);
result = true;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
return result;
}
bool tf_ssb_db_get_global_setting_string(sqlite3* db, const char* name, char* out_value, size_t size)
{
bool result = false;
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
snprintf(out_value, size, "%s", sqlite3_column_text(statement, 0));
result = true;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
return result;
}

View File

@ -455,6 +455,34 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id);
*/
bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, sqlite3* db, const char* id, const char* permission);
/**
** Get a boolean global setting value.
** @param db The database.
** @param name The setting name.
** @param out_value Populated with the value.
** @return true if the setting was found.
*/
bool tf_ssb_db_get_global_setting_bool(sqlite3* db, const char* name, bool* out_value);
/**
** Get an int64_t global setting value.
** @param db The database.
** @param name The setting name.
** @param out_value Populated with the value.
** @return true if the setting was found.
*/
bool tf_ssb_db_get_global_setting_int64(sqlite3* db, const char* name, int64_t* out_value);
/**
** Get a string global setting value.
** @param db The database.
** @param name The setting name.
** @param out_value Populated with the value.
** @param size The size of the out_value buffer.
** @return true if the setting was found.
*/
bool tf_ssb_db_get_global_setting_string(sqlite3* db, const char* name, char* out_value, size_t size);
/**
** An SQLite authorizer callback. See https://www.sqlite.org/c3ref/set_authorizer.html for use.
** @param user_data User data registered with the authorizer.

View File

@ -947,14 +947,6 @@ void tf_ssb_get_stats(tf_ssb_t* ssb, tf_ssb_stats_t* out_stats);
*/
tf_ssb_blob_wants_t* tf_ssb_connection_get_blob_wants_state(tf_ssb_connection_t* connection);
/**
** Get a report of information about recent disconnections.
** @param ssb The SSB instance.
** @param context A JS context.
** @return Information about disconnections.
*/
JSValue tf_ssb_get_disconnection_debug(tf_ssb_t* ssb, JSContext* context);
/**
** Record whether the calling thread is busy.
** @param ssb The SSB instance.
@ -1101,6 +1093,13 @@ void tf_ssb_connection_adjust_read_backpressure(tf_ssb_connection_t* connection,
*/
void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int delta);
/**
** Get the reason why a connection is going away.
** @param connection The connection.
** @return The reason or NULL.
*/
const char* tf_ssb_connection_get_destroy_reason(tf_ssb_connection_t* connection);
/**
** Initiate a tunnel connection.
** @param ssb The SSB instance.

View File

@ -1120,6 +1120,11 @@ static JSValue _tf_ssb_connections(JSContext* context, JSValueConst this_val, in
int flags = tf_ssb_connection_get_flags(connection);
JS_SetPropertyStr(context, flags_object, "one_shot", JS_NewBool(context, (flags & k_tf_ssb_connect_flag_one_shot) != 0));
JS_SetPropertyStr(context, object, "flags", flags_object);
const char* destroy_reason = tf_ssb_connection_get_destroy_reason(connection);
if (destroy_reason)
{
JS_SetPropertyStr(context, object, "destroy_reason", JS_NewString(context, destroy_reason));
}
JS_SetPropertyUint32(context, result, i, object);
}
}

View File

@ -20,30 +20,6 @@ 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);
static int64_t _get_global_setting_int64(tf_ssb_t* ssb, const char* name, int64_t default_value)
{
int64_t result = default_value;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL)
{
result = sqlite3_column_int64(statement, 0);
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool default_value)
{
bool result = default_value;
@ -243,7 +219,10 @@ static void _tf_ssb_request_blob_wants_work(tf_ssb_connection_t* connection, voi
blob_wants_work_t* work = user_data;
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
int64_t age = _get_global_setting_int64(ssb, "blob_fetch_age_seconds", -1);
int64_t age = -1;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
tf_ssb_db_get_global_setting_int64(db, "blob_fetch_age_seconds", &age);
tf_ssb_release_db_reader(ssb, db);
int64_t timestamp = -1;
if (age == 0)
{
@ -256,7 +235,7 @@ static void _tf_ssb_request_blob_wants_work(tf_ssb_connection_t* connection, voi
timestamp = now - age * 1000ULL;
}
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT id FROM blob_wants_view WHERE id > ? AND timestamp > ? ORDER BY id LIMIT ?", -1, &statement, NULL) == SQLITE_OK)
{
@ -1003,7 +982,10 @@ static void _tf_ssb_rpc_ebt_replicate_send_clock_work(tf_ssb_connection_t* conne
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
JSValue full_clock = JS_NewObject(context);
int64_t depth = _get_global_setting_int64(ssb, "replication_hops", 2);
int64_t depth = 2;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
tf_ssb_db_get_global_setting_int64(db, "replication_hops", &depth);
tf_ssb_release_db_reader(ssb, db);
/* Ask for every identity we know is being followed from local accounts. */
const char** visible = tf_ssb_db_get_all_visible_identities(ssb, depth);
@ -1400,14 +1382,17 @@ typedef struct _delete_t
static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
{
delete_t* delete = user_data;
int64_t age = _get_global_setting_int64(ssb, "blob_expire_age_seconds", -1);
int64_t age = -1;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
tf_ssb_db_get_global_setting_int64(db, "blob_expire_age_seconds", &age);
tf_ssb_release_db_reader(ssb, db);
if (age <= 0)
{
_tf_ssb_rpc_checkpoint(ssb);
return;
}
int64_t start_ns = uv_hrtime();
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
db = tf_ssb_acquire_db_writer(ssb);
sqlite3_stmt* statement;
int64_t now = (int64_t)time(NULL) * 1000ULL;
int64_t timestamp = now - age * 1000ULL;
@ -1474,7 +1459,10 @@ static void _tf_ssb_rpc_delete_feeds_work(tf_ssb_t* ssb, void* user_data)
return;
}
int64_t start_ns = uv_hrtime();
int replication_hops = (int)_get_global_setting_int64(ssb, "replication_hops", 2);
int64_t replication_hops = 2;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
tf_ssb_db_get_global_setting_int64(db, "replication_hops", &replication_hops);
tf_ssb_release_db_reader(ssb, db);
const char** identities = tf_ssb_db_get_all_visible_identities(ssb, replication_hops);
JSMallocFunctions funcs = { 0 };
@ -1493,7 +1481,7 @@ static void _tf_ssb_rpc_delete_feeds_work(tf_ssb_t* ssb, void* user_data)
JS_FreeValue(context, json);
JS_FreeValue(context, array);
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
db = tf_ssb_acquire_db_writer(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db,
"DELETE FROM messages WHERE author IN ("

View File

@ -932,21 +932,6 @@ char* tf_task_get_hitches(tf_task_t* task)
return result;
}
char* tf_task_get_disconnections(tf_task_t* task)
{
JSContext* context = task->_context;
tf_trace_begin(task->_trace, __func__);
JSValue object = tf_ssb_get_disconnection_debug(task->_ssb, context);
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);

View File

@ -310,14 +310,6 @@ void tf_task_remove_child(tf_task_t* task, tf_taskstub_t* child);
*/
bool tf_task_send_error_to_parent(tf_task_t* task, JSValue error);
/**
** Get a report of recent disconnections.
** @param task The task.
** @return A JSON representation of recent disconnections that must be freed
** with tf_free().
*/
char* tf_task_get_disconnections(tf_task_t* task);
/**
** Get a report of miscellaneous debug information.
** @param task The task.

View File

@ -1,2 +1,2 @@
#define VERSION_NUMBER "0.0.26"
#define VERSION_NUMBER "0.0.27-wip"
#define VERSION_NAME "This program kills fascists."

View File

@ -73,8 +73,10 @@ build_the_thing() {
no-whirlpool
no-weak-ssl-ciphers
no-zlib
-Os
-Oz
-DOPENSSL_SMALL_FOOTPRINT
-ffunction-sections
-fdata-sections
-flto"
pwd
echo "./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS" && \

View File

@ -29,14 +29,14 @@ do
case $build_target in
ios64-xcrun)
TRIBLE="arm64-darwin-ios"
OPTIONS="--static -static -ffunction-sections -fdata-sections -fPIC -Wno-macro-redefined -miphoneos-version-min=9.0"
OPTIONS="--static -static -Os -ffunction-sections -fdata-sections -fPIC -Wno-macro-redefined -miphoneos-version-min=9.0"
DESTDIR="/tmp/$BUILD_DIR/arm64-ios"
SSL_TARGET="ios64-xcrun"
CC=clang
;;
iossimulator-xcrun)
TRIBLE="x86_64-darwin-ios"
OPTIONS="--static -static -ffunction-sections -fdata-sections -fPIC -Wno-macro-redefined"
OPTIONS="--static -static -Os -ffunction-sections -fdata-sections -fPIC -Wno-macro-redefined"
DESTDIR="/tmp/$BUILD_DIR/x86_64-iossim"
SSL_TARGET="iossimulator-xcrun"
CC=clang

91
tools/ssl-local Executable file
View File

@ -0,0 +1,91 @@
#!/bin/bash
BUILD_PLATFORM=$(uname -s)
if [[ -z $BUILD_TARGET ]]; then
BUILD_TARGET=$(uname -m)
WORK_DIR=out/openssl-local
else
WORK_DIR=out/openssl-$BUILD_TARGET
SSL_TARGET=linux-$BUILD_TARGET
fi
rm -rf $WORK_DIR
cp -aRf deps/openssl_src/ $WORK_DIR
echo "Building"
pwd
pushd $WORK_DIR || exit 128
rm -rf $DESTDIR
echo $PATH
export GLOBAL_OPTIONS="
no-apps
no-asm
no-async
no-autoerrinit
no-autoload-config
no-cmp
no-cms
no-comp
no-deprecated
no-dgram
no-docs
no-dsa
no-dso
no-dtls
no-dtls1
no-dtls1-method
no-dynamic-engine
no-ec2m
no-egd
no-engine
no-err
no-filenames
no-gost
no-http
no-idea
no-legacy
no-md2
no-md4
no-module
no-multiblock
no-nextprotoneg
no-ocsp
no-psk
no-shared
no-sock
no-srp
no-ssl
no-ssl3
no-ssl-trace
no-stdio
no-tests
no-thread-pool
no-threads
no-tls1
no-tls1-method
no-trace
no-ui-console
no-uplink
no-whirlpool
no-weak-ssl-ciphers
no-zlib
-Os
-DOPENSSL_SMALL_FOOTPRINT
-ffunction-sections
-fdata-sections
-flto"
pwd
echo "./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS" && \
./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS && \
make -s clean && \
make -s build_generated && \
make -s libcrypto.a libssl.a || exit 128
popd
echo WORK_DIR=$WORK_DIR
rm -rf deps/openssl/$BUILD_PLATFORM/$BUILD_TARGET/
mkdir -p deps/openssl/$BUILD_PLATFORM/$BUILD_TARGET/usr/local/include/
mkdir -p deps/openssl/$BUILD_PLATFORM/$BUILD_TARGET/usr/local/lib/
cp -R $WORK_DIR/include/* deps/openssl/$BUILD_PLATFORM/$BUILD_TARGET/usr/local/include/
cp $WORK_DIR/*.a deps/openssl/$BUILD_PLATFORM/$BUILD_TARGET/usr/local/lib/
echo Success