19 Commits

Author SHA1 Message Date
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
19 changed files with 520 additions and 185 deletions

View File

@ -24,15 +24,14 @@ jobs:
uses: android-actions/setup-android@v3 uses: android-actions/setup-android@v3
with: with:
packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264' 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: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all docs
- run: docker build . - run: docker build .
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
with: with:
path: out/TildeFriends-release.fdroid.apk path: |
- uses: actions/upload-artifact@v3 out/TildeFriends-release.fdroid.apk
with: out/winrelease/tildefriends.exe
path: out/winrelease/tildefriends.exe out/tildefriends-x86_64.AppImage
- uses: actions/upload-artifact@v3 out/release/tildefriends.standalone
with: out/armrelease/tildefriends.standalone
path: out/tildefriends-x86_64.AppImage

View File

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

View File

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

View File

@ -112,26 +112,24 @@ class TfElement extends LitElement {
keydown(event) { keydown(event) {
if (event.altKey && event.key == 'ArrowUp') { if (event.altKey && event.key == 'ArrowUp') {
this.next_channel(1); this.next_channel(-1);
event.preventDefault(); event.preventDefault();
} else if (event.altKey && event.key == 'ArrowDown') { } else if (event.altKey && event.key == 'ArrowDown') {
this.next_channel(-1); this.next_channel(1);
event.preventDefault(); event.preventDefault();
} }
} }
next_channel(delta) { 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)); let index = channel_names.indexOf(this.hash.substring(1));
if (index != -1) { index = index != -1 ? index + delta : 0;
index += delta; tfrpc.rpc.setHash(
this.set_hash( '#' +
'#' + encodeURIComponent(
encodeURIComponent( channel_names[(index + channel_names.length) % channel_names.length]
channel_names[(index + channel_names.length) % channel_names.length] )
) );
);
}
} }
set_hash(hash) { set_hash(hash) {
@ -150,6 +148,7 @@ class TfElement extends LitElement {
async fetch_about(ids, users) { async fetch_about(ids, users) {
const k_cache_version = 1; const k_cache_version = 1;
let cache = await tfrpc.rpc.databaseGet('about'); let cache = await tfrpc.rpc.databaseGet('about');
let original_cache = cache;
cache = cache ? JSON.parse(cache) : {}; cache = cache ? JSON.parse(cache) : {};
if (cache.version !== k_cache_version) { if (cache.version !== k_cache_version) {
cache = { cache = {
@ -215,7 +214,13 @@ class TfElement extends LitElement {
} }
} }
cache.last_row_id = max_row_id; 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 || {}; users = users || {};
for (let id of Object.keys(cache.about)) { for (let id of Object.keys(cache.about)) {
users[id] = Object.assign(users[id] || {}, cache.about[id]); users[id] = Object.assign(users[id] || {}, cache.about[id]);
@ -538,16 +543,15 @@ class TfElement extends LitElement {
)} )}
</div> </div>
`; `;
let contents = !this.loaded let contents =
? this.loading !this.loaded || this.loading
? html`<div ? html`<div
class="w3-panel w3-theme-l5 w3-card-4 w3-padding-large w3-round-xlarge" class="w3-display-middle w3-panel w3-theme-l5 w3-card-4 w3-padding-large w3-round-xlarge w3-xlarge"
> >
Loading... <span class="w3-spin" style="display: inline-block">🦀</span>
</div> Loading...
${this.render_tab()}` </div>`
: html`<div>Select or create an identity.</div>` : this.render_tab();
: this.render_tab();
return html` return html`
<div <div
style="width: 100vw; min-height: 100vh; height: 100%" style="width: 100vw; min-height: 100vh; height: 100%"

View File

@ -15,6 +15,7 @@ class TfComposeElement extends LitElement {
drafts: {type: Object}, drafts: {type: Object},
author: {type: String}, author: {type: String},
channel: {type: String}, channel: {type: String},
new_thread: {type: Boolean},
}; };
} }
@ -28,6 +29,7 @@ class TfComposeElement extends LitElement {
this.apps = undefined; this.apps = undefined;
this.drafts = {}; this.drafts = {};
this.author = undefined; this.author = undefined;
this.new_thread = false;
} }
process_text(text) { process_text(text) {
@ -200,9 +202,23 @@ class TfComposeElement extends LitElement {
channel: this.channel, channel: this.channel,
}; };
if (this.root || this.branch) { if (this.root || this.branch) {
message.root = this.root; message.root = this.new_thread ? (this.branch ?? this.root) : this.root;
message.branch = this.branch; 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) { if (Object.values(draft.mentions || {}).length) {
message.mentions = Object.values(draft.mentions); 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() { get_draft() {
return this.drafts[this.branch || ''] || {}; return this.drafts[this.branch || ''] || {};
} }
@ -563,6 +593,7 @@ class TfComposeElement extends LitElement {
self.render_mention(x) self.render_mention(x)
)} )}
${this.render_attach_app()} ${this.render_content_warning()} ${this.render_attach_app()} ${this.render_content_warning()}
${this.render_new_thread()}
<button class="w3-button w3-theme-d1" id="submit" @click=${this.submit}> <button class="w3-button w3-theme-d1" id="submit" @click=${this.submit}>
Submit Submit
</button> </button>

View File

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

View File

@ -176,7 +176,7 @@ class TfTabNewsElement extends LitElement {
return html` return html`
<div <div
class="w3-sidebar w3-bar-block w3-theme-d1 w3-collapse w3-animate-left" 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" id="sidebar"
> >
<div <div
@ -216,6 +216,18 @@ class TfTabNewsElement extends LitElement {
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined} style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined}
>🔐private ${this.unread_status('🔐')}</a >🔐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( ${this.channels.map(
(x) => html` (x) => html`
<a <a

View File

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

View File

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

View File

@ -25,6 +25,7 @@
#if defined(__linux__) #if defined(__linux__)
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/stat.h>
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
@ -41,7 +42,102 @@
struct backtrace_state* g_backtrace_state; 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__) #if !TARGET_OS_IPHONE && !defined(__ANDROID__)
static int _tf_command_export(const char* file, int argc, char* argv[]); 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[]) static int _tf_command_import(const char* file, int argc, char* argv[])
{ {
const char* user = "import"; 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; bool show_usage = false;
while (!show_usage) 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("\n%s import [options] [paths...]\n\n", file);
tf_printf("options:\n"); tf_printf("options:\n");
tf_printf(" -u, --user user User into whose account apps will be imported (default: \"import\").\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_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
_create_directories_for_file(db_path, 0700);
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL); tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
if (optind < argc) 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_import(ssb, user, "apps");
} }
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int _tf_command_export(const char* file, int argc, char* argv[]) static int _tf_command_export(const char* file, int argc, char* argv[])
{ {
const char* user = "core"; 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; bool show_usage = false;
while (!show_usage) 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("\n%s export [options] [paths...]\n\n", file);
tf_printf("options:\n"); tf_printf("options:\n");
tf_printf(" -u, --user user User from whose account apps will be exported (default: \"core\").\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(" -h, --help Show this usage information.\n");
tf_printf("\n"); tf_printf("\n");
tf_printf("paths Paths of apps to export (example: /~core/ssb /~user/app).\n"); tf_printf("paths Paths of apps to export (example: /~core/ssb /~user/app).\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -271,6 +373,7 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
} }
} }
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return EXIT_SUCCESS; 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* user = NULL;
const char* identity = 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; const char* content = NULL;
bool show_usage = false; 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("options:\n");
tf_printf(" -u, --user user User owning identity with which to publish.\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(" -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(" -c, --content json JSON content of message to publish.\n");
tf_printf(" -h, --help Show this usage information.\n"); tf_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
int result = EXIT_FAILURE; int result = EXIT_FAILURE;
tf_printf("Posting %s as account %s belonging to %s...\n", content, identity, user); 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); tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
uint8_t private_key[512] = { 0 }; uint8_t private_key[512] = { 0 };
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key))) 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_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
} }
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return result; return result;
} }
static int _tf_command_store_blob(const char* file, int argc, char* argv[]) 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; const char* file_path = NULL;
bool show_usage = false; 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("\n%s store_blob [options]\n\n", file);
tf_printf("options:\n"); 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(" -f, --file file_path Path to file to add to the blob store.\n");
tf_printf(" -h, --help Show this usage information.\n"); tf_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -441,6 +550,7 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
if (!blob_file) if (!blob_file)
{ {
tf_printf("Failed to open %s: %s.\n", file_path, strerror(errno)); tf_printf("Failed to open %s: %s.\n", file_path, strerror(errno));
tf_free((void*)default_db_path);
return EXIT_FAILURE; 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)); tf_printf("Failed to read %s: %s.\n", file_path, strerror(errno));
fclose(blob_file); fclose(blob_file);
tf_free(data); tf_free(data);
tf_free((void*)default_db_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
fclose(blob_file); fclose(blob_file);
char id[256]; char id[256];
_create_directories_for_file(db_path, 0700);
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL); 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)) 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_ssb_destroy(ssb);
tf_free(data); tf_free(data);
tf_free((void*)default_db_path);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int _tf_command_verify(const char* file, int argc, char* argv[]) static int _tf_command_verify(const char* file, int argc, char* argv[])
{ {
const char* identity = 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;
bool show_usage = false; bool show_usage = false;
while (!show_usage) 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("\n%s import [options] [paths...]\n\n", file);
tf_printf("options:\n"); tf_printf("options:\n");
tf_printf(" -i, --identity identity Identity to verify.\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_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE; 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); tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
bool verified = tf_ssb_db_verify(ssb, identity); bool verified = tf_ssb_db_verify(ssb, identity);
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
tf_free((void*)default_db_path);
return verified ? EXIT_SUCCESS : EXIT_FAILURE; return verified ? EXIT_SUCCESS : EXIT_FAILURE;
} }
#endif #endif
@ -673,13 +789,14 @@ static void _shed_privileges()
static int _tf_command_run(const char* file, int argc, char* argv[]) 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 = { tf_run_args_t args = {
.count = 1, .count = 1,
.script = "core/core.js", .script = "core/core.js",
.http_port = 12345, .http_port = 12345,
.https_port = 12346, .https_port = 12346,
.ssb_port = 8008, .ssb_port = 8008,
.db_path = k_db_path_default, .db_path = default_db_path,
}; };
bool show_usage = false; 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(" -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(" -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(" -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(" -k, --ssb-network-key key SSB network key to use.\n");
tf_printf(" -n, --count count Number of instances to run.\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"); 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(" -z, --zip path Zip archive from which to load files.\n");
tf_printf(" -v, --verbose Log raw messages.\n"); tf_printf(" -v, --verbose Log raw messages.\n");
tf_printf(" -h, --help Show this usage information.\n"); tf_printf(" -h, --help Show this usage information.\n");
tf_free((void*)default_db_path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -780,6 +898,7 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
setpgid(0, 0); setpgid(0, 0);
#endif #endif
_create_directories_for_file(args.db_path, 0700);
if (args.count == 1) if (args.count == 1)
{ {
result = _tf_run_task(&args, 0); 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(data);
tf_free(threads); tf_free(threads);
} }
tf_free((void*)default_db_path);
return result; return result;
} }
@ -1088,7 +1208,7 @@ void tf_run_thread_start(const char* zip_path)
.http_port = 12345, .http_port = 12345,
.https_port = 12346, .https_port = 12346,
.ssb_port = 8008, .ssb_port = 8008,
.db_path = k_db_path_default, .db_path = "db.sqlite",
.one_proc = true, .one_proc = true,
.zip = zip_path, .zip = zip_path,
}; };

