C / POSIX
Build, configure, and run the Honch C/POSIX SDK on macOS, Linux, and embedded Linux.
The C/POSIX port runs on macOS and Linux. It targets embedded Linux devices and gateways, and doubles as the fastest way to exercise core behavior on your development machine — its queue is file-backed, so you can watch events move through pending/ and dead/ directories on disk.
Status
0.3.0. Reports $sdk_platform as c-posix.Before You Start
- Requirements: CMake
3.20+, a C11 compiler, libcurl, and a POSIX threads (pthreads) implementation. - Each active client needs its own writable
queue_directory. Do not point two clients at the same directory. - Unlike the device ports, this port's API is multi-client: every call takes an explicit
honch_client_t *.
1. Build The SDK
cmake -S . -B build -DHONCH_BUILD_TESTS=ON -DHONCH_BUILD_EXAMPLES=ON
cmake --build build
ctest --test-dir build --output-on-failureThe build is warnings-as-errors. To compile out crash/error reporting ($crash + $error), configure with -DHONCH_ENABLE_ERROR_TRACKING=OFF.
To install and link from another CMake project:
cmake -S . -B build-install -DHONCH_BUILD_TESTS=OFF -DHONCH_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/opt/honch-posix
cmake --build build-install --target honch_posix
cmake --install build-installfind_package(honch_posix REQUIRED)
target_link_libraries(app PRIVATE honch::honch_posix)2. Configure And Send A First Event
#include "honch/honch.h"
honch_config_t config = {
.api_key = "your-api-key",
.endpoint_url = "https://i.honch.io",
.device_model = "linux-gateway",
.firmware_version = "1.0.0",
.queue_directory = "/var/lib/honch",
};
honch_client_t *client = NULL;
if (honch_init(&client, &config) != HONCH_STATUS_OK) {
return 1;
}
const honch_property_t props[] = { honch_prop("role", honch_str("developer")) };
honch_identify(client, "local-user-001", props, 1);
honch_session_start(client, "demo");
honch_track(client, "button_pressed", NULL, 0);
honch_session_end(client);
honch_flush(client);
honch_shutdown(client);Required fields are api_key, endpoint_url, device_model, firmware_version, and queue_directory. Everything else falls back to the shared defaults. honch_init() is synchronous — it validates config, reconciles the queue directory, persists identity, and queues $device_boot — but does no network I/O.
| Field | Default | Notes |
|---|---|---|
device_id | generated + persisted | A random ID is created on first run if you do not set one. |
environment | "production" | |
durability_mode | OS_BUFFERED | SYNC_ALWAYS fsyncs every write for power-loss safety at a throughput cost. |
flush_interval_seconds | 120 | |
flush_event_threshold | 20 | |
transport_timeout_ms | 8000 | |
connectivity_callback | — | Return offline so ticks skip DNS/TLS and keep events pending. |
3. Pump Delivery
Call honch_tick(client) from a dedicated thread. It performs a synchronous HTTP POST on the calling thread and blocks up to transport_timeout_ms, so keep it off latency-sensitive paths.
while (running) {
honch_tick(client);
sleep(1);
}honch_flush(client) forces queued batches out immediately — handy in short-lived processes before exit.
4. Inspect Local Storage
The queue is a directory tree you can read directly:
<queue_directory>/
pending/ events waiting to upload (one file each)
dead/ permanently rejected events
state/ device_id, distinct_id, firmware_versionEvents are written atomically (temp file then rename) and evicted oldest-first when the queue is full. Retryable failures leave events in pending/; permanent rejections move them to dead/. This visibility is the main reason to validate an integration here before moving to a constrained device.
5. Crash Breadcrumbs (Optional)
honch_install_error_handlers(queue_directory) installs async-signal-safe handlers for SIGABRT, SIGSEGV, SIGBUS, SIGILL, and SIGFPE. They write a bounded breadcrumb file to the directory; the next honch_init() imports it as a $crash event. The path is process-global, so use it with a single client. Because the breadcrumb is persisted to disk, a fatal crash is delivered on the next run even though the in-memory queue does not survive it. POSIX captures the signal/reset context, not a coredump — there is no symbolicated backtrace on this port. For handled, non-fatal errors call honch_core_report_log_error(client, component, message).
Transport Contract
POST <endpoint_url>/capture
Content-Type: application/vnd.honch.chunk
X-Honch-Project-Key: <api_key>
X-Honch-Stream-Id: <stream_id>Transport is libcurl with TLS verification enabled (peer and host); only http/https are allowed and redirects are not followed. Use https:// in production.
Examples
The repository ships runnable examples under ports/posix/example/: posix_device (the snippet above), connected_camera, posix_gpio (edge-tracking from a host GPIO source), and identify_merge.
Debugging Failures
When a call returns a non-HONCH_OK status, honch_core_get_last_error() gives the reason behind it:
honch_error_detail_t detail;
if (honch_tick(client) != HONCH_OK &&
honch_core_get_last_error(client, &detail) == HONCH_OK) {
char line[192];
honch_error_detail_format(&detail, line, sizeof(line));
fprintf(stderr, "honch: %s\n", line);
// "transport error: HTTP 503 - server returned an error status (reason=http_status)"
// or, for a connect-phase failure (raw CURLcode in os_error):
// "transport error: DNS resolution failed - check the configured endpoint (reason=dns_failed) os_error=6"
}The libcurl transport fills http_status from the response and maps the CURLcode of a connect/DNS/TLS failure into reason (with the raw code in os_error). The core also emits the same one-line summary once per distinct failure through the platform log hook. See Error Context & Diagnostics.
Public API
| Function | Purpose |
|---|---|
honch_init(&client, &config) | Create and initialize a client. |
honch_core_get_last_error(client, &detail) | Structured detail (reason, http_status, os_error) for the last failure. |
honch_track(client, event, props, count) | Queue an event. |
honch_identify(client, distinct_id, traits, count) | Set identity; emits $identify. |
honch_set_property(client, key, value) | Emit $set_property. |
honch_session_start(client, name) / honch_session_end(client) | Bracket a session. |
honch_core_report_log_error(client, component, message) | Report a handled, non-fatal error as an $error. |
honch_install_error_handlers(queue_directory) | Install crash-breadcrumb signal handlers ($crash on next run). |
honch_tick(client) | Cooperative delivery step. |
honch_flush(client) | Send queued batches now. |
honch_reset(client) | Clear identity, session, and queue. |
honch_shutdown(client) | Emit $device_shutdown, final flush, free the client. |
honch_get_device_id(client) | Borrowed device-ID pointer. |
honch_copy_device_id(client, buf, size) | Copy the device ID into your buffer (thread-safe). |
honch_status_string(status) | Human-readable status text. |
Calls return honch_status_t (HONCH_STATUS_OK on success), except honch_get_device_id and honch_status_string, which return const char *.