Changelog
All notable changes to xtils are documented here (reverse chronological order).
Format: type(scope): description — types: feat, fix, refactor, chore, tidy.
v2.0.0 2026-06
Major release. Tagged after the v1.x deprecation grace period; all snake_case wrappers and compat shims are gone.
💥 BREAKING CHANGES — deprecated APIs removed
| Header | Removed | Replacement |
|---|---|---|
xtils/app/app.h | App::registor/ins/run/run_daemon/init/is_running/spawn/spawn_async/every/delay/emit/connect/conf | App::Register/Ins/Run/RunDaemon/Init/IsRunning/Spawn/SpawnAsync/Every/Delay/Emit/Connect/Conf |
xtils/app/service.h | Service::emit, xtils::isOk/init/shutdown/run_forever/run_daemon | Service::Emit, xtils::IsOk/Init/Shutdown/RunForever/RunDaemon |
xtils/tasks/task_group.h | is_busy/size/stop/stop_wait_all/main_runner | IsBusy/Size/Stop/StopWaitAll/MainRunner |
xtils/utils/thread_safe.h | pop_wait/try_pop/push/clear/size/quit | PopWait/TryPop/Push/Clear/Size/Quit |
xtils/config/config_compat.h | entire file deleted | Use PascalCase API (Define/ParseArgs/LoadFile/ParseJson/Get/GetOr, ...) |
xtils/fsm/fsm_compat.h | entire file deleted | Use PascalCase API |
XTILS_ENABLE_DEPRECATED macro | no longer recognised | Remove from your build system |
🌟 v2.0 highlights (cumulative since v1.2.1)
New modules
xtils/metrics/— lightweight metrics primitives:Counter/Gauge/Histogramwith labelled families andPrometheusExportertext renderingxtils/scripting/— embedded QuickJS-NG JavaScript engine,ScriptEngine/ScriptContext/ScriptValue, bidirectionalJson↔ScriptValueconversion. Opt-in viaSCRIPTING_ENABLE=ONxtils/net/ipc_channel.h— JSON-RPC 2.0 over filesystem Unix / abstract Unix / TCP sockets.IpcServer/IpcClientwith sync call, async call, notifications and subscriptionsxtils/net/http_client_pool.h— fixed-size HTTP client pool with RAII borrow handle and acquire timeout
Logging — structured logs
xtils/logging/mdc.h— Mapped Diagnostic Context, thread-local key/value context auto-appended to structured outputxtils/logging/log_builder.h— chained-field API:LOGI().Field("req_id", id).Field("status", code).Msg("done");- Logging rewrite: atomic level checks (no mutex on hot path),
LogEntrystoresconst char*literals (zero copy), rawtimespecformatted lazily, newFormatterinterface (PlainFormatter/ColorFormatter) per sink - Assertion macros renamed to
XTILS_CHECK/XTILS_DCHECK/XTILS_FATAL(opt-in short names viaXTILS_LOG_SHORT_MACROS)
Net
- HTTP type cleanup:
HttpClient::Request/Response/Listener/MultipartField/MultipartFileare now nested types; the synchronous entry point unifies intoHttpClient::Send(). Server/router scoped names exposed asHttpServer::Request/Connection,HttpRouter::Context/Response. OldHttpRequest/HttpResponsepublic-header collisions removed - Router: path parameters now support both Express-style
:paramand the existing{param}syntax - HttpServer: new
HttpServerConfigwith configurablemax_payload_size(default 4 MB) for memory-constrained devices - Multipart parsing:
MultipartParserplus lazyGetMultipartFields()/GetMultipartFiles()on the request context - File streaming:
HttpServerConnection::SendFileStreaming()chunked delivery (64 KB chunks) - WebSocket: client owns its HTTP upgrade handshake directly — no more dependency on
HttpClient/HttpClientEventListener. WSS supported - TLS backends:
TLS_BACKEND=openssl|mbedtlsCMake option; backend-agnostictls_factory.h - HttpClient: single-flight start/cancel made explicit and atomic; timeout callbacks no longer touch destroyed clients
Tasks
TaskRunnerextensions:PostDelayedTaskWithHandle/CancelDelayedTask,PostTaskAt(time_point), virtualNow()for fake-clock testsCronScheduler::TaskInfogainsnextRun;triggerCheck()locks the task mapTaskGroupPascalCased; perf: tasks moved into / out of queues to avoid extrastd::functioncopies
Config
Config::LoadEnv(prefix)— import<PREFIX>_<KEY>env vars into dot-notation pathsConfig::Short(name, alias)— single-character short flag (e.g.-pfor--port)ConfigWatcher(xtils/config/config_watcher.h) — inotify-based hot reloadGetOr<T>two overloads: explicit fallback / Defined default
App / Service
IService::Dependencies()virtual — declare service deps; App initialises in topological order, deinitialises in reverse- Cycles or unknown dependencies abort early
App::TopoSortServices()exposed for unit tests
Utils
xtils/utils/crypto.h— SHA-256, HMAC-SHA1/256, secure RNG, UUID v4 (reuses the selected TLS backend; no new deps)xtils/utils/result.h—Result<T,E>gainsis_err(),unwrap_or_else(),expect(). Error model documented atdocs/error-model.mdin the source repo- JSON: zero-copy
find(key)/find(index),Json::object()/Json::array()factories; UTF-16 surrogate-pair fix; float round-trip precision (%.17g);operator[]/push_backtype safety (only null may be promoted)
FSM / Behavior Tree
- FSM:
HistoryEntrygains human-readable names,DumpHistory(),RegisterEvent/GetEventName. History is now adeque;recursive_mutex;GetHistory()returns by value;SetRecordFailedEvents(bool) - BT:
SubTree/WaitForEvent/EventGuardnodes; event queue (sendEvent/peekEvent/consumeEvent/hasEvent/clearEvents);pause/resume;LoadTreesFromDirectory; structuredBtLogger(BtFileLogger/BtInspectLogger/BtCompositeLogger)
IPC (final v2.0 push)
IpcServer/IpcClientreuseUnixSocketRawand accept stream addresses beyond filesystem Unix sockets — abstract Unix and TCP IPv4/IPv6 also workTaskGroupis now the only IPC executor API; method/notification handlers dispatch through the serverTaskGroupinstead of running inline on per-client read threads- Async calls no longer spawn one detached waiter thread each; callbacks complete from the read loop and are posted via the explicit / shared callback
TaskGroup - Pending callers and the read thread are correctly woken / joined when the peer disconnects before
Disconnect()
Inspect
- Reimplementation: ~880 → ~330 lines
- Built-in two-pane web console (HTTP + WebSocket panels) embedded at build time via
cmake/embed_file.cmake - Handler signature:
void(const Request&, Response&) - New:
PublishWithResult,GetSubscriberCount,GetRoutes,HasRoute
Notable fixes
string_utils: rename misnamed parameterxtilsback tobasein everyInt*ToString/StringToInt*overloadApp::Run(): replace broken heartbeat watchdog with proper monotonic deadline; acceptthreads=1EventManager::Stop: no longer shuts down a borrowed executor; default-constructed manager owns its ownUnixSocketRaw::Receive/SendvsShutdownrace fixed with fd-validity checkHttpRouter: per-request CORS reset on keep-alive; no danglingOriginstring_view; no chunked trailer appended to response body
Migration
| Item | How to migrate |
|---|---|
All *_compat.h headers | Already removed — switch to PascalCase API |
XTILS_ENABLE_DEPRECATED | Drop from CMake/build |
HttpRequest/HttpResponse public types | Use HttpRouter::Context/Response (router) or HttpClient::Request/Response (client) |
HttpClient::Request* sync entry points | Use HttpClient::Send() |
WebSocketClient HttpClient dependency | No longer needed; client handles upgrade itself |
IpcServer/IpcClient TaskRunner* ctor | Pass TaskGroup& (or rely on default shared TaskGroup) |
v1.1.0 2025-10-16
First official tag. Includes all foundational modules built since project inception.
Module overview
| Module | Status |
|---|---|
| App framework | ✅ service lifecycle, events, timers |
| Config | ✅ JSON config + CLI parsing |
| Logging | ✅ async logger, console/file sinks, watchdog |
| Net | ✅ TCP/UDP client/server, HTTP client/server, WebSocket client |
| FSM | ✅ state machine + history + Graphviz export |
| Tasks | ✅ event loop, thread pool, TaskGroup, timer, CronScheduler |
| Debug | ✅ Inspect HTTP/WS debug server, Chrome Tracer |
| Utils | ✅ JSON, strings, files, base64, SHA1, byte reader/writer |
Highlights
- App framework: singleton context,
Service<T>CRTP base, automatic config-section injection - Event loop: epoll-backed
UnixTaskRunner,ThreadTaskRunnerdedicated-thread wrapper - Networking: full TCP/UDP/HTTP/WebSocket stack, Express-style router, CORS, middleware
- Logging: printf-style macros, async ring buffer, size-rotated file sink, memory/CPU watchdog
- FSM: named states, event transitions, guards, history, DOT graph export
- CronScheduler: cron expressions + interval scheduling
- Custom JSON: zero-dependency, replaces nlohmann_json
- Inspect: runtime HTTP/WebSocket debug server, fully strippable at compile time
- Tracer: Chrome trace format profiling with RAII macros
- Build: single-static-library CMake target, automatic C++17 propagation, GitHub Actions CI
Project bootstrapping (2025-06 ~ 2025-09)
Initial phase, gradually building out core modules:
- 2025-06: HTTP / WebSocket server prototypes, JSON impl, Config class
- 2025-07: Inspect debug server, Tracer, WeakPtr, platform abstraction
- 2025-08: file utils, byte reader/writer, Service framework
- 2025-09: FSM debug enhancements, full HTTP/TCP/UDP impl