PyWatt Macros
This crate provides procedural macros to simplify the development of Rust-based PyWatt modules.
#[pywatt_sdk::module]
The primary macro offered is #[pywatt_sdk::module]. This attribute macro is designed to be applied to an async function that returns an axum::Router and takes an pywatt_sdk::AppState<T> as its argument (where T is your custom module state).
It automates the following boilerplate tasks:
- Initialization: Sets up module logging.
- Orchestrator Handshake: Reads initial configuration from the orchestrator.
- Secret Management:
- Creates a
SecretClientfor interacting with the orchestrator's secret service. - Prefetches specified secrets.
- Optionally subscribes to secret rotation events for the prefetched secrets.
- Creates a
- State Creation:
- Builds the user-defined module state. It calls a user-provided state builder function (or
Default::default()if none is specified), passing the orchestrator's initialization data and any prefetched secrets. - Constructs the main
pywatt_sdk::AppStatewhich wraps the user state and other SDK components.
- Builds the user-defined module state. It calls a user-provided state builder function (or
- Router Setup:
- Calls the annotated function to get the base Axum router.
- Layers the
pywatt_sdk::AppStateinto the router so it's accessible to handlers.
- Standard Endpoints:
- Adds a health check endpoint (defaults to
/health, path is configurable). - Optionally adds a Prometheus metrics endpoint (defaults to
/metrics, currently a placeholder).
- Adds a health check endpoint (defaults to
- Module Announcement: Announces the module's listen address and its HTTP endpoints (including health and metrics if enabled) to the orchestrator.
- Server Startup: Starts an Axum HTTP server listening on the TCP address provided by the orchestrator.
Arguments
The #[pywatt_sdk::module] macro accepts the following arguments:
secrets: [&str]: An array of secret keys (string literals) to be prefetched at startup. Example:secrets = ["api_key", "db_password"].rotate: bool: Iftrue, subscribes to rotation events for the secrets specified in thesecretsargument. Defaults tofalse. Example:rotate = true.endpoints: [AnnouncedEndpoint]: An array ofpywatt_sdk::AnnouncedEndpointstructs describing the custom endpoints your module provides. Example:endpoints = [pywatt_sdk::AnnouncedEndpoint { path: "/my/data".to_string(), methods: vec!["GET".to_string(), "POST".to_string()], auth: None }].health: &str(orhealth_path: &str): Optional. Custom path for the health check endpoint. Defaults to"/health". Example:health = "/status".metrics: bool: Iftrue, enables a/metricsendpoint. Defaults tofalse. Example:metrics = true.version: &str: Optional. A version string to prefix all announced custom endpoint paths (health and metrics paths are not prefixed). Example:version = "v1"would change an endpoint/datato/v1/datain the announcement.state: fn_path: Optional. A path to a function that builds your custom module state. The function must have a signature compatible withfn(&pywatt_sdk::OrchestratorInit, Vec<secrecy::SecretString>) -> UserStateType. If not provided,Default::default()is used to create the user state. Example:state = my_custom_state_builder.channels,security_level,auth_required: These arguments are currently parsed but ignored. They are included for potential future compatibility.
Example Usage
use ;
use ;
use ExposeSecret;
// Define your custom module state (if any)
// Optional: Define a custom state builder function
async
async
// The macro will generate the main function and all boilerplate.
// To run this (assuming it's in src/main.rs and Cargo.toml is set up):
// cargo run
This macro significantly reduces the amount of code needed to get a PyWatt module up and running, allowing developers to focus on the module's core logic.