chore: rename quicproquo → quicprochat in docs, Docker, CI, and packaging
Rename all project references from quicproquo/qpq to quicprochat/qpc across documentation, Docker configuration, CI workflows, packaging scripts, operational configs, and build tooling. - Docker: crate paths, binary names, user/group, data dirs, env vars - CI: workflow crate references, binary names, artifact names - Docs: all markdown files under docs/, SDK READMEs, book.toml - Packaging: OpenWrt Makefile, init script, UCI config (file renames) - Scripts: justfile, dev-shell, screenshot, cross-compile, ai_team - Operations: Prometheus config, alert rules, Grafana dashboard - Config: .env.example (QPQ_* → QPC_*), CODEOWNERS paths - Top-level: README, CONTRIBUTING, ROADMAP, CLAUDE.md
This commit is contained in:
@@ -1,49 +1,49 @@
|
||||
# C FFI Bindings
|
||||
|
||||
The C FFI layer (`crates/quicproquo-ffi/`) provides synchronous C-callable functions that wrap the Rust client library. This is the foundation for language bindings in Python (CFFI), Swift, Kotlin/JNI, Java, and Ruby.
|
||||
The C FFI layer (`crates/quicprochat-ffi/`) provides synchronous C-callable functions that wrap the Rust client library. This is the foundation for language bindings in Python (CFFI), Swift, Kotlin/JNI, Java, and Ruby.
|
||||
|
||||
## Building
|
||||
|
||||
```sh
|
||||
cargo build --release -p quicproquo-ffi
|
||||
cargo build --release -p quicprochat-ffi
|
||||
```
|
||||
|
||||
This produces:
|
||||
- Linux: `target/release/libquicproquo_ffi.so`
|
||||
- macOS: `target/release/libquicproquo_ffi.dylib`
|
||||
- Windows: `target/release/quicproquo_ffi.dll`
|
||||
- Linux: `target/release/libquicprochat_ffi.so`
|
||||
- macOS: `target/release/libquicprochat_ffi.dylib`
|
||||
- Windows: `target/release/quicprochat_ffi.dll`
|
||||
|
||||
## API
|
||||
|
||||
### Status Codes
|
||||
|
||||
```c
|
||||
#define QPQ_OK 0
|
||||
#define QPQ_ERROR 1
|
||||
#define QPQ_AUTH_FAILED 2
|
||||
#define QPQ_TIMEOUT 3
|
||||
#define QPQ_NOT_CONNECTED 4
|
||||
#define QPC_OK 0
|
||||
#define QPC_ERROR 1
|
||||
#define QPC_AUTH_FAILED 2
|
||||
#define QPC_TIMEOUT 3
|
||||
#define QPC_NOT_CONNECTED 4
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```c
|
||||
// Connect to a server. Returns opaque handle or NULL on failure.
|
||||
QpqHandle* qpq_connect(
|
||||
QpqHandle* qpc_connect(
|
||||
const char* server, // "host:port"
|
||||
const char* ca_cert, // path to CA certificate PEM
|
||||
const char* server_name // TLS SNI name
|
||||
);
|
||||
|
||||
// Authenticate with OPAQUE. Returns status code.
|
||||
int qpq_login(
|
||||
int qpc_login(
|
||||
QpqHandle* handle,
|
||||
const char* username,
|
||||
const char* password
|
||||
);
|
||||
|
||||
// Send a message to a recipient (by username).
|
||||
int qpq_send(
|
||||
int qpc_send(
|
||||
QpqHandle* handle,
|
||||
const char* recipient, // recipient username
|
||||
const uint8_t* message, // message bytes
|
||||
@@ -52,20 +52,20 @@ int qpq_send(
|
||||
|
||||
// Receive pending messages. Blocks up to timeout_ms.
|
||||
// On success, *out_json is a JSON array of strings.
|
||||
int qpq_receive(
|
||||
int qpc_receive(
|
||||
QpqHandle* handle,
|
||||
uint32_t timeout_ms,
|
||||
char** out_json // caller must free with qpq_free_string
|
||||
char** out_json // caller must free with qpc_free_string
|
||||
);
|
||||
|
||||
// Disconnect and free the handle.
|
||||
void qpq_disconnect(QpqHandle* handle);
|
||||
void qpc_disconnect(QpqHandle* handle);
|
||||
|
||||
// Get last error message (valid until next FFI call on this handle).
|
||||
const char* qpq_last_error(const QpqHandle* handle);
|
||||
const char* qpc_last_error(const QpqHandle* handle);
|
||||
|
||||
// Free a string returned by qpq_receive.
|
||||
void qpq_free_string(char* ptr);
|
||||
// Free a string returned by qpc_receive.
|
||||
void qpc_free_string(char* ptr);
|
||||
```
|
||||
|
||||
## Usage Example (C)
|
||||
@@ -76,53 +76,53 @@ void qpq_free_string(char* ptr);
|
||||
|
||||
// Forward declarations (or include a header).
|
||||
typedef struct QpqHandle QpqHandle;
|
||||
extern QpqHandle* qpq_connect(const char*, const char*, const char*);
|
||||
extern int qpq_login(QpqHandle*, const char*, const char*);
|
||||
extern int qpq_send(QpqHandle*, const char*, const unsigned char*, size_t);
|
||||
extern int qpq_receive(QpqHandle*, unsigned int, char**);
|
||||
extern void qpq_disconnect(QpqHandle*);
|
||||
extern const char* qpq_last_error(const QpqHandle*);
|
||||
extern void qpq_free_string(char*);
|
||||
extern QpqHandle* qpc_connect(const char*, const char*, const char*);
|
||||
extern int qpc_login(QpqHandle*, const char*, const char*);
|
||||
extern int qpc_send(QpqHandle*, const char*, const unsigned char*, size_t);
|
||||
extern int qpc_receive(QpqHandle*, unsigned int, char**);
|
||||
extern void qpc_disconnect(QpqHandle*);
|
||||
extern const char* qpc_last_error(const QpqHandle*);
|
||||
extern void qpc_free_string(char*);
|
||||
|
||||
int main(void) {
|
||||
QpqHandle* h = qpq_connect("127.0.0.1:5001", "ca.pem", "localhost");
|
||||
QpqHandle* h = qpc_connect("127.0.0.1:5001", "ca.pem", "localhost");
|
||||
if (!h) {
|
||||
fprintf(stderr, "connect failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = qpq_login(h, "alice", "password123");
|
||||
int rc = qpc_login(h, "alice", "password123");
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "login failed: %s\n", qpq_last_error(h));
|
||||
qpq_disconnect(h);
|
||||
fprintf(stderr, "login failed: %s\n", qpc_last_error(h));
|
||||
qpc_disconnect(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* msg = "hello from C!";
|
||||
qpq_send(h, "bob", (const unsigned char*)msg, strlen(msg));
|
||||
qpc_send(h, "bob", (const unsigned char*)msg, strlen(msg));
|
||||
|
||||
char* json = NULL;
|
||||
rc = qpq_receive(h, 5000, &json);
|
||||
rc = qpc_receive(h, 5000, &json);
|
||||
if (rc == 0 && json) {
|
||||
printf("received: %s\n", json);
|
||||
qpq_free_string(json);
|
||||
qpc_free_string(json);
|
||||
}
|
||||
|
||||
qpq_disconnect(h);
|
||||
qpc_disconnect(h);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Compile with:
|
||||
```sh
|
||||
gcc -o demo demo.c -L target/release -lquicproquo_ffi
|
||||
gcc -o demo demo.c -L target/release -lquicprochat_ffi
|
||||
```
|
||||
|
||||
## Memory Management
|
||||
|
||||
- `qpq_connect` returns a heap-allocated handle. The caller **must** call `qpq_disconnect` to free it.
|
||||
- `qpq_receive` writes a heap-allocated JSON string to `*out_json`. The caller **must** call `qpq_free_string` to free it.
|
||||
- `qpq_last_error` returns a pointer owned by the handle. Do **not** free it. It is valid until the next FFI call on the same handle.
|
||||
- `qpc_connect` returns a heap-allocated handle. The caller **must** call `qpc_disconnect` to free it.
|
||||
- `qpc_receive` writes a heap-allocated JSON string to `*out_json`. The caller **must** call `qpc_free_string` to free it.
|
||||
- `qpc_last_error` returns a pointer owned by the handle. Do **not** free it. It is valid until the next FFI call on the same handle.
|
||||
|
||||
## Thread Safety
|
||||
|
||||
@@ -133,7 +133,7 @@ Each `QpqHandle` owns its own Tokio runtime. Concurrent calls on the **same** ha
|
||||
The FFI layer bridges synchronous C callers to the async Rust client:
|
||||
|
||||
```
|
||||
C caller ─── qpq_login() ───► QpqHandle ─── runtime.block_on() ───► async Rust client
|
||||
C caller ─── qpc_login() ───► QpqHandle ─── runtime.block_on() ───► async Rust client
|
||||
```
|
||||
|
||||
Each handle contains:
|
||||
|
||||
Reference in New Issue
Block a user