View File

@ -4222,63 +4222,19 @@ typedef struct _update_settings_t
char room_name[1024]; char room_name[1024];
} update_settings_t; } 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) static void _tf_ssb_update_settings_work(tf_ssb_t* ssb, void* user_data)
{ {
update_settings_t* update = user_data; update_settings_t* update = user_data;
update->is_room = _get_global_setting_bool(ssb, "room", true); sqlite3* db = tf_ssb_acquire_db_reader(ssb);
update->is_replicator = _get_global_setting_bool(ssb, "replicator", true); update->is_room = true;
update->is_peer_exchange = _get_global_setting_bool(ssb, "peer_exchange", true); update->is_replicator = true;
_get_global_setting_string(ssb, "room_name", update->room_name, sizeof(update->room_name)); update->is_peer_exchange = true;
_get_global_setting_string(ssb, "seeds_host", update->seeds_host, sizeof(update->seeds_host)); 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) static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void* user_data)

View File

@ -1681,34 +1681,13 @@ bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* con
return result; 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 tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password)
{ {
bool result = false; bool result = false;
JSValue users_array = JS_UNDEFINED; 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) if (registration_allowed)
{ {
sqlite3_stmt* statement = NULL; 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; 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); 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. ** An SQLite authorizer callback. See https://www.sqlite.org/c3ref/set_authorizer.html for use.
** @param user_data User data registered with the authorizer. ** @param user_data User data registered with the authorizer.

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_blobs(tf_ssb_t* ssb, int delay_ms);
static void _tf_ssb_rpc_start_delete_feeds(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) static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool default_value)
{ {
bool result = 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; blob_wants_work_t* work = user_data;
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection); 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); 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; int64_t timestamp = -1;
if (age == 0) 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; timestamp = now - age * 1000ULL;
} }
sqlite3* db = tf_ssb_acquire_db_reader(ssb); db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement; 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) 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); tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
JSValue full_clock = JS_NewObject(context); 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. */ /* Ask for every identity we know is being followed from local accounts. */
const char** visible = tf_ssb_db_get_all_visible_identities(ssb, depth); 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) static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
{ {
delete_t* delete = 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) if (age <= 0)
{ {
_tf_ssb_rpc_checkpoint(ssb); _tf_ssb_rpc_checkpoint(ssb);
return; return;
} }
int64_t start_ns = uv_hrtime(); int64_t start_ns = uv_hrtime();
sqlite3* db = tf_ssb_acquire_db_writer(ssb); db = tf_ssb_acquire_db_writer(ssb);
sqlite3_stmt* statement; sqlite3_stmt* statement;
int64_t now = (int64_t)time(NULL) * 1000ULL; int64_t now = (int64_t)time(NULL) * 1000ULL;
int64_t timestamp = now - age * 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; return;
} }
int64_t start_ns = uv_hrtime(); 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); const char** identities = tf_ssb_db_get_all_visible_identities(ssb, replication_hops);
JSMallocFunctions funcs = { 0 }; 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, json);
JS_FreeValue(context, array); JS_FreeValue(context, array);
sqlite3* db = tf_ssb_acquire_db_writer(ssb); db = tf_ssb_acquire_db_writer(ssb);
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(db, if (sqlite3_prepare(db,
"DELETE FROM messages WHERE author IN (" "DELETE FROM messages WHERE author IN ("

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." #define VERSION_NAME "This program kills fascists."

View File

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

View File

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

View File

@ -56,7 +56,7 @@ build_the_thing() {
no-uplink no-uplink
no-weak-ssl-ciphers no-weak-ssl-ciphers
no-zlib no-zlib
-Os -Oz
-ffunction-sections -ffunction-sections
-fdata-sections -fdata-sections
-flto -flto