| Crates.io | pywatt_macros |
| lib.rs | pywatt_macros |
| version | 0.2.9 |
| created_at | 2025-06-05 16:42:57.339735+00 |
| updated_at | 2025-06-05 16:42:57.339735+00 |
| description | Procedural macros for the PyWatt SDK |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1701808 |
| size | 17,988 |
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:
SecretClient for interacting with the orchestrator's secret service.Default::default() if none is specified), passing the orchestrator's initialization data and any prefetched secrets.pywatt_sdk::AppState which wraps the user state and other SDK components.pywatt_sdk::AppState into the router so it's accessible to handlers./health, path is configurable)./metrics, currently a placeholder).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: If true, subscribes to rotation events for the secrets specified in the secrets argument. Defaults to false. Example: rotate = true.endpoints: [AnnouncedEndpoint]: An array of pywatt_sdk::AnnouncedEndpoint structs 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 (or health_path: &str): Optional. Custom path for the health check endpoint. Defaults to "/health". Example: health = "/status".metrics: bool: If true, enables a /metrics endpoint. Defaults to false. 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 /data to /v1/data in the announcement.state: fn_path: Optional. A path to a function that builds your custom module state. The function must have a signature compatible with fn(&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.use pywatt_sdk::{self, AppState, AnnouncedEndpoint, Result};
use axum::{routing::get, Router};
use secrecy::ExposeSecret;
// Define your custom module state (if any)
#[derive(Default, Clone)]
struct MyModuleState {
api_key: Option<String>,
}
// Optional: Define a custom state builder function
fn build_my_state(init_data: &pywatt_sdk::OrchestratorInit, secrets: Vec<secrecy::SecretString>) -> MyModuleState {
println!("Building MyModuleState. Orchestrator API: {}", init_data.orchestrator_api);
let mut api_key = None;
if let Some(secret_value) = secrets.get(0) { // Assuming "MY_API_KEY" is the first secret
api_key = Some(secret_value.expose_secret().clone());
println!("API Key prefetched!");
}
MyModuleState { api_key }
}
async fn get_hello(state: AppState<MyModuleState>) -> String {
if let Some(key) = &state.user_state.api_key {
format!("Hello from PyWatt module with API key: {}...", &key[..5])
} else {
"Hello from PyWatt module!".to_string()
}
}
#[pywatt_sdk::module(
secrets = ["MY_API_KEY"],
rotate = true,
endpoints = [
AnnouncedEndpoint {
path: "/hello".to_string(),
methods: vec!["GET".to_string()],
auth: None,
}
],
state = build_my_state,
version = "v1"
)]
async fn my_module_router(state: AppState<MyModuleState>) -> Router {
Router::new().route("/hello", get(get_hello).with_state(state))
}
// 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.