8 Commits

Author SHA1 Message Date
876abb169a build: Support building the sqlite3 CLI from the makefile for convenience. Guarantees it's compatible with the right extensions.
All checks were successful
Build Tilde Friends / Build-Docs (push) Successful in 2m35s
Build Tilde Friends / Build-All (push) Successful in 9m56s
2025-12-29 16:31:47 -05:00
4cbc08eb35 ssb: Very minor CSS things with the blog post form.
All checks were successful
Build Tilde Friends / Build-Docs (push) Successful in 2m31s
Build Tilde Friends / Build-All (push) Successful in 10m4s
2025-12-29 15:46:49 -05:00
f785e7dceb ssb: Support authoring blog messages. #136
All checks were successful
Build Tilde Friends / Build-Docs (push) Successful in 2m26s
Build Tilde Friends / Build-All (push) Successful in 10m33s
2025-12-29 15:26:14 -05:00
f57643d7bc core: uv_strerror can leak. Prefer uv_strerror_r.
All checks were successful
Build Tilde Friends / Build-Docs (push) Successful in 2m42s
Build Tilde Friends / Build-All (push) Successful in 10m24s
2025-12-29 13:27:03 -05:00
c7c62c72e4 build: Next release will be 0.2026.1. 2025-12-29 12:53:52 -05:00
4ba4acbd41 build: Update default.nix. 2025-12-29 12:52:46 -05:00
f7dcd63ae9 ios: Lousy smarch weather.
All checks were successful
Build Tilde Friends / Build-Docs (push) Successful in 2m34s
Build Tilde Friends / Build-All (push) Successful in 10m13s
2025-12-29 12:39:13 -05:00
45d317c716 welcome: Add the aarch64 appimage.
Some checks failed
Build Tilde Friends / Build-Docs (push) Has been cancelled
Build Tilde Friends / Build-All (push) Has been cancelled
2025-12-29 12:33:49 -05:00
22 changed files with 398 additions and 179 deletions

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 := 49 VERSION_CODE := 50
VERSION_NUMBER := 0.2025.12 VERSION_NUMBER := 0.2026.1-wip
VERSION_NAME := This program kills fascists. VERSION_NAME := This program kills fascists.
IPHONEOS_VERSION_MIN=14.5 IPHONEOS_VERSION_MIN=14.5
@@ -89,6 +89,7 @@ CFLAGS += \
-Wall \ -Wall \
-Wextra \ -Wextra \
-Wno-cast-function-type-mismatch \ -Wno-cast-function-type-mismatch \
-Wno-format-truncation \
-Wno-unknown-warning-option \ -Wno-unknown-warning-option \
-Wno-unused-parameter \ -Wno-unused-parameter \
-MMD \ -MMD \
@@ -308,14 +309,14 @@ ifeq ($(UNAME_S),Linux)
all: appimage out/release/tildefriends.standalone 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 out/debug/sqlite3: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined out/debug/tildefriends out/debug/sqlite3: LDFLAGS += -fsanitize=address -fsanitize=undefined
endif endif
endif endif
ifeq ($(UNAME_M),aarch64) ifeq ($(UNAME_M),aarch64)
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common out/debug/tildefriends out/debug/sqlite3: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined out/debug/tildefriends out/debug/sqlite3: LDFLAGS += -fsanitize=address -fsanitize=undefined
endif endif
get_objs = \ get_objs = \
@@ -673,9 +674,10 @@ $(filter-out $(BUILD_DIR)/win%,$(SODIUM_OBJS)): CFLAGS += \
-DHAVE_ALLOCA_H -DHAVE_ALLOCA_H
endif endif
SQLITE_ALL_SOURCES := deps/sqlite/sqlite3.c deps/sqlite/shell.c
SQLITE_SOURCES := deps/sqlite/sqlite3.c SQLITE_SOURCES := deps/sqlite/sqlite3.c
SQLITE_OBJS := $(call get_objs,SQLITE_SOURCES) SQLITE_OBJS := $(call get_objs,SQLITE_SOURCES)
$(SQLITE_OBJS): CFLAGS += \ $(call get_objs,SQLITE_ALL_SOURCES): CFLAGS += \
-DSQLITE_DBCONFIG_DEFAULT_DEFENSIVE \ -DSQLITE_DBCONFIG_DEFAULT_DEFENSIVE \
-DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_DQS=0 \ -DSQLITE_DQS=0 \
@@ -822,7 +824,7 @@ $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
## ##
## Common targets: ## Common targets:
## ##
all: $(BUILD_TYPES) ## Build all targets that appear possible to build on this machine. all: $(BUILD_TYPES) out/debug/sqlite3 out/release/sqlite3 ## Build all targets that appear possible to build on this machine.
debug: ## Build a debug executable for the current host platform. debug: ## Build a debug executable for the current host platform.
release: ## Build a release executable for the current host platform. release: ## Build a release executable for the current host platform.
armdebug: ## Cross-compile aarch64 debug on Linux. armdebug: ## Cross-compile aarch64 debug on Linux.
@@ -870,6 +872,10 @@ $(BUILD_DIR)/$(1)/%.o: %.S
@$$(AS) -c $$< -o $$@ @$$(AS) -c $$< -o $$@
endef endef
out/%/sqlite3 : out/%/deps/sqlite/sqlite3.o out/%/deps/sqlite/shell.o
@echo "[link] $@"
@$(CC) -o $@ $^ $(LDFLAGS)
$(foreach build_type,$(BUILD_TYPES),$(eval $(call build_rules,$(build_type)))) $(foreach build_type,$(BUILD_TYPES),$(eval $(call build_rules,$(build_type))))
src/version.h : $(firstword $(MAKEFILE_LIST)) src/version.h : $(firstword $(MAKEFILE_LIST))

View File

@@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "🦀", "emoji": "🦀",
"previous": "&PrgfYYKpL2tedApJXokIIk+h9/yRYo0aUliNF3QsnZ4=.sha256" "previous": "&4tVt4bblxxJp54qNl0T6kUYoKNUVOwsn5OFkJuelgqo=.sha256"
} }

