### Install OpenSSL for Windows using vcpkg Source: https://github.com/pimeys/rust-web-push/blob/master/README.md These commands are specific to Windows users needing to install OpenSSL via vcpkg for building the crate. Ensure vcpkg is integrated into your system first. ```shell vcpkg integrate install vcpkg install openssl:x64-windows-static-md ``` -------------------------------- ### Send Encrypted Web Push Notification with VAPID Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Example demonstrating how to send an encrypted push notification using VAPID authentication. Requires an async executor and OpenSSL. The subscription information and VAPID private key are read from external sources. ```rust use web_push::* use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let endpoint = "https://updates.push.services.mozilla.com/wpush/v1/..."; let p256dh = "key_from_browser_as_base64"; let auth = "auth_from_browser_as_base64"; //You would likely get this by deserializing a browser `pushSubscription` object via serde. let subscription_info = SubscriptionInfo::new( endpoint, p256dh, auth ); //Read signing material for payload. let file = File::open("private_key.pem").unwrap(); let mut sig_builder = VapidSignatureBuilder::from_pem(file, &subscription_info)?.build()?; //Now add payload and encrypt. let mut builder = WebPushMessageBuilder::new(&subscription_info); let content = "Encrypted payload to be sent in the notification".as_bytes(); builder.set_payload(ContentEncoding::Aes128Gcm, content); builder.set_vapid_signature(sig_builder); let client = IsahcWebPushClient::new()?; //Finally, send the notification! client.send(builder.build()?).await?; Ok(()) } ``` -------------------------------- ### Example Web Push Subscription JSON Source: https://github.com/pimeys/rust-web-push/blob/master/README.md This JSON structure is required to store subscription information for receiving push notifications. Ensure the endpoint and keys are correctly obtained from your browser's push service. ```json { "endpoint": "https://updates.push.services.mozilla.com/wpush/v1/TOKEN", "keys": { "auth": "####secret####", "p256dh": "####public_key####" } } ``` -------------------------------- ### Configure Logging for Rust Web Push Source: https://context7.com/pimeys/rust-web-push/llms.txt Enables trace-level logging for the `rust-web-push` crate by configuring `pretty_env_logger` in `Cargo.toml` and initializing it in `main`. ```toml # Cargo.toml [dependencies] log = "0.4" pretty_env_logger = "0.3" ``` ```rust fn main() { pretty_env_logger::init(); // ... } ``` -------------------------------- ### Run Rust Program with Trace Logging Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Execute your Rust program with the RUST_LOG environment variable set to trace the web_push::client module. This provides detailed information about outgoing requests. ```bash RUST_LOG="web_push::client=trace" cargo run ``` -------------------------------- ### Send Web Push Notification from Command Line Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Use this command to send a web push notification from the command line after setting up your subscription JSON and private key. Adjust paths as necessary. ```shell cd examples/simple-send && cargo run -- -v ../../private_key.pem -f ../../test.json -p "It works!" ``` -------------------------------- ### Add rust-web-push to Cargo.toml Source: https://context7.com/pimeys/rust-web-push/llms.txt Specify the web-push dependency in your Cargo.toml file. Choose between the default isahc-based client or the hyper-based client for Tokio environments. ```toml # Cargo.toml [dependencies] # Default: isahc-based client web-push = "0.11.0" # Hyper-based client (Tokio only, ~300 KB smaller binary) web-push = { version = "0.11.0", features = ["hyper-client"], default-features = false } ``` -------------------------------- ### Construct SubscriptionInfo Manually or Deserialize from JSON Source: https://context7.com/pimeys/rust-web-push/llms.txt Create a SubscriptionInfo object either by manually providing the endpoint and keys, or by deserializing a browser's PushSubscription JSON object. ```rust use web_push::* use serde_json::json; // Option 1: construct manually let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); // Option 2: deserialize from browser pushSubscription JSON (e.g., received via HTTP POST) let raw = json!({ "endpoint": "https://fcm.googleapis.com/fcm/send/eKClHsXFm9E:APA91b...", "keys": { "p256dh": "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6ts...", "auth": "EvcWjEgzr4rbvhfi3yds0A" } }); let subscription: SubscriptionInfo = serde_json::from_value(raw).unwrap(); println!("Endpoint: {}", subscription.endpoint); println!("p256dh: {}", subscription.keys.p256dh); println!("auth: {}", subscription.keys.auth); ``` -------------------------------- ### Configure Logging for Debugging Web Push Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Add these dependencies to your Cargo.toml to enable logging. This is useful for debugging issues with the web push service. ```toml log = "0.4" pretty_env_logger = "0.3" ``` -------------------------------- ### Initialize Pretty Environment Logger in Rust Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Initialize the pretty_env_logger in your main Rust function to enable detailed logging output. This requires the `log` and `pretty_env_logger` crates. ```rust extern crate pretty_env_logger; // ... fn main() { pretty_env_logger::init(); // ... } ``` -------------------------------- ### Send Web Push Notification with IsahcClient Source: https://context7.com/pimeys/rust-web-push/llms.txt Uses the default `IsahcWebPushClient` to send a web push notification. Create the client once and reuse it for multiple notifications. Handles different `WebPushError` variants. ```rust use web_push::* use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let subscription: SubscriptionInfo = serde_json::from_str(r#"{ "endpoint": "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "keys": { "p256dh": "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "auth": "xS03Fi5ErfTNH_l9WHE9Ig" } }"#)?; let vapid = VapidSignatureBuilder::from_pem(File::open("private_key.pem")?, &subscription)? .build()?; let mut msg_builder = WebPushMessageBuilder::new(&subscription); msg_builder.set_payload(ContentEncoding::Aes128Gcm, b"Your order has shipped!"); msg_builder.set_vapid_signature(vapid); // Create client once; reuse for many notifications let client = IsahcWebPushClient::new()?; match client.send(msg_builder.build()?).await { Ok(()) => println!("Notification delivered."), Err(WebPushError::EndpointNotValid(_)) => println!("Subscription expired — remove from DB."), Err(WebPushError::ServerError { retry_after, .. }) => { println!("Push service overloaded. Retry after: {:?}", retry_after); } Err(e) => eprintln!("Error: {}", e), } Ok(()) } ``` -------------------------------- ### Configure Cargo.toml for Hyper Client Source: https://context7.com/pimeys/rust-web-push/llms.txt Specifies the `web-push` crate with the `hyper-client` feature enabled and `default-features` disabled to reduce binary size. ```toml # Cargo.toml web-push = { version = "0.11.0", features = ["hyper-client"], default-features = false } ``` -------------------------------- ### Generate VAPID Key Pair using OpenSSL Source: https://context7.com/pimeys/rust-web-push/llms.txt Use OpenSSL to generate a private key and derive the public key in base64url format, which is required for VAPID authentication. ```bash # Generate EC private key (prime256v1 / P-256) openssl ecparam -genkey -name prime256v1 -out private_key.pem # Derive public key bytes for the JavaScript client (base64url, no padding) openssl ec -in private_key.pem -pubout -outform DER | tail -c 65 | base64 | tr '/+' '_-' | tr -d '\n=' ``` -------------------------------- ### Reusable VAPID Signature Builder (No Subscription) Source: https://context7.com/pimeys/rust-web-push/llms.txt Creates a reusable VAPID signature builder from a PEM-encoded private key without binding to a specific subscription. This is efficient for sending to multiple subscribers with the same key. ```rust use web_push::* use std::fs::File; // Load key once at startup let partial_builder = VapidSignatureBuilder::from_pem_no_sub( File::open("private_key.pem").unwrap() ).unwrap(); // Expose the derived public key to JavaScript clients let public_key_bytes: Vec = partial_builder.get_public_key(); // base64url-encode to send to browser: // use ct_codecs::{Base64UrlSafeNoPadding, Encoder}; // let b64 = Base64UrlSafeNoPadding::encode_to_string(&public_key_bytes).unwrap(); // For each subscriber, clone and attach subscription info let subscriptions: Vec = vec![/* ... */]; for sub in &subscriptions { let sig = partial_builder.clone() .add_sub_info(sub) .build() .unwrap(); // use `sig` when building the message for `sub` } ``` -------------------------------- ### Implement Custom WebPushClient Trait Source: https://context7.com/pimeys/rust-web-push/llms.txt Shows how to implement the `WebPushClient` trait for a custom HTTP client. This involves using `request_builder::build_request` to construct the request and `request_builder::parse_response` to handle the response. ```rust use async_trait::async_trait; use web_push::{WebPushClient, WebPushError, WebPushMessage, request_builder}; struct MyCustomClient; #[async_trait] impl WebPushClient for MyCustomClient { async fn send(&self, message: WebPushMessage) -> Result<(), WebPushError> { // build_request is generic over the body type let request = request_builder::build_request::>(message); // --- use your own HTTP library here --- // let (status, body) = my_http_lib::post(request).await?; // Parse the response status and body back into a Result // request_builder::parse_response(status, body) Ok(()) } } ``` -------------------------------- ### IsahcWebPushClient Source: https://context7.com/pimeys/rust-web-push/llms.txt The default async HTTP client, built on isahc. It is thread-safe and should be created once and reused for multiple notifications. ```APIDOC ## `IsahcWebPushClient` — Default HTTP Client (feature: `isahc-client`) The default async HTTP client, built on [isahc](https://crates.io/crates/isahc). Works with any async executor. Thread-safe; `.clone()` shares the underlying connection pool cheaply. Should be created once and reused. ```rust use web_push::* use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let subscription: SubscriptionInfo = serde_json::from_str(r#"{{ "endpoint": "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "keys": {{ "p256dh": "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "auth": "xS03Fi5ErfTNH_l9WHE9Ig" }} }}"#)?; let vapid = VapidSignatureBuilder::from_pem(File::open("private_key.pem")?, &subscription)? .build()?; let mut msg_builder = WebPushMessageBuilder::new(&subscription); msg_builder.set_payload(ContentEncoding::Aes128Gcm, b"Your order has shipped!"); msg_builder.set_vapid_signature(vapid); // Create client once; reuse for many notifications let client = IsahcWebPushClient::new()?; match client.send(msg_builder.build()?).await { Ok(()) => println!("Notification delivered."), Err(WebPushError::EndpointNotValid(_)) => println!("Subscription expired — remove from DB."), Err(WebPushError::ServerError { retry_after, .. }) => { println!("Push service overloaded. Retry after: {:?}", retry_after); } Err(e) => eprintln!("Error: {}", e), } Ok(()) } ``` ``` -------------------------------- ### HyperWebPushClient Source: https://context7.com/pimeys/rust-web-push/llms.txt An alternative client built on hyper with TLS via hyper-tls. Requires Tokio and results in a smaller binary when isahc is excluded. ```APIDOC ## `HyperWebPushClient` — Hyper HTTP Client (feature: `hyper-client`) An alternative client built on [hyper](https://crates.io/crates/hyper) with TLS via `hyper-tls`. Requires Tokio. Produces a smaller binary (~300 KB less) when isahc is excluded. Enable with `features = ["hyper-client"], default-features = false`. ```toml # Cargo.toml web-push = { version = "0.11.0", features = ["hyper-client"], default-features = false } ``` ```rust use web_push::* use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let subscription = SubscriptionInfo::new( "https://fcm.googleapis.com/fcm/send/TOKEN", "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6tsDnReWmhsImkhDF_DBdkNSU", "EvcWjEgzr4rbvhfi3yds0A", ); let vapid = VapidSignatureBuilder::from_pem(File::open("private_key.pem")?, &subscription)? .build()?; let mut builder = WebPushMessageBuilder::new(&subscription); builder.set_payload(ContentEncoding::Aes128Gcm, b"Hello via hyper!"); builder.set_vapid_signature(vapid); // HyperWebPushClient works identically to IsahcWebPushClient let client = HyperWebPushClient::new(); client.send(builder.build()?).await?; Ok(()) } ``` ``` -------------------------------- ### Build VAPID Signature from Base64 Source: https://context7.com/pimeys/rust-web-push/llms.txt Constructs a VAPID signature using a base64url-encoded private key. Ensure the key is URL-safe and has no padding. ```rust use web_push::* let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); // Raw private key bytes, base64url-encoded (no padding) — common format from VAPID key generator sites let vapid_signature = VapidSignatureBuilder::from_base64( "IQ9Ur0ykXoHS9gzfYX0aBjy9lvdrjx_PFUXmie9YRcY", &subscription, ) .unwrap() .build() .unwrap(); ``` -------------------------------- ### Send Web Push Notification with HyperClient Source: https://context7.com/pimeys/rust-web-push/llms.txt Uses `HyperWebPushClient` to send a web push notification. This client requires Tokio and produces a smaller binary compared to the default `IsahcWebPushClient`. ```rust use web_push::* use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let subscription = SubscriptionInfo::new( "https://fcm.googleapis.com/fcm/send/TOKEN", "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6tsDnReWmhsImkhDF_DBdkNSU", "EvcWjEgzr4rbvhfi3yds0A", ); let vapid = VapidSignatureBuilder::from_pem(File::open("private_key.pem")?, &subscription)? .build()?; let mut builder = WebPushMessageBuilder::new(&subscription); builder.set_payload(ContentEncoding::Aes128Gcm, b"Hello via hyper!"); builder.set_vapid_signature(vapid); // HyperWebPushClient works identically to IsahcWebPushClient let client = HyperWebPushClient::new(); client.send(builder.build()?).await?; Ok(()) } ``` -------------------------------- ### Build and Encrypt Web Push Message Source: https://context7.com/pimeys/rust-web-push/llms.txt Constructs a `WebPushMessage`, optionally encrypting a payload using ECE. The builder accepts a `VapidSignature` and the plaintext payload, encrypting it internally. Maximum payload size is 3,800 bytes. ```rust use web_push::* use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let subscription = SubscriptionInfo::new( "https://fcm.googleapis.com/fcm/send/eKClHsXFm9E:APA91b...", "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6tsDnReWmhsImkhDF_DBdkNSU", "EvcWjEgzr4rbvhfi3yds0A", ); // Build VAPID signature let vapid_sig = VapidSignatureBuilder::from_pem( File::open("private_key.pem")?, &subscription, )? .build()?; // Build the message let mut builder = WebPushMessageBuilder::new(&subscription); // Encrypt payload with aes128gcm (preferred) or AesGcm (legacy) builder.set_payload(ContentEncoding::Aes128Gcm, b"Hello from the server!"); // Attach VAPID signature (required when sending a payload) builder.set_vapid_signature(vapid_sig); // Optional metadata builder.set_ttl(3600); // 1 hour retention; default = 28 days builder.set_urgency(Urgency::High); // wake device immediately builder.set_topic("breaking-news".to_string()); // replaces any queued message with same topic let message: WebPushMessage = builder.build()?; // `message` is ready to pass to a WebPushClient::send() Ok(()) } ``` -------------------------------- ### Build HTTP Request with request_builder::build_request Source: https://context7.com/pimeys/rust-web-push/llms.txt Constructs a raw `http::Request` with necessary headers like TTL, Urgency, and Authorization. This function is generic over the body type, allowing integration with any HTTP client library. ```rust use web_push::{ request_builder::build_request, ContentEncoding, SubscriptionInfo, WebPushMessageBuilder, }; let info = SubscriptionInfo::new( "https://fcm.googleapis.com/fcm/send/TOKEN", "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6tsDnReWmhsImkhDF_DBdkNSU", "EvcWjEgzr4rbvhfi3yds0A", ); let mut builder = WebPushMessageBuilder::new(&info); builder.set_payload(ContentEncoding::Aes128Gcm, b"test payload"); // Build an http::Request with an isahc::Body #[cfg(feature = "isahc-client")] let request = build_request::(builder.build().unwrap()); let ttl = request.headers().get("TTL").unwrap().to_str().unwrap(); let encoding = request.headers().get("Content-Encoding").unwrap().to_str().unwrap(); println!("TTL: {ttl}, Encoding: {encoding}"); // TTL: 2419200, Encoding: aes128gcm ``` -------------------------------- ### VapidSignatureBuilder::from_base64 Source: https://context7.com/pimeys/rust-web-push/llms.txt Builds a VAPID signature from a base64url-encoded private key and subscription information. ```APIDOC ## `VapidSignatureBuilder::from_base64` Builds a VAPID signature from a base64url-encoded private key and subscription information. ### Usage ```rust use web_push::*; let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); // Raw private key bytes, base64url-encoded (no padding) — common format from VAPID key generator sites let vapid_signature = VapidSignatureBuilder::from_base64( "IQ9Ur0ykXoHS9gzfYX0aBjy9lvdrjx_PFUXmie9YRcY", &subscription, ) .unwrap() .build() .unwrap(); ``` ``` -------------------------------- ### PartialVapidSignatureBuilder Source: https://context7.com/pimeys/rust-web-push/llms.txt A reusable builder that holds only the private key, without binding to a specific subscription. Useful for servers sending to many subscribers with the same key. ```APIDOC ## `PartialVapidSignatureBuilder` — Reusable Builder (No Subscription) A cloneable builder that holds only the private key, without binding to a specific subscription. Designed for server scenarios that send to many subscribers with the same key: load the key once, then cheaply clone and attach per-subscription info. ### Usage ```rust use web_push::*; use std::fs::File; // Load key once at startup let partial_builder = VapidSignatureBuilder::from_pem_no_sub( File::open("private_key.pem").unwrap() ).unwrap(); // Expose the derived public key to JavaScript clients let public_key_bytes: Vec = partial_builder.get_public_key(); // base64url-encode to send to browser: // use ct_codecs::{Base64UrlSafeNoPadding, Encoder}; // let b64 = Base64UrlSafeNoPadding::encode_to_string(&public_key_bytes).unwrap(); // For each subscriber, clone and attach subscription info let subscriptions: Vec = vec![/* ... */]; for sub in &subscriptions { let sig = partial_builder.clone() .add_sub_info(sub) .build() .unwrap(); // use `sig` when building the message for `sub` } ``` Also available as `from_der_no_sub` and `from_base64_no_sub`. ``` -------------------------------- ### Derive VAPID Public Key from Private Key Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Command to derive the public key from a generated VAPID private key using OpenSSL. The public key is typically provided to the JavaScript client. ```bash openssl ec -in private_key.pem -pubout -outform DER|tail -c 65|base64|tr '/+' '_-'|tr -d '\n=' ``` -------------------------------- ### Build VAPID Signature from PEM Key Source: https://context7.com/pimeys/rust-web-push/llms.txt Create a VAPID signature using a private key in PEM format. This method automatically includes standard JWT claims like audience and expiry, which can be customized. ```rust use web_push::* use std::fs::File; let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); let file = File::open("private_key.pem").unwrap(); let mut sig_builder = VapidSignatureBuilder::from_pem(file, &subscription).unwrap(); // Optional: override or add custom JWT claims sig_builder.add_claim("sub", "mailto:admin@example.com"); let vapid_signature: VapidSignature = sig_builder.build().unwrap(); // vapid_signature.auth_t — signed JWT string // vapid_signature.auth_k — public key bytes ``` -------------------------------- ### Generate VAPID Private Key Source: https://github.com/pimeys/rust-web-push/blob/master/README.md Command to generate a private key for VAPID authentication using OpenSSL. This key is used by the server to sign push notification requests. ```bash openssl ecparam -genkey -name prime256v1 -out private_key.pem ``` -------------------------------- ### Build VAPID Signature from DER Key Source: https://context7.com/pimeys/rust-web-push/llms.txt Generate a VAPID signature using a private key in DER format. The builder handles the necessary JWT claims and signing process. ```rust use web_push::* use std::fs::File; let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); let file = File::open("private_key.der").unwrap(); let vapid_signature = VapidSignatureBuilder::from_der(file, &subscription) .unwrap() .build() .unwrap(); ``` -------------------------------- ### VapidSignatureBuilder - VAPID Authentication Source: https://context7.com/pimeys/rust-web-push/llms.txt Constructs a VAPID signature (ES256 JWT) that authorises the server to send notifications. The builder automatically adds the required `aud` (audience derived from the endpoint host) and `exp` (12-hour expiry) JWT claims; these can be overridden with `add_claim`. Three key input formats are supported: PEM, DER, and raw base64url. ```APIDOC ## VapidSignatureBuilder - VAPID Authentication ### Description Constructs a VAPID signature (ES256 JWT) that authorises the server to send notifications. The builder automatically adds the required `aud` (audience derived from the endpoint host) and `exp` (12-hour expiry) JWT claims; these can be overridden with `add_claim`. Three key input formats are supported: PEM, DER, and raw base64url. ### `VapidSignatureBuilder::from_pem` ```rust use web_push::*; use std::fs::File; let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); let file = File::open("private_key.pem").unwrap(); let mut sig_builder = VapidSignatureBuilder::from_pem(file, &subscription).unwrap(); // Optional: override or add custom JWT claims sig_builder.add_claim("sub", "mailto:admin@example.com"); let vapid_signature: VapidSignature = sig_builder.build().unwrap(); // vapid_signature.auth_t — signed JWT string // vapid_signature.auth_k — public key bytes ``` ### `VapidSignatureBuilder::from_der` ```rust use web_push::*; use std::fs::File; let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); let file = File::open("private_key.der").unwrap(); let vapid_signature = VapidSignatureBuilder::from_der(file, &subscription) .unwrap() .build() .unwrap(); ``` ``` -------------------------------- ### request_builder::build_request Source: https://context7.com/pimeys/rust-web-push/llms.txt Low-level function to construct raw HTTP requests with necessary headers like TTL, Urgency, Topic, Content-Encoding, Content-Type, and Authorization. It is generic over the body type. ```APIDOC ## `request_builder::build_request` — Low-Level HTTP Request Construction Builds the raw `http::Request` with the correct headers (`TTL`, `Urgency`, `Topic`, `Content-Encoding`, `Content-Type`, `Authorization`). Generic over the body type so it works with any HTTP client library. ```rust use web_push::{ request_builder::build_request, ContentEncoding, SubscriptionInfo, WebPushMessageBuilder, }; let info = SubscriptionInfo::new( "https://fcm.googleapis.com/fcm/send/TOKEN", "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6tsDnReWmhsImkhDF_DBdkNSU", "EvcWjEgzr4rbvhfi3yds0A", ); let mut builder = WebPushMessageBuilder::new(&info); builder.set_payload(ContentEncoding::Aes128Gcm, b"test payload"); // Build an http::Request with an isahc::Body #[cfg(feature = "isahc-client")] let request = build_request::(builder.build().unwrap()); let ttl = request.headers().get("TTL").unwrap().to_str().unwrap(); let encoding = request.headers().get("Content-Encoding").unwrap().to_str().unwrap(); println!("TTL: {ttl}, Encoding: {encoding}"); // TTL: 2419200, Encoding: aes128gcm ``` ``` -------------------------------- ### SubscriptionInfo - Browser Subscription Data Source: https://context7.com/pimeys/rust-web-push/llms.txt Holds the push endpoint URL and the client's encryption keys obtained from the browser's PushSubscription object. It implements serde::Deserialize, allowing direct deserialization of a browser pushSubscription JSON object. ```APIDOC ## SubscriptionInfo ### Description Holds the push endpoint URL and the client's encryption keys obtained from the browser's `PushSubscription` object. Implements `serde::Deserialize`, so a browser `pushSubscription` JSON object can be deserialized directly into it. ### Usage ```rust use web_push::SubscriptionInfo; use serde_json::json; // Option 1: construct manually let subscription = SubscriptionInfo::new( "https://updates.push.services.mozilla.com/wpush/v1/gAAAAAB...", "BLMbF9ffKBiWQLCKvTHb6LO8Nb6dcUh6TItC455vu2kElga6PQvUmaFyCdykxY2nOSSL3yKgfbmFLRTUaGv4yV8", "xS03Fi5ErfTNH_l9WHE9Ig", ); // Option 2: deserialize from browser pushSubscription JSON (e.g., received via HTTP POST) let raw = json!({ "endpoint": "https://fcm.googleapis.com/fcm/send/eKClHsXFm9E:APA91b...", "keys": { "p256dh": "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6ts...", "auth": "EvcWjEgzr4rbvhfi3yds0A" } }); let subscription: SubscriptionInfo = serde_json::from_value(raw).unwrap(); println!("Endpoint: {}", subscription.endpoint); println!("p256dh: {}", subscription.keys.p256dh); println!("auth: {}", subscription.keys.auth); ``` ``` -------------------------------- ### WebPushMessageBuilder Source: https://context7.com/pimeys/rust-web-push/llms.txt Constructs the final `WebPushMessage`, optionally encrypting a payload using ECE. It accepts the `VapidSignature` and plaintext payload, encrypting it internally. ```APIDOC ## `WebPushMessageBuilder` — Build & Encrypt the Notification Constructs the final `WebPushMessage`, optionally encrypting a payload using ECE. The builder accepts the `VapidSignature` from above and the raw plaintext payload, which it encrypts internally before building. Maximum payload size is 3,800 bytes (practical limit enforced at 3,052 before ECE overhead). ### Usage ```rust use web_push::*; use std::fs::File; #[tokio::main] async fn main() -> Result<(), Box> { let subscription = SubscriptionInfo::new( "https://fcm.googleapis.com/fcm/send/eKClHsXFm9E:APA91b...", "BGa4N1PI79lboMR_YrwCiCsgp35DRvedt7opHcf0yM3iOBTSoQYqQLwWxAfRKE6tsDnReWmhsImkhDF_DBdkNSU", "EvcWjEgzr4rbvhfi3yds0A", ); // Build VAPID signature let vapid_sig = VapidSignatureBuilder::from_pem( File::open("private_key.pem")?, &subscription, )? .build()?; // Build the message let mut builder = WebPushMessageBuilder::new(&subscription); // Encrypt payload with aes128gcm (preferred) or AesGcm (legacy) builder.set_payload(ContentEncoding::Aes128Gcm, b"Hello from the server!"); // Attach VAPID signature (required when sending a payload) builder.set_vapid_signature(vapid_sig); // Optional metadata builder.set_ttl(3600); // 1 hour retention; default = 28 days builder.set_urgency(Urgency::High); // wake device immediately builder.set_topic("breaking-news".to_string()); // replaces any queued message with same topic let message: WebPushMessage = builder.build()?; // `message` is ready to pass to a WebPushClient::send() Ok(()) } ``` ``` -------------------------------- ### Select Payload Encryption Algorithm Source: https://context7.com/pimeys/rust-web-push/llms.txt Specifies the ECE encryption standard for the payload. `Aes128Gcm` is recommended for modern browsers, while `AesGcm` is for legacy support. ```rust use web_push::ContentEncoding; // Recommended for all current browsers let encoding = ContentEncoding::Aes128Gcm; println!("{}", encoding.to_str()); // "aes128gcm" // Legacy — only if you know the subscriber requires it let encoding_legacy = ContentEncoding::AesGcm; println!("{}", encoding_legacy.to_str()); // "aesgcm" ``` -------------------------------- ### Handle WebPushError in Rust Source: https://context7.com/pimeys/rust-web-push/llms.txt A function to match and handle various `WebPushError` variants, providing specific error messages for different issues like unauthorized credentials, expired subscriptions, or server errors. ```rust use web_push::WebPushError; fn handle_push_error(err: WebPushError) { match err { WebPushError::Unauthorized(_) => eprintln!("Bad VAPID credentials"), WebPushError::EndpointNotValid(_) => eprintln!("Subscription expired — delete it"), WebPushError::EndpointNotFound(_) => eprintln!("Endpoint not found"), WebPushError::PayloadTooLarge => eprintln!("Payload exceeds ~3052 bytes"), WebPushError::InvalidCryptoKeys => eprintln!("Bad p256dh or auth key"), WebPushError::InvalidTopic => eprintln!("Topic must be ≤32 base64url chars"), WebPushError::ServerError { retry_after, info } => { eprintln!("Push service error: {}. Retry after: {:?}", info, retry_after); } WebPushError::Io(e) => eprintln!("I/O error: {}", e), other => eprintln!("Other error: {} ({})", other, other.short_description()), } } ``` -------------------------------- ### WebPushClient Trait Source: https://context7.com/pimeys/rust-web-push/llms.txt The `async_trait`-based trait implemented by both built-in clients. Users can implement this trait to integrate custom HTTP libraries. ```APIDOC ## `WebPushClient` — Custom Client Trait The `async_trait`-based trait implemented by both built-in clients. Implement it with `request_builder::build_request` and `request_builder::parse_response` to plug in any HTTP library. ```rust use async_trait::async_trait; use web_push::{WebPushClient, WebPushError, WebPushMessage, request_builder}; struct MyCustomClient; #[async_trait] impl WebPushClient for MyCustomClient { async fn send(&self, message: WebPushMessage) -> Result<(), WebPushError> { // build_request is generic over the body type let request = request_builder::build_request::>(message); // --- use your own HTTP library here --- // let (status, body) = my_http_lib::post(request).await?; // Parse the response status and body back into a Result // request_builder::parse_response(status, body) Ok(()) } } ``` ``` -------------------------------- ### Urgency Source: https://context7.com/pimeys/rust-web-push/llms.txt Controls the `Urgency` HTTP header sent to the push service, allowing it to optimize battery life by deferring low-priority messages. ```APIDOC ## `Urgency` — Notification Priority Controls the `Urgency` HTTP header sent to the push service, allowing it to optimise battery life by deferring low-priority messages on low-power devices. ### Usage ```rust use web_push::{Urgency, WebPushMessageBuilder, SubscriptionInfo}; let subscription = SubscriptionInfo::new("https://example.com/push", "p256dh_key", "auth_secret"); let mut builder = WebPushMessageBuilder::new(&subscription); // Variants: VeryLow | Low | Normal (default) | High builder.set_urgency(Urgency::High); // critical alert, wake device builder.set_urgency(Urgency::Normal); // news update builder.set_urgency(Urgency::Low); // background sync builder.set_urgency(Urgency::VeryLow); // advertisements ``` ``` -------------------------------- ### Parse HTTP Response to WebPushError in Rust Source: https://context7.com/pimeys/rust-web-push/llms.txt Converts an HTTP status code and response body into `Ok(())` or the appropriate `WebPushError` variant. Used internally by clients and exposed for custom implementations. ```rust use http::StatusCode; use web_push::{request_builder::parse_response, WebPushError}; // Success assert!(parse_response(StatusCode::CREATED, vec![]).is_ok()); // Expired subscription — caller should remove it from the database match parse_response(StatusCode::GONE, vec![]) { Err(WebPushError::EndpointNotValid(info)) => { eprintln!("Subscription gone: {}", info); } _ => {} } // Server-side rate limiting match parse_response(StatusCode::INTERNAL_SERVER_ERROR, vec![]) { Err(WebPushError::ServerError { retry_after, .. }) => { if let Some(dur) = retry_after { println!("Retry in {:?}", dur); } } _ => {} } ``` -------------------------------- ### Set Notification Urgency Source: https://context7.com/pimeys/rust-web-push/llms.txt Controls the `Urgency` HTTP header to optimize battery life. Options range from `VeryLow` to `High`, influencing how the push service handles deferring messages on low-power devices. ```rust use web_push::{Urgency, WebPushMessageBuilder, SubscriptionInfo}; let subscription = SubscriptionInfo::new("https://example.com/push", "p256dh_key", "auth_secret"); let mut builder = WebPushMessageBuilder::new(&subscription); // Variants: VeryLow | Low | Normal (default) | High builder.set_urgency(Urgency::High); // critical alert, wake device builder.set_urgency(Urgency::Normal); // news update builder.set_urgency(Urgency::Low); // background sync builder.set_urgency(Urgency::VeryLow); // advertisements ``` -------------------------------- ### ContentEncoding Source: https://context7.com/pimeys/rust-web-push/llms.txt Selects the ECE encryption standard applied to the payload. `Aes128Gcm` is the modern standard. ```APIDOC ## `ContentEncoding` — Payload Encryption Algorithm Selects the ECE encryption standard applied to the payload. `Aes128Gcm` is the modern standard and should be used unless targeting very old browsers. ### Usage ```rust use web_push::ContentEncoding; // Recommended for all current browsers let encoding = ContentEncoding::Aes128Gcm; println!("{}", encoding.to_str()); // "aes128gcm" // Legacy — only if you know the subscriber requires it let encoding_legacy = ContentEncoding::AesGcm; println!("{}", encoding_legacy.to_str()); // "aesgcm" ``` ``` -------------------------------- ### parse_response Source: https://context7.com/pimeys/rust-web-push/llms.txt Converts an HTTP status code and response body into Ok(()) or the appropriate WebPushError variant. This function is used internally by clients and can also be exposed for custom client implementations. ```APIDOC ## `request_builder::parse_response` — HTTP Response → `WebPushError` Converts an HTTP status code and response body into `Ok(())` or the appropriate `WebPushError` variant. Used internally by both clients and exposed for custom client implementations. ```rust use http::StatusCode; use web_push::{request_builder::parse_response, WebPushError}; // Success assert!(parse_response(StatusCode::CREATED, vec![]).is_ok()); // Expired subscription — caller should remove it from the database match parse_response(StatusCode::GONE, vec![]) { Err(WebPushError::EndpointNotValid(info)) => { eprintln!("Subscription gone: {}", info); } _ => {} } // Server-side rate limiting match parse_response(StatusCode::INTERNAL_SERVER_ERROR, vec![]) { Err(WebPushError::ServerError { retry_after, .. }) => { if let Some(dur) = retry_after { println!("Retry in {:?}", dur); } } _ => {} } ``` ``` -------------------------------- ### WebPushError Enum Source: https://context7.com/pimeys/rust-web-push/llms.txt The WebPushError enum covers both client-side validation errors and push-service HTTP error responses. All fallible operations return Result<_, WebPushError>. ```APIDOC ## `WebPushError` — Error Type All fallible operations return `Result<_, WebPushError>`. The enum covers both client-side validation errors and push-service HTTP error responses. ```rust use web_push::WebPushError; fn handle_push_error(err: WebPushError) { match err { WebPushError::Unauthorized(_) => eprintln!("Bad VAPID credentials"), WebPushError::EndpointNotValid(_) => eprintln!("Subscription expired — delete it"), WebPushError::EndpointNotFound(_) => eprintln!("Endpoint not found"), WebPushError::PayloadTooLarge => eprintln!("Payload exceeds ~3052 bytes"), WebPushError::InvalidCryptoKeys => eprintln!("Bad p256dh or auth key"), WebPushError::InvalidTopic => eprintln!("Topic must be ≤32 base64url chars"), WebPushError::ServerError { retry_after, info } => { eprintln!("Push service error: {}. Retry after: {:?}", info, retry_after); } WebPushError::Io(e) => eprintln!("I/O error: {}", e), other => eprintln!("Other error: {} ({})", other, other.short_description()), } } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.