Files
quicproquo/docs/src/getting-started/generators.md
Chris Nennemann db46b72f58 feat: Sprint 3 — C FFI bindings, WASM compilation, Python example, SDK docs
- Create quicproquo-ffi crate with 7 extern "C" functions: connect,
  login, send, receive, disconnect, last_error, free_string
  (produces libquicproquo_ffi.so and .a)
- Feature-gate quicproquo-core for WASM: identity, hybrid_kem,
  safety_numbers, sealed_sender, app_message, padding, transcript
  all compile to wasm32-unknown-unknown
- Add Python ctypes example (examples/python/qpq_client.py) with
  QpqClient wrapper class and CLI
- Add SDK documentation: FFI reference, WASM guide, qpq-gen generators
- Update Dockerfile for quicproquo-ffi workspace member
2026-03-03 23:47:40 +01:00

5.3 KiB

Code Generators (qpq-gen)

The qpq-gen CLI tool scaffolds new plugins, bots, RPC methods, and hook events for the quicproquo ecosystem.

Installation

cargo install --path crates/quicproquo-gen

Or run directly from the workspace:

cargo run -p quicproquo-gen -- <subcommand>

Subcommands

qpq-gen plugin <name> -- Server Plugin

Scaffolds a standalone Cargo project for a server plugin compiled as a shared library (cdylib). The generated plugin implements the HookVTable C ABI and is loaded by the server at startup via --plugin-dir.

qpq-gen plugin rate-limiter
qpq-gen plugin audit-log --output /tmp/plugins

Generated files:

rate_limiter/
  Cargo.toml        # cdylib crate depending on quicproquo-plugin-api
  README.md         # Build and install instructions
  src/lib.rs        # Plugin skeleton with qpq_plugin_init entry point

The template includes:

  • qpq_plugin_init -- called by the server on load; populates the HookVTable
  • on_message_enqueue -- sample hook that rejects payloads larger than 1 MB
  • error_message -- returns the rejection reason as a C string
  • destroy -- frees the plugin state

What to customize: Replace the on_message_enqueue logic with your own policy. Add more hooks by setting additional fields on the HookVTable (on_auth, on_channel_created, on_fetch, on_user_registered, on_batch_enqueue).

Build and install:

cd rate_limiter
cargo build --release
cp target/release/librate_limiter.so /path/to/plugins/
qpq-server --plugin-dir /path/to/plugins/

qpq-gen bot <name> -- Bot Project

Scaffolds a standalone bot project using the Bot SDK. The generated binary connects to a quicproquo server, authenticates via OPAQUE, and runs a message-handling loop.

qpq-gen bot echo-bot
qpq-gen bot moderation-bot --output /tmp/bots

Generated files:

moderation_bot/
  Cargo.toml        # Binary crate depending on quicproquo-bot + tokio
  README.md         # Quick-start and command reference
  src/main.rs       # Bot skeleton with handle_message dispatcher

The template ships with four built-in commands as examples:

Command Description
!help List available commands
!echo <text> Echo back the text
!whoami Show the sender's username
!ping Respond with "pong!"

Configuration is read from environment variables:

Variable Default
QPQ_SERVER 127.0.0.1:7000
QPQ_USERNAME <bot-name>
QPQ_PASSWORD changeme
QPQ_CA_CERT server-cert.der
QPQ_STATE_PATH <bot-name>-state.bin

What to customize: Edit the handle_message function in src/main.rs to add your own command handlers. Return Some(response) to reply, or None to stay silent.

Run:

cd moderation_bot
QPQ_SERVER=127.0.0.1:7000 \
QPQ_USERNAME=moderation_bot \
QPQ_PASSWORD=changeme \
QPQ_CA_CERT=path/to/server-cert.der \
cargo run

qpq-gen rpc <Name> -- RPC Method Guide

Prints a step-by-step guide for adding a new Cap'n Proto RPC method to the server. This generator does not create files; it outputs instructions and code snippets to copy into the appropriate locations.

qpq-gen rpc listChannels

The Name argument should be in camelCase (e.g., listChannels). The generator derives the snake_case form automatically for file and function names.

Steps covered:

  1. Schema -- Add the method to the interface NodeService block in schemas/node.capnp, then rebuild with cargo build -p quicproquo-proto
  2. Handler module -- Create crates/quicproquo-server/src/node_service/<name>.rs with the handler implementation (template code is printed)
  3. Registration -- Wire the handler into node_service/mod.rs
  4. Storage (if needed) -- Add a method to the Store trait and implement it in sql_store.rs and storage.rs
  5. Hook (optional) -- Run qpq-gen hook <name> to let plugins observe the new RPC
  6. Verify -- cargo build -p quicproquo-server && cargo test -p quicproquo-server

qpq-gen hook <name> -- Hook Event Guide

Prints a step-by-step guide for adding a new server hook event that plugins can observe. Like rpc, this generator outputs instructions rather than creating files.

qpq-gen hook message_deleted

The name argument should be in snake_case (e.g., message_deleted). The generator derives the PascalCase form for struct names.

Steps covered:

  1. Event struct -- Define MessageDeletedEvent in crates/quicproquo-server/src/hooks.rs
  2. Trait method -- Add on_message_deleted to the ServerHooks trait with a default no-op implementation
  3. Tracing -- Implement the hook in TracingHooks with a tracing::info! call
  4. Plugin API -- Add a C-compatible CMessageDeletedEvent struct and an on_message_deleted field to HookVTable in crates/quicproquo-plugin-api/src/lib.rs
  5. Plugin dispatch -- Wire the conversion and dispatch in plugin_loader.rs
  6. Call site -- Fire the hook from the relevant RPC handler in node_service/
  7. Verify -- Build and test quicproquo-plugin-api and quicproquo-server