mirror of
https://github.com/logos-co/logos-protocol.git
synced 2026-08-27 12:01:15 +00:00
* Extract the Logos protocol layer from logos-cpp-sdk
Transports (plain TCP/TLS, qt_local, qt_remote/QRO, mock), token manager,
consumer core (LogosAPIClient/LogosAPIConsumer incl. the capability
auto-requestModule flow), ModuleProxy, the abstract LogosProviderObject
interface, and the canonical QVariant<->JSON conversion — now behind the
language-neutral lp_* C ABI (logos_protocol.h) carrying the protocol
semver (LOGOS_PROTOCOL_VERSION_*, lp_protocol_version()).
Bytes crossing the ABI use the lossless {"_bytes": base64url} tagging
(NUL-safe), matching the plain wire encoding.
Provider lp_* surface is compiled groundwork; serving lands with module
authoring.
* Move LogosProviderPlugin into logos_provider_interface.h
Plugin-loading tools (logos-cpp-generator's introspection mode, lm, the
hosts) need only qobject_cast<LogosProviderPlugin*>() + the abstract
LogosProviderObject — both framework-internal. Hosting the detection
interface here keeps those tools off the developer-facing logos-qt-sdk
layer. Same iid (org.logos.LogosProviderPlugin); header-only, ABI-neutral.
* Define the common module-impl C ABI (logos_module_impl.h)
ONE cdylib contract for module implementations in every language:
dispatch / get_methods / set_context / set_emit_callback / accept_token
/ get_protocol_version / string_free. The C++ and Rust SDKs emit these
exports around their respective impls; the uniform generated Qt glue
(and later a no-Qt host) talks to the cdylib only through this ABI.
JSON data model and tagged bytes form match the lp_* consumer ABI; the
protocol-version handshake complements the build-time metadata stamp.
* json convert: integers stay integers across the C ABI
QJsonValue::fromVariant degrades every numeric to double, so Int/UInt/
LongLong/ULongLong QVariants serialized as 5.0 — and a strict consumer on
the other side of the C ABI (a generated dispatch reading an int param)
rejects or zeroes them. Surfaced by the first cdylib-authored module
whose inbound args cross qvariantToNlohmann; the dlopen smoke harness
fed hand-written int JSON and never exercised this edge.
* call-error channel: surface {code,message,origin} for unacquirable targets
invokeRemoteMethod could not distinguish a failed call from a void/null
result — lp_invoke returned LP_OK with a null JSON result even when the
target module was never reached, and generated typed wrappers silently
defaulted (0 / empty string). Additive err-out overloads on
LogosAPIConsumer/LogosAPIClient fill a std-only logos::CallError
(logos_call_error.h, new LogosCallError exception for the generated
wrappers to throw); lp_invoke now honors its documented contract for
this class of failure: LP_ERR_UNAVAILABLE + canonical error JSON.
First detectable code: object_unavailable (requestObject failure) —
the struct is the extension point for transport-level statuses.
* call-error: drop the exception type — the error channel is the out-param
Per review, generated wrappers expose CallError as an optional trailing
out-parameter instead of throwing; the struct is the whole contract.
* ci: build + run the protocol test suite
On every pull request (unfiltered — stacked PRs included), master pushes,
and manual dispatch. The repo shipped without CI; its 111-test suite only
ran locally and through the workspace gate.
* consumer: typed requestModule for the capability flow
Port of logos-cpp-sdk master f5a127dd ('use updated capability module',
cpp-sdk#85, Iuri Matias) — the touched files (logos_api_client.cpp,
logos_api_consumer.{h,cpp}) moved into this repo in the P1 extraction.
The capability auto-requestModule path now calls a typed std::string
helper on the consumer (which acquires the capability object directly)
instead of a stringly invokeRemoteMethod round-trip. 111/111 tests.
* ci: DeterminateSystems nix installer (macOS runners)
cachix/install-nix-action fails on the macOS runners with
eDSRecordAlreadyExists (pre-existing nix build users); the org's
macOS-bearing workflows use the DeterminateSystems installer.
101 lines
4.7 KiB
C
101 lines
4.7 KiB
C
#ifndef LOGOS_MODULE_IMPL_H
|
|
#define LOGOS_MODULE_IMPL_H
|
|
|
|
/* ===========================================================================
|
|
* logos_module_impl.h — the COMMON module-impl C ABI.
|
|
*
|
|
* ONE contract for module implementations in every language: a Logos module
|
|
* compiles to a cdylib exporting exactly these symbols. The C++ SDK emits
|
|
* this wrapper around a universal C++ impl class; the Rust SDK emits it
|
|
* around a Rust impl. The uniform generated Qt-plugin glue (and, later, a
|
|
* no-Qt host) talks to the cdylib ONLY through this ABI — the glue is
|
|
* identical regardless of the module's source language, which is what makes
|
|
* the eventual Qt-glue removal a host swap instead of a per-language change.
|
|
*
|
|
* Data model mirrors the lp_* consumer ABI (logos_protocol.h):
|
|
* - method args / event payloads: JSON array (UTF-8 const char*)
|
|
* - results: JSON value
|
|
* - bytes: the canonical {"_bytes":"<base64url>"} tagged form
|
|
* - errors from dispatch: NULL return, or a canonical error object
|
|
* {"code","message","origin"} returned as the result of a failed call
|
|
* when the implementation prefers structured errors.
|
|
*
|
|
* Ownership: every char* RETURNED by the module is heap-allocated and the
|
|
* CALLER frees it with logos_module_string_free (exported by the module so
|
|
* allocator domains never mix). Every const char* passed IN is borrowed.
|
|
*
|
|
* Threading: the host serializes dispatch calls (one at a time) unless a
|
|
* future capability negotiates otherwise. The emit callback may be invoked
|
|
* from any module thread; the host marshals.
|
|
*
|
|
* Versioning: logos_module_get_protocol_version() returns the
|
|
* logos-protocol semver the module was COMPILED against (forwarded from
|
|
* LOGOS_PROTOCOL_VERSION_STRING, never minted). Hosts apply the same rule
|
|
* as the metadata stamp: equal MAJOR ⇔ compatible. This runtime handshake
|
|
* complements the build-time metadata stamp and is what a no-Qt host (no
|
|
* Qt plugin metadata) negotiates with.
|
|
* =========================================================================== */
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#define LOGOS_MODULE_IMPL_EXPORT __declspec(dllexport)
|
|
#else
|
|
#define LOGOS_MODULE_IMPL_EXPORT __attribute__((visibility("default")))
|
|
#endif
|
|
|
|
/* Event-emission callback installed by the host/glue. `data_json` is a JSON
|
|
* array payload, borrowed for the duration of the call. */
|
|
typedef void (*logos_module_emit_cb)(const char* event_name,
|
|
const char* data_json,
|
|
void* user_data);
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Exported by every module cdylib (generated by the SDK of the module's
|
|
* language; module authors never write these by hand).
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
/* Dispatch a method call. Returns the result JSON value as a heap string
|
|
* (free with logos_module_string_free), or NULL when the method is unknown
|
|
* or dispatch failed structurally. */
|
|
LOGOS_MODULE_IMPL_EXPORT char* logos_module_dispatch(const char* method,
|
|
const char* args_json);
|
|
|
|
/* The module's method/event metadata as a JSON array — same shape as
|
|
* LogosProviderObject::getMethods() (entries tagged "method"/"event"). */
|
|
LOGOS_MODULE_IMPL_EXPORT char* logos_module_get_methods(void);
|
|
|
|
/* Module identity/context, stamped by the host before the first dispatch:
|
|
* module path, instance id, per-instance persistence path. Mirrors
|
|
* LogosModuleContext / RustModuleContext. Any argument may be NULL. */
|
|
LOGOS_MODULE_IMPL_EXPORT void logos_module_set_context(
|
|
const char* module_path,
|
|
const char* instance_id,
|
|
const char* instance_persistence_path);
|
|
|
|
/* Install the host's event-emission callback. The module keeps (cb,
|
|
* user_data) and invokes cb once per emitted event. Passing NULL clears it;
|
|
* after the clearing call returns, the module must not invoke the old cb. */
|
|
LOGOS_MODULE_IMPL_EXPORT void logos_module_set_emit_callback(
|
|
logos_module_emit_cb cb, void* user_data);
|
|
|
|
/* Deliver an auth token for `module_name` (the provider-side
|
|
* informModuleToken). Returns 0 on acceptance. */
|
|
LOGOS_MODULE_IMPL_EXPORT int logos_module_accept_token(const char* module_name,
|
|
const char* token);
|
|
|
|
/* The logos-protocol semver this module was compiled against. Static
|
|
* string — do NOT free. */
|
|
LOGOS_MODULE_IMPL_EXPORT const char* logos_module_get_protocol_version(void);
|
|
|
|
/* Free a string returned by this module. Safe on NULL. */
|
|
LOGOS_MODULE_IMPL_EXPORT void logos_module_string_free(char* s);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* LOGOS_MODULE_IMPL_H */
|