View File

@@ -77,12 +77,16 @@ class TfComposeElement extends LitElement {
input(event) { input(event) {
let edit = this.renderRoot.getElementById('edit'); let edit = this.renderRoot.getElementById('edit');
let preview = this.renderRoot.getElementById('preview'); let edit_title = this.renderRoot.getElementById('edit_title');
preview.innerHTML = this.process_text(edit.innerText); let edit_summary = this.renderRoot.getElementById('edit_summary');
let content_warning = this.renderRoot.getElementById('content_warning'); let content_warning = this.renderRoot.getElementById('content_warning');
let draft = this.get_draft(); let draft = this.get_draft();
draft.text = edit.innerText; draft.text = edit.innerText;
draft.content_warning = content_warning?.value; draft.content_warning = content_warning?.value;
if (draft.type == 'blog') {
draft.title = edit_title.value;
draft.summary = edit_summary.value;
}
setTimeout(() => this.notify(draft), 0); setTimeout(() => this.notify(draft), 0);
} }
@@ -130,9 +134,7 @@ class TfComposeElement extends LitElement {
}); });
} }
async add_file(file) { async file_to_blob_id(file) {
try {
let draft = this.get_draft();
let self = this; let self = this;
let buffer = await file.arrayBuffer(); let buffer = await file.arrayBuffer();
let type = file.type; let type = file.type;
@@ -155,7 +157,13 @@ class TfComposeElement extends LitElement {
} else { } else {
buffer = Array.from(new Uint8Array(buffer)); buffer = Array.from(new Uint8Array(buffer));
} }
let id = await tfrpc.rpc.store_blob(buffer); return {id: await tfrpc.rpc.store_blob(buffer), type: type, buffer, buffer};
}
async add_file(file) {
try {
let draft = this.get_draft();
let {id, type, buffer} = await this.file_to_blob_id(file);
let name = type.split('/')[0] + ':' + file.name; let name = type.split('/')[0] + ':' + file.name;
if (!draft.mentions) { if (!draft.mentions) {
draft.mentions = {}; draft.mentions = {};
@@ -166,11 +174,10 @@ class TfComposeElement extends LitElement {
type: type, type: type,
size: buffer.length ?? buffer.byteLength, size: buffer.length ?? buffer.byteLength,
}; };
let edit = self.renderRoot.getElementById('edit'); draft.text = (draft.text ?? '') + `\n![${name}](${id})`;
edit.innerText += `\n![${name}](${id})`; this.notify(draft);
self.input();
} catch (e) { } catch (e) {
alert(e?.message); alert(e?.message + e?.stack);
} }
} }
@@ -198,10 +205,28 @@ class TfComposeElement extends LitElement {
async submit() { async submit() {
let self = this; let self = this;
let draft = this.get_draft(); let draft = this.get_draft();
let edit = this.renderRoot.getElementById('edit'); if (draft.type == 'blog') {
let message = {
type: 'blog',
title: draft.title,
summary: draft.summary,
thumbnail: draft.thumbnail,
blog: await tfrpc.rpc.store_blob(draft.text),
};
if (Object.values(draft.mentions || {}).length) {
message.mentions = Object.values(draft.mentions);
}
console.log('Would post:', message);
try {
await tfrpc.rpc.appendMessage(this.whoami, message);
self.notify(undefined);
} catch (error) {
alert(error.message);
}
} else {
let message = { let message = {
type: 'post', type: 'post',
text: edit.innerText, text: draft.text,
channel: this.channel, channel: this.channel,
}; };
if (this.root || this.branch) { if (this.root || this.branch) {
@@ -249,6 +274,7 @@ class TfComposeElement extends LitElement {
alert(error.message); alert(error.message);
} }
} }
}
discard() { discard() {
this.notify(undefined); this.notify(undefined);
@@ -344,8 +370,7 @@ class TfComposeElement extends LitElement {
super.updated(); super.updated();
let edit = this.renderRoot.getElementById('edit'); let edit = this.renderRoot.getElementById('edit');
if (this.last_updated_text !== edit.innerText) { if (this.last_updated_text !== edit.innerText) {
let preview = this.renderRoot.getElementById('preview'); this.process_text(edit.innerText);
preview.innerHTML = this.process_text(edit.innerText);
this.last_updated_text = edit.innerText; this.last_updated_text = edit.innerText;
} }
this._tribute.collection[0].values = this.get_values(); this._tribute.collection[0].values = this.get_values();
@@ -584,6 +609,100 @@ class TfComposeElement extends LitElement {
} }
} }
can_be_blog() {
let draft = this.get_draft();
return (
this.root === undefined &&
this.branch === undefined &&
draft.encrypt_to === undefined
);
}
set_type(type) {
let draft = this.get_draft();
draft.type = type;
this.notify(draft);
}
render_post_form(draft) {
return html`
<style>
.w3-input:empty::before {
content: attr(placeholder);
opacity: 0.5;
}
.w3-input:empty:focus::before {
content: '';
}
</style>
<span
class="w3-input w3-theme-d1 w3-border"
style="resize: vertical; width: 100%; white-space: pre-wrap"
placeholder="Write a post here."
id="edit"
@input=${this.input}
@paste=${this.paste}
contenteditable="plaintext-only"
.innerText=${live(draft.text ?? '')}
></span>
`;
}
blog_set_image() {
let self = this;
let input = document.createElement('input');
input.type = 'file';
input.addEventListener('change', async function (event) {
input.parentNode.removeChild(input);
let file = event.target.files[0];
let {id} = await self.file_to_blob_id(file);
let draft = self.get_draft();
draft.thumbnail = id;
self.notify(draft);
});
document.body.appendChild(input);
input.click();
}
blog_clear_image() {
let draft = this.get_draft();
delete draft.thumbnail;
this.notify(draft);
}
render_blog_form(draft) {
return html`
<style>
.w3-input:empty::before {
content: attr(placeholder);
opacity: 0.5;
}
.w3-input:empty:focus::before {
content: '';
}
</style>
<label for="edit_title">Title</label>
<input class="w3-input w3-theme-d1" type="text" placeholder="Enter blog post title." id="edit_title" @input=${this.input} value=${live(draft.title)}></input>
<label for="edit_summary">Summary</label>
<textarea class="w3-input w3-theme-d1" placeholder="Enter blog post summary." id="edit_summary" @input=${this.input}>${draft.summary}</textarea>
<label for="edit">Post</label>
<span
class="w3-input w3-theme-d1"
style="resize: vertical; width: 100%; white-space: pre-wrap"
placeholder="Write blog post here."
id="edit"
@input=${this.input}
@paste=${this.paste}
contenteditable="plaintext-only"
.innerText=${live(draft.text ?? '')}
></span>
<div class="w3-margin-top">
<button class="w3-button w3-theme-d1" @click=${this.blog_set_image}>Set Banner Image</button>
${draft.thumbnail ? html`<button class="w3-button w3-theme-d1" @click=${this.blog_clear_image}>Remove Banner Image</button>` : undefined}
</div>
`;
}
render() { render() {
let self = this; let self = this;
let draft = self.get_draft(); let draft = self.get_draft();
@@ -606,14 +725,6 @@ class TfComposeElement extends LitElement {
<style> <style>
${generate_theme()} ${generate_theme()}
</style> </style>
<style>
.w3-input:empty::before {
content: attr(placeholder);
}
.w3-input:empty:focus::before {
content: '';
}
</style>
<div <div
class="w3-card-4 w3-theme-d4 w3-padding w3-margin-top w3-margin-bottom" class="w3-card-4 w3-theme-d4 w3-padding w3-margin-top w3-margin-bottom"
style="box-sizing: border-box" style="box-sizing: border-box"
@@ -626,20 +737,26 @@ class TfComposeElement extends LitElement {
</header> </header>
<div class="w3-container" style="padding: 0 0 16px 0"> <div class="w3-container" style="padding: 0 0 16px 0">
<div class="w3-half"> <div class="w3-half">
<span ${draft.type === undefined || draft.type === 'post'
class="w3-input w3-theme-d1 w3-border" ? this.render_post_form(draft)
style="resize: vertical; width: 100%; white-space: pre-wrap" : this.render_blog_form(draft)}
placeholder="Write a post here."
id="edit"
@input=${this.input}
@paste=${this.paste}
contenteditable="plaintext-only"
.innerText=${live(draft.text ?? '')}
></span>
</div> </div>
<div class="w3-half w3-container"> <div class="w3-half w3-container">
${content_warning} ${content_warning}
<p id="preview"></p> ${draft.type === 'blog' && draft.title
? html`<h3>${unsafeHTML(tfutils.markdown(draft.title))}</h3>`
: undefined}
${draft.type === 'blog' && draft.summary
? html`<div class="w3-panel w3-theme-d1">
${unsafeHTML(tfutils.markdown(draft.summary))}
</div>`
: undefined}
${draft.type === 'blog' && draft.thumbnail
? html`<img src=${'/' + draft.thumbnail + '/view'} />`
: undefined}
<p id="preview">
${unsafeHTML(tfutils.markdown(draft.text ?? ''))}
</p>
</div> </div>
</div> </div>
${Object.values(draft.mentions || {}).map((x) => ${Object.values(draft.mentions || {}).map((x) =>
@@ -683,6 +800,23 @@ class TfComposeElement extends LitElement {
> >
Attach Attach
</button> </button>
${(draft.type === undefined || draft.type === 'post') &&
this.can_be_blog()
? html` <button
class="w3-button w3-bar-item w3-theme-d1"
@click=${() => this.set_type('blog')}
>
Make Blog Post
</button>`
: undefined}
${draft.type === 'blog'
? html` <button
class="w3-button w3-bar-item w3-theme-d1"
@click=${() => this.set_type('post')}
>
Make Post
</button>`
: undefined}
${this.render_attach_app_button()} ${encrypt} ${this.render_attach_app_button()} ${encrypt}
<button <button
class="w3-button w3-bar-item w3-theme-d1" class="w3-button w3-bar-item w3-theme-d1"

View File

@@ -1008,9 +1008,10 @@ class TfMessageElement extends LitElement {
.users=${this.users} .users=${this.users}
></tf-user> ></tf-user>
</div> </div>
${this.render_menu()} ${this.render_votes()} ${this.render_menu()}
${this.render_refs()} ${this.render_actions()}
</div> </div>
${this.render_votes()} ${this.render_refs()}
${this.render_actions()}
`); `);
break; break;
case 'raw': case 'raw':

View File

@@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "👋", "emoji": "👋",
"previous": "&sVSmI40DUgnS4TUa2AiKrlNj+qN3WDeXII3364OSMIo=.sha256" "previous": "&8rKGBsPducu7WpnOVm9b5A3OZk5hFVI9RsxeFS9c0lk=.sha256"
} }

View File

@@ -143,17 +143,24 @@
<h3>Desktop</h3> <h3>Desktop</h3>
<p> <p>
<a <a
class="w3-button w3-round-large w3-black w3-padding-large" class="w3-button w3-round-large w3-black w3-padding-large w3-margin-top"
href="https://dev.tildefriends.net/cory/tildefriends/releases" href="https://dev.tildefriends.net/cory/tildefriends/releases"
><i class="fa fa-download"></i> Download</a ><i class="fa fa-download"></i> Download</a
> >
<a <a
class="w3-button w3-round-large w3-padding w3-blue-gray" class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage" href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
> >
<img src="appimage.svg" style="height: 2em; margin: 0" /> <img src="appimage.svg" style="height: 2em; margin: 0" />
Get Linux x86_64 AppImage Get Linux x86_64 AppImage
</a> </a>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://dev.tildefriends.net/releases/tildefriends-aarch64.AppImage"
>
<img src="appimage.svg" style="height: 2em; margin: 0" />
Get Linux aarch64 AppImage
</a>
</p> </p>
<p> <p>
Tilde Friends is distributed as a single executable file (or Tilde Friends is distributed as a single executable file (or

View File

@@ -25,14 +25,14 @@
}: }:
pkgs.stdenv.mkDerivation rec { pkgs.stdenv.mkDerivation rec {
pname = "tildefriends"; pname = "tildefriends";
version = "0.2025.11"; version = "0.2025.12";
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-z4v4ghKOBTMv+agTUKg+HU8zfE4imluXFsozQCT4qX8="; hash = "sha256-SSHsZLo3BVoK34cd+fN3ANEXAlj8cXLGm6EnjdMSFAo=";
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="49" android:versionCode="50"
android:versionName="0.2025.12"> android:versionName="0.2026.1-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

@@ -63,7 +63,8 @@ static void _file_read_read_callback(uv_fs_t* req)
} }
else else
{ {
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to read %s: %s", req->path, uv_strerror(req->result))); char buffer[256];
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to read %s: %s", req->path, uv_strerror_r(req->result, buffer, sizeof(buffer))));
} }
uv_fs_req_cleanup(req); uv_fs_req_cleanup(req);
int result = uv_fs_close(req->loop, req, fsreq->file, _file_async_close_callback); int result = uv_fs_close(req->loop, req, fsreq->file, _file_async_close_callback);
@@ -89,7 +90,8 @@ static void _file_read_open_callback(uv_fs_t* req)
int result = uv_fs_read(req->loop, req, fsreq->file, &buf, 1, 0, _file_read_read_callback); int result = uv_fs_read(req->loop, req, fsreq->file, &buf, 1, 0, _file_read_read_callback);
if (result < 0) if (result < 0)
{ {
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to read %s: %s", path, uv_strerror(result))); char buffer[256];
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to read %s: %s", path, uv_strerror_r(result, buffer, sizeof(buffer))));
result = uv_fs_close(req->loop, req, fsreq->file, _file_async_close_callback); result = uv_fs_close(req->loop, req, fsreq->file, _file_async_close_callback);
if (result < 0) if (result < 0)
{ {
@@ -100,7 +102,8 @@ static void _file_read_open_callback(uv_fs_t* req)
} }
else else
{ {
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to open %s for read: %s", path, uv_strerror(req->result))); char buffer[256];
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to open %s for read: %s", path, uv_strerror_r(req->result, buffer, sizeof(buffer))));
uv_fs_req_cleanup(req); uv_fs_req_cleanup(req);
tf_free(req); tf_free(req);
} }
@@ -128,7 +131,8 @@ static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int ar
int result = uv_fs_open(tf_task_get_loop(task), &req->fs, actual, UV_FS_O_RDONLY, 0, _file_read_open_callback); int result = uv_fs_open(tf_task_get_loop(task), &req->fs, actual, UV_FS_O_RDONLY, 0, _file_read_open_callback);
if (result < 0) if (result < 0)
{ {
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to open %s for read: %s", file_name, uv_strerror(result))); char buffer[256];
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to open %s for read: %s", file_name, uv_strerror_r(result, buffer, sizeof(buffer))));
uv_fs_req_cleanup(&req->fs); uv_fs_req_cleanup(&req->fs);
tf_free(req); tf_free(req);
} }
@@ -243,7 +247,8 @@ static JSValue _file_read_file_zip(JSContext* context, JSValueConst this_val, in
int r = uv_queue_work(tf_task_get_loop(task), &work->request, _file_read_file_zip_work, _file_read_file_zip_after_work); int r = uv_queue_work(tf_task_get_loop(task), &work->request, _file_read_file_zip_work, _file_read_file_zip_after_work);
if (r) if (r)
{ {
tf_task_reject_promise(task, work->promise, JS_ThrowInternalError(context, "Failed to create read work for %s: %s", file_name, uv_strerror(r))); char buffer[256];
tf_task_reject_promise(task, work->promise, JS_ThrowInternalError(context, "Failed to create read work for %s: %s", file_name, uv_strerror_r(r, buffer, sizeof(buffer))));
tf_free((void*)work->file_path); tf_free((void*)work->file_path);
tf_free(work); tf_free(work);
} }

View File

@@ -585,7 +585,8 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
} }
else if (read_size < 0) else if (read_size < 0)
{ {
_http_connection_destroy(connection, uv_strerror(read_size)); char buffer[256];
_http_connection_destroy(connection, uv_strerror_r(read_size, buffer, sizeof(buffer)));
} }
} }
@@ -601,12 +602,14 @@ static void _http_timer_reset(tf_http_connection_t* connection)
int r = uv_timer_stop(&connection->timeout); int r = uv_timer_stop(&connection->timeout);
if (r) if (r)
{ {
tf_printf("uv_timer_stop: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_timer_stop: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0); r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0);
if (r) if (r)
{ {
tf_printf("uv_timer_start: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_timer_start: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
} }
} }
@@ -626,7 +629,8 @@ static void _http_on_connection(uv_stream_t* stream, int status)
int r = uv_tcp_init(connection->http->loop, &connection->tcp); int r = uv_tcp_init(connection->http->loop, &connection->tcp);
if (r) if (r)
{ {
tf_printf("uv_tcp_init: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_tcp_init: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
_http_connection_destroy(connection, "uv_tcp_init"); _http_connection_destroy(connection, "uv_tcp_init");
return; return;
} }
@@ -635,14 +639,16 @@ static void _http_on_connection(uv_stream_t* stream, int status)
connection->timeout.data = connection; connection->timeout.data = connection;
if (r) if (r)
{ {
tf_printf("uv_timer_init: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_timer_init: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
_http_connection_destroy(connection, "uv_timer_init"); _http_connection_destroy(connection, "uv_timer_init");
return; return;
} }
r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0); r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0);
if (r) if (r)
{ {
tf_printf("uv_timer_start: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_timer_start: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
_http_connection_destroy(connection, "uv_timer_start"); _http_connection_destroy(connection, "uv_timer_start");
return; return;
} }
@@ -650,7 +656,8 @@ static void _http_on_connection(uv_stream_t* stream, int status)
r = uv_accept(stream, (uv_stream_t*)&connection->tcp); r = uv_accept(stream, (uv_stream_t*)&connection->tcp);
if (r) if (r)
{ {
tf_printf("uv_accept: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_accept: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
_http_connection_destroy(connection, "uv_accept"); _http_connection_destroy(connection, "uv_accept");
return; return;
} }
@@ -658,7 +665,8 @@ static void _http_on_connection(uv_stream_t* stream, int status)
r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read); r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read);
if (r) if (r)
{ {
tf_printf("uv_read_start: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_read_start: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
_http_connection_destroy(connection, "uv_read_start"); _http_connection_destroy(connection, "uv_read_start");
return; return;
} }
@@ -679,7 +687,8 @@ int tf_http_listen(tf_http_t* http, int port, bool local_only, tf_http_cleanup_t
int r = uv_tcp_init(http->loop, &listener->tcp); int r = uv_tcp_init(http->loop, &listener->tcp);
if (r) if (r)
{ {
tf_printf("uv_tcp_init: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_tcp_init: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
if (r == 0) if (r == 0)
@@ -709,7 +718,8 @@ int tf_http_listen(tf_http_t* http, int port, bool local_only, tf_http_cleanup_t
r = uv_tcp_bind(&listener->tcp, addr, 0); r = uv_tcp_bind(&listener->tcp, addr, 0);
if (r) if (r)
{ {
tf_printf("%s:%d: uv_tcp_bind: %s\n", __FILE__, __LINE__, uv_strerror(r)); char buffer[256];
tf_printf("%s:%d: uv_tcp_bind: %s\n", __FILE__, __LINE__, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
} }
@@ -727,7 +737,8 @@ int tf_http_listen(tf_http_t* http, int port, bool local_only, tf_http_cleanup_t
r = uv_listen((uv_stream_t*)&listener->tcp, 16, _http_on_connection); r = uv_listen((uv_stream_t*)&listener->tcp, 16, _http_on_connection);
if (r) if (r)
{ {
tf_printf("uv_listen: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_listen: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
} }
@@ -906,7 +917,8 @@ static void _http_write_internal(tf_http_connection_t* connection, const void* d
int r = uv_write(write, (uv_stream_t*)&connection->tcp, &(uv_buf_t) { .base = (void*)(write + 1), .len = size }, 1, _http_on_write); int r = uv_write(write, (uv_stream_t*)&connection->tcp, &(uv_buf_t) { .base = (void*)(write + 1), .len = size }, 1, _http_on_write);
if (r) if (r)
{ {
tf_printf("uv_write: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_write: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
} }
} }

View File

@@ -13,13 +13,13 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.2025.12</string> <string>0.2026.1</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
<array> <array>
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>49</string> <string>50</string>
<key>DTPlatformName</key> <key>DTPlatformName</key>
<string>iphoneos</string> <string>iphoneos</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View File

@@ -1940,7 +1940,8 @@ static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir,
int result = uv_chdir(files); int result = uv_chdir(files);
if (result) if (result)
{ {
tf_printf("uv_chdir: %s\n", uv_strerror(result)); char buffer[256];
tf_printf("uv_chdir: %s\n", uv_strerror_r(result, buffer, sizeof(buffer)));
} }
size_t args_length = strlen(out_port_file) + strlen("--args=http_port=0,out_http_port_file=") + 1; size_t args_length = strlen(out_port_file) + strlen("--args=http_port=0,out_http_port_file=") + 1;

View File

@@ -133,7 +133,8 @@ void tf_packetstream_start(tf_packetstream_t* stream)
int result = uv_read_start((uv_stream_t*)&stream->stream, _packetstream_allocate, _packetstream_on_read); int result = uv_read_start((uv_stream_t*)&stream->stream, _packetstream_allocate, _packetstream_on_read);
if (result) if (result)
{ {
tf_printf("uv_read_start: %s\n", uv_strerror(result)); char buffer[256];
tf_printf("uv_read_start: %s\n", uv_strerror_r(result, buffer, sizeof(buffer)));
} }
} }
@@ -162,7 +163,8 @@ void tf_packetstream_send(tf_packetstream_t* stream, int packet_type, const char
int result = uv_write(request, (uv_stream_t*)&stream->stream, &write_buffer, 1, _packetstream_on_write); int result = uv_write(request, (uv_stream_t*)&stream->stream, &write_buffer, 1, _packetstream_on_write);
if (result) if (result)
{ {
tf_printf("tf_packetstream_send: uv_write: %s\n", uv_strerror(result)); char buffer[256];
tf_printf("tf_packetstream_send: uv_write: %s\n", uv_strerror_r(result, buffer, sizeof(buffer)));
tf_free(request); tf_free(request);
} }
} }

View File

@@ -473,7 +473,7 @@ static void _tf_ssb_connection_on_write(uv_write_t* req, int status)
if (status) if (status)
{ {
char buffer[256]; char buffer[256];
snprintf(buffer, sizeof(buffer), "write failed asynchronously: %s", uv_strerror(status)); tf_util_uv_error_buf(buffer, sizeof(buffer), "write failed asynchronously: ", status);
tf_ssb_connection_close(connection, buffer); tf_ssb_connection_close(connection, buffer);
} }
tf_free(req); tf_free(req);
@@ -492,7 +492,7 @@ static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t si
{ {
tf_ssb_connection_adjust_write_count(connection, -1); tf_ssb_connection_adjust_write_count(connection, -1);
char buffer[256]; char buffer[256];
snprintf(buffer, sizeof(buffer), "write failed: %s", uv_strerror(result)); tf_util_uv_error_buf(buffer, sizeof(buffer), "write failed: ", result);
tf_ssb_connection_close(connection, buffer); tf_ssb_connection_close(connection, buffer);
tf_free(write); tf_free(write);
} }
@@ -2233,7 +2233,8 @@ static void _tf_ssb_connection_on_tcp_recv_internal(tf_ssb_connection_t* connect
} }
else else
{ {
tf_ssb_connection_close(connection, uv_strerror(nread)); char buffer[256];
tf_ssb_connection_close(connection, tf_util_uv_error_buf(buffer, sizeof(buffer), "read: ", nread));
} }
} }
@@ -2275,7 +2276,7 @@ static bool _tf_ssb_connection_read_start(tf_ssb_connection_t* connection)
if (result && result != UV_EALREADY) if (result && result != UV_EALREADY)
{ {
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_read_start failed: %s", uv_strerror(result)); tf_util_uv_error_buf(reason, sizeof(reason), "uv_read_start failed: ", result);
tf_ssb_connection_close(connection, reason); tf_ssb_connection_close(connection, reason);
return false; return false;
} }
@@ -2290,7 +2291,7 @@ static bool _tf_ssb_connection_read_stop(tf_ssb_connection_t* connection)
if (result && result != UV_EALREADY) if (result && result != UV_EALREADY)
{ {
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_read_stop failed: %s", uv_strerror(result)); tf_util_uv_error_buf(reason, sizeof(reason), "uv_read_stop failed: ", result);
tf_ssb_connection_close(connection, reason); tf_ssb_connection_close(connection, reason);
return false; return false;
} }
@@ -2312,7 +2313,7 @@ static void _tf_ssb_connection_on_connect(uv_connect_t* connect, int status)
else else
{ {
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_tcp_connect failed: %s", uv_strerror(status)); tf_util_uv_error_buf(reason, sizeof(reason), "uv_tcp_connect failed: ", status);
tf_ssb_connection_close(connection, reason); tf_ssb_connection_close(connection, reason);
} }
} }
@@ -2825,7 +2826,8 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
int r = uv_loop_close(ssb->loop); int r = uv_loop_close(ssb->loop);
if (r != 0 && !ssb->quiet) if (r != 0 && !ssb->quiet)
{ {
tf_printf("uv_loop_close: %s\n", uv_strerror(r)); char buffer[256];
tf_printf("uv_loop_close: %s\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
} }
if (!ssb->quiet) if (!ssb->quiet)
@@ -3031,8 +3033,10 @@ static tf_ssb_connection_t* _tf_ssb_connection_create(
int result = uv_tcp_connect(&connection->connect, &connection->tcp, (const struct sockaddr*)addr, _tf_ssb_connection_on_connect); int result = uv_tcp_connect(&connection->connect, &connection->tcp, (const struct sockaddr*)addr, _tf_ssb_connection_on_connect);
if (result) if (result)
{ {
char prefix[256];
snprintf(prefix, sizeof(prefix), "uv_tcp_connect(%s): ", host);
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_tcp_connect(%s) => %s", host, uv_strerror(result)); tf_util_uv_error_buf(reason, sizeof(reason), prefix, result);
connection->connect.data = NULL; connection->connect.data = NULL;
_tf_ssb_connection_destroy(connection, reason); _tf_ssb_connection_destroy(connection, reason);
} }
@@ -3138,8 +3142,10 @@ static void _tf_on_connect_getaddrinfo(uv_getaddrinfo_t* addrinfo, int result, s
} }
else if (connect->callback) else if (connect->callback)
{ {
char prefix[256];
snprintf(prefix, sizeof(prefix), "uv_getaddrinfo(%s): ", connect->host);
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_getaddrinfo(%s) => %s", connect->host, uv_strerror(result)); tf_util_uv_error_buf(reason, sizeof(reason), prefix, result);
connect->callback(NULL, reason, connect->user_data); connect->callback(NULL, reason, connect->user_data);
} }
} }
@@ -3183,13 +3189,15 @@ void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* ke
int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET }); int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET });
if (r < 0) if (r < 0)
{ {
char prefix[256];
snprintf(prefix, sizeof(prefix), "uv_getaddrinfo(%s): ", connect->host);
char reason[1024];
tf_util_uv_error_buf(reason, sizeof(reason), prefix, r);
if (callback) if (callback)
{ {
char reason[1024];
snprintf(reason, sizeof(reason), "uv_getaddr_info(%s): %s", host, uv_strerror(r));
callback(NULL, reason, user_data); callback(NULL, reason, user_data);
} }
tf_printf("uv_getaddrinfo(%s): %s\n", host, uv_strerror(r)); tf_printf("%s\n", reason);
tf_free(connect); tf_free(connect);
tf_ssb_unref(ssb); tf_ssb_unref(ssb);
} }
@@ -3233,13 +3241,15 @@ static void _tf_ssb_connect_with_invite(
int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET }); int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET });
if (r < 0) if (r < 0)
{ {
char prefix[256];
snprintf(prefix, sizeof(prefix), "uv_getaddrinfo(%s): ", connect->host);
char reason[1024];
tf_util_uv_error_buf(reason, sizeof(reason), prefix, r);
if (callback) if (callback)
{ {
char reason[1024];
snprintf(reason, sizeof(reason), "uv_getaddr_info(%s): %s", host, uv_strerror(r));
callback(NULL, reason, user_data); callback(NULL, reason, user_data);
} }
tf_printf("uv_getaddrinfo(%s): %s\n", host, uv_strerror(r)); tf_printf("%s\n", reason);
tf_free(connect); tf_free(connect);
tf_ssb_unref(ssb); tf_ssb_unref(ssb);
} }
@@ -3250,7 +3260,8 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
tf_ssb_t* ssb = stream->data; tf_ssb_t* ssb = stream->data;
if (status < 0) if (status < 0)
{ {
tf_printf("uv_listen failed: %s\n", uv_strerror(status)); char buffer[256];
tf_printf("uv_listen failed: %s\n", uv_strerror_r(status, buffer, sizeof(buffer)));
return; return;
} }
@@ -3267,7 +3278,7 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
{ {
connection->tcp.data = NULL; connection->tcp.data = NULL;
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_tcp_init() => %s", uv_strerror(result)); tf_util_uv_error_buf(reason, sizeof(reason), "uv_tcp_init: ", result);
_tf_ssb_connection_destroy(connection, reason); _tf_ssb_connection_destroy(connection, reason);
return; return;
} }
@@ -3276,7 +3287,7 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
if (result != 0) if (result != 0)
{ {
char reason[1024]; char reason[1024];
snprintf(reason, sizeof(reason), "uv_accept() => %s", uv_strerror(result)); tf_util_uv_error_buf(reason, sizeof(reason), "uv_accept: ", result);
_tf_ssb_connection_destroy(connection, reason); _tf_ssb_connection_destroy(connection, reason);
return; return;
} }
@@ -3307,7 +3318,8 @@ static void _tf_ssb_update_broadcast_result(tf_ssb_t* ssb, struct sockaddr* addr
{ {
char broadcast_str[256] = { 0 }; char broadcast_str[256] = { 0 };
uv_ip4_name((struct sockaddr_in*)address, broadcast_str, sizeof(broadcast_str)); uv_ip4_name((struct sockaddr_in*)address, broadcast_str, sizeof(broadcast_str));
tf_printf("Unable to send broadcast for %s via %s (%d): %s.\n", address_str, broadcast_str, result, uv_strerror(result)); char buffer[256];
tf_printf("Unable to send broadcast for %s via %s (%d): %s.\n", address_str, broadcast_str, result, uv_strerror_r(result, buffer, sizeof(buffer)));
} }
ssb->broadcast_results[i].result = result; ssb->broadcast_results[i].result = result;
} }
@@ -3334,7 +3346,8 @@ static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, s
int r = uv_tcp_getsockname(&ssb->server, &server_addr, &len); int r = uv_tcp_getsockname(&ssb->server, &server_addr, &len);
if (r != 0) if (r != 0)
{ {
tf_printf("Unable to get server's address: %s.\n", uv_strerror(r)); char buffer[256];
tf_printf("Unable to get server's address: %s.\n", uv_strerror_r(r, buffer, sizeof(buffer)));
} }
else if (server_addr.sa_family != AF_INET) else if (server_addr.sa_family != AF_INET)
{ {
@@ -3472,14 +3485,16 @@ int tf_ssb_server_open(tf_ssb_t* ssb, int port)
int status = uv_tcp_bind(&ssb->server, (struct sockaddr*)&addr, 0); int status = uv_tcp_bind(&ssb->server, (struct sockaddr*)&addr, 0);
if (status != 0) if (status != 0)
{ {
tf_printf("%s:%d: uv_tcp_bind failed: %s\n", __FILE__, __LINE__, uv_strerror(status)); char buffer[256];
tf_printf("%s:%d: uv_tcp_bind failed: %s\n", __FILE__, __LINE__, uv_strerror_r(status, buffer, sizeof(buffer)));
return 0; return 0;
} }
status = uv_listen((uv_stream_t*)&ssb->server, SOMAXCONN, _tf_ssb_on_connection); status = uv_listen((uv_stream_t*)&ssb->server, SOMAXCONN, _tf_ssb_on_connection);
if (status != 0) if (status != 0)
{ {
tf_printf("uv_listen failed: %s\n", uv_strerror(status)); char buffer[256];
tf_printf("uv_listen failed: %s\n", uv_strerror_r(status, buffer, sizeof(buffer)));
/* TODO: cleanup */ /* TODO: cleanup */
return 0; return 0;
} }
@@ -3739,13 +3754,15 @@ void tf_ssb_broadcast_listener_start(tf_ssb_t* ssb, bool linger)
int result = uv_udp_bind(&ssb->broadcast_listener, (const struct sockaddr*)&addr, UV_UDP_REUSEADDR); int result = uv_udp_bind(&ssb->broadcast_listener, (const struct sockaddr*)&addr, UV_UDP_REUSEADDR);
if (result != 0) if (result != 0)
{ {
tf_printf("bind: %s\n", uv_strerror(result)); char buffer[256];
tf_printf("bind: %s\n", uv_strerror_r(result, buffer, sizeof(buffer)));
} }
result = uv_udp_recv_start(&ssb->broadcast_listener, _tf_ssb_on_broadcast_listener_alloc, _tf_ssb_on_broadcast_listener_recv); result = uv_udp_recv_start(&ssb->broadcast_listener, _tf_ssb_on_broadcast_listener_alloc, _tf_ssb_on_broadcast_listener_recv);
if (result != 0) if (result != 0)
{ {
tf_printf("uv_udp_recv_start: %s\n", uv_strerror(result)); char buffer[256];
tf_printf("uv_udp_recv_start: %s\n", uv_strerror_r(result, buffer, sizeof(buffer)));
} }
if (!linger) if (!linger)

View File

@@ -1055,7 +1055,8 @@ static void _tf_ssb_db_blob_store_after_work(tf_ssb_t* ssb, int status, void* us
} }
if (status != 0) if (status != 0)
{ {
tf_printf("tf_ssb_db_blob_store_async -> uv_queue_work failed asynchronously: %s\n", uv_strerror(status)); char buffer[256];
tf_printf("tf_ssb_db_blob_store_async -> uv_queue_work failed asynchronously: %s\n", uv_strerror_r(status, buffer, sizeof(buffer)));
} }
if (blob_work->callback) if (blob_work->callback)
{ {

View File

@@ -69,7 +69,8 @@ static void _tf_ssb_export_scandir(uv_fs_t* req)
int r = uv_fs_unlink(tf_ssb_get_loop(export->ssb), &req, path, NULL); int r = uv_fs_unlink(tf_ssb_get_loop(export->ssb), &req, path, NULL);
if (r) if (r)
{ {
tf_printf("Failed to unlink %s: %s.\n", path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to unlink %s: %s.\n", path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
tf_free(path); tf_free(path);
@@ -197,7 +198,8 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &export.req, file_path, 0, _tf_ssb_export_scandir); int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &export.req, file_path, 0, _tf_ssb_export_scandir);
if (r) if (r)
{ {
tf_printf("Failed to scan directory %s: %s.\n", file_path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to scan directory %s: %s.\n", file_path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
while (!export.done) while (!export.done)
{ {

View File

@@ -100,7 +100,8 @@ static char* _tf_ssb_import_read_file(uv_loop_t* loop, const char* path, size_t*
} }
else else
{ {
tf_printf("Failed to read %s: %s.\n", path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to read %s: %s.\n", path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
uv_fs_req_cleanup(&read_req); uv_fs_req_cleanup(&read_req);
@@ -108,12 +109,14 @@ static char* _tf_ssb_import_read_file(uv_loop_t* loop, const char* path, size_t*
r = uv_fs_close(loop, &close_req, handle, NULL); r = uv_fs_close(loop, &close_req, handle, NULL);
if (r) if (r)
{ {
tf_printf("Failed to close %s: %s.\n", path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to close %s: %s.\n", path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
} }
else else
{ {
tf_printf("Failed to open %s: %s.\n", path, uv_strerror(handle)); char buffer[256];
tf_printf("Failed to open %s: %s.\n", path, uv_strerror_r(handle, buffer, sizeof(buffer)));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
return data; return data;
@@ -163,7 +166,8 @@ static void _tf_ssb_import_recursive_add_files(tf_ssb_t* ssb, uv_loop_t* loop, J
} }
else else
{ {
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
} }
@@ -234,7 +238,8 @@ static void _tf_ssb_import_app_json(tf_ssb_t* ssb, uv_loop_t* loop, JSContext* c
} }
else else
{ {
tf_printf("Failed to open %s: %s.\n", path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to open %s: %s.\n", path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
} }
@@ -270,7 +275,8 @@ void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
} }
else else
{ {
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror(r)); char buffer[256];
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror_r(r, buffer, sizeof(buffer)));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
} }

View File

@@ -182,7 +182,8 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
int pipe_result = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); int pipe_result = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
if (pipe_result) if (pipe_result)
{ {
tf_printf("uv_socketpair failed: %s\n", uv_strerror(pipe_result)); char buffer[256];
tf_printf("uv_socketpair failed: %s\n", uv_strerror_r(pipe_result, buffer, sizeof(buffer)));
} }
uv_pipe_t* pipe = tf_packetstream_get_pipe(stub->_stream); uv_pipe_t* pipe = tf_packetstream_get_pipe(stub->_stream);
@@ -190,12 +191,14 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
pipe_result = uv_pipe_init(tf_task_get_loop(parent), pipe, 1); pipe_result = uv_pipe_init(tf_task_get_loop(parent), pipe, 1);
if (pipe_result != 0) if (pipe_result != 0)
{ {
tf_printf("uv_pipe_init failed: %s\n", uv_strerror(pipe_result)); char buffer[256];
tf_printf("uv_pipe_init failed: %s\n", uv_strerror_r(pipe_result, buffer, sizeof(buffer)));
} }
pipe_result = uv_pipe_open(pipe, fds[0]); pipe_result = uv_pipe_open(pipe, fds[0]);
if (pipe_result != 0) if (pipe_result != 0)
{ {
tf_printf("uv_pipe_open failed: %s\n", uv_strerror(pipe_result)); char buffer[256];
tf_printf("uv_pipe_open failed: %s\n", uv_strerror_r(pipe_result, buffer, sizeof(buffer)));
} }
if (start_service) if (start_service)
@@ -248,7 +251,8 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
} }
else else
{ {
tf_printf("uv_spawn failed: %s\n", uv_strerror(spawn_result)); char buffer[256];
tf_printf("uv_spawn failed: %s\n", uv_strerror_r(spawn_result, buffer, sizeof(buffer)));
JS_FreeValue(context, taskObject); JS_FreeValue(context, taskObject);
} }
} }
@@ -323,7 +327,8 @@ tf_taskstub_t* tf_taskstub_create_parent(tf_task_t* task, uv_file file)
int result = uv_pipe_open(tf_packetstream_get_pipe(parentStub->_stream), file); int result = uv_pipe_open(tf_packetstream_get_pipe(parentStub->_stream), file);
if (result != 0) if (result != 0)
{ {
tf_printf("uv_pipe_open failed: %s\n", uv_strerror(result)); char buffer[256];
tf_printf("uv_pipe_open failed: %s\n", uv_strerror_r(result, buffer, sizeof(buffer)));
} }
tf_packetstream_start(parentStub->_stream); tf_packetstream_start(parentStub->_stream);
return parentStub; return parentStub;

View File

@@ -889,7 +889,8 @@ static void _test_auto(const tf_test_options_t* options)
int spawn_result = uv_spawn(&loop, &process, &process_options); int spawn_result = uv_spawn(&loop, &process, &process_options);
if (spawn_result) if (spawn_result)
{ {
tf_printf("uv_spawn: %s\n", uv_strerror(spawn_result)); char buffer[256];
tf_printf("uv_spawn: %s\n", uv_strerror_r(spawn_result, buffer, sizeof(buffer)));
abort(); abort();
} }
@@ -902,7 +903,8 @@ static void _test_auto(const tf_test_options_t* options)
spawn_result = uv_spawn(&loop, &selenium, &process_options); spawn_result = uv_spawn(&loop, &selenium, &process_options);
if (spawn_result) if (spawn_result)
{ {
tf_printf("uv_spawn: %s\n", uv_strerror(spawn_result)); char buffer[256];
tf_printf("uv_spawn: %s\n", uv_strerror_r(spawn_result, buffer, sizeof(buffer)));
abort(); abort();
} }

View File

@@ -684,3 +684,11 @@ size_t tf_string_set(char* buffer, size_t size, const char* string)
} }
return length; return length;
} }
const char* tf_util_uv_error_buf(char* buffer, size_t size, const char* prefix, int error)
{
char message[256];
uv_strerror_r(error, message, sizeof(message));
snprintf(buffer, size, "%s%s", prefix, message);
return buffer;
}

View File

@@ -249,4 +249,14 @@ bool tf_util_is_mobile();
*/ */
size_t tf_string_set(char* buffer, size_t size, const char* string); size_t tf_string_set(char* buffer, size_t size, const char* string);
/**
** Format a string representation of a libuv error into a string buffer.
** @param buffer The string buffer to be populated.
** @param size The size of the buffer.
** @param prefix Prefix to the error message.
** @param error The libuv error number.
** @return The formatted string.
*/
const char* tf_util_uv_error_buf(char* buffer, size_t size, const char* prefix, int error);
/** @} */ /** @} */

View File

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