pub struct EncryptedBodyBuilder<T> { /* private fields */ }Expand description
Route builder that expects an authenticated-encrypted request body of type T
(ChaCha20-Poly1305).
Obtained from ServerMechanism::encryption. On each matching request the raw
body bytes are decrypted using the SerializationKey supplied there. If
decryption fails the route immediately returns 403 Forbidden.
Optionally attach shared state via state before
finalising with onconnect /
onconnect_sync.
Implementations§
Source§impl<T> EncryptedBodyBuilder<T>
impl<T> EncryptedBodyBuilder<T>
Sourcepub fn onconnect<F, Fut, Re>(self, handler: F) -> SocketType
pub fn onconnect<F, Fut, Re>(self, handler: F) -> SocketType
Finalises this route with an async handler that receives the decrypted body as T.
Examples found in repository?
examples/socket_client_server.rs (lines 120-124)
62async fn main() -> Result<(), Box<dyn std::error::Error>> {
63 // ── Build routes ──────────────────────────────────────────────────────────
64 let store: Arc<Mutex<Vec<Item>>> = Arc::new(Mutex::new(vec![]));
65
66 let mut server = Server::default();
67
68 // Plain GET — no body, no state.
69 server.mechanism(
70 ServerMechanism::get("/health")
71 .onconnect(|| async { reply!(json => Health { ok: true }) })
72 );
73
74 // POST with a JSON body — echoes back the created item.
75 server.mechanism(
76 ServerMechanism::post("/items")
77 .json::<NewItem>()
78 .onconnect(|body: NewItem| async move {
79 reply!(json => Item { id: 1, name: body.name }, status => Status::Created)
80 })
81 );
82
83 // GET with query parameters — filters the stored items by prefix.
84 server.mechanism({
85 let store = store.clone();
86 ServerMechanism::get("/items/search")
87 .state(store)
88 .query::<Filter>()
89 .onconnect(|state: Arc<Mutex<Vec<Item>>>, f: Filter| async move {
90 let items = state.lock().unwrap();
91 let matches: Vec<Item> = items
92 .iter()
93 .filter(|i| i.name.starts_with(&f.prefix))
94 .cloned()
95 .collect();
96 reply!(json => SearchResult { matches })
97 })
98 });
99
100 // POST with shared state — stores the item and returns it.
101 server.mechanism({
102 let store = store.clone();
103 ServerMechanism::post("/items/store")
104 .state(store)
105 .json::<NewItem>()
106 .onconnect(|state: Arc<Mutex<Vec<Item>>>, body: NewItem| async move {
107 let mut s = state.lock().unwrap();
108 let id = s.len() as u32 + 1;
109 let item = Item { id, name: body.name };
110 s.push(item.clone());
111 reply!(json => item, status => Status::Created)
112 })
113 });
114
115 // POST with authenticated-encrypted body (ChaCha20-Poly1305 via SerializationKey).
116 // The body is decrypted before the handler is called; a wrong key returns 403.
117 server.mechanism(
118 ServerMechanism::post("/items/secure")
119 .encryption::<NewItem>(SerializationKey::Default)
120 .onconnect(|body: NewItem| async move {
121 let item = Item { id: 99, name: body.name };
122 // The response must also be sealed so the client can open it.
123 reply!(sealed => item, key => SerializationKey::Default)
124 })
125 );
126
127 // ── Serve with graceful shutdown ──────────────────────────────────────────
128 let (tx, rx) = tokio::sync::oneshot::channel::<()>();
129 let server_handle = tokio::spawn(async move {
130 server.serve_with_graceful_shutdown(
131 ([127, 0, 0, 1], PORT),
132 async { rx.await.ok(); },
133 ).await;
134 });
135
136 // Give the server time to bind before firing requests.
137 tokio::time::sleep(Duration::from_millis(200)).await;
138 println!("Server started on port {PORT}");
139
140 // ── Client requests ───────────────────────────────────────────────────────
141 let client = ClientBuilder::new(Target::Localhost(PORT))
142 .timeout(Duration::from_secs(5))
143 .build_async();
144
145 // GET /health
146 let health: Health = client.get("/health").send().await?;
147 assert!(health.ok);
148 println!("GET /health → ok={}", health.ok);
149
150 // POST /items (JSON body)
151 let created: Item = client
152 .post("/items")
153 .json(NewItem { name: "widget".into() })
154 .send()
155 .await?;
156 assert_eq!(created.name, "widget");
157 println!("POST /items → {:?}", created);
158
159 // POST /items/store (shared state — populates the store)
160 let stored: Item = client
161 .post("/items/store")
162 .json(NewItem { name: "gadget".into() })
163 .send()
164 .await?;
165 println!("POST /items/store → {:?}", stored);
166
167 let stored2: Item = client
168 .post("/items/store")
169 .json(NewItem { name: "gizmo".into() })
170 .send()
171 .await?;
172 println!("POST /items/store → {:?}", stored2);
173
174 // GET /items/search?prefix=ga (query params)
175 let result: SearchResult = client
176 .get("/items/search")
177 .query(Filter { prefix: "ga".into() })
178 .send()
179 .await?;
180 assert!(result.matches.iter().all(|i| i.name.starts_with("ga")));
181 println!("GET /items/search?prefix=ga → {} match(es): {:?}", result.matches.len(), result.matches);
182
183 // POST /items/secure (authenticated-encrypted body)
184 let secure_item = client
185 .post("/items/secure")
186 .encryption(NewItem { name: "secret".into() }, SerializationKey::Default)
187 .send::<Item>()
188 .await?;
189 assert_eq!(secure_item.name, "secret");
190 println!("POST /items/secure → {:?}", secure_item);
191
192 // ── Shutdown ──────────────────────────────────────────────────────────────
193 tx.send(()).ok();
194 server_handle.await?;
195 println!("\nAll requests successful ✓");
196 Ok(())
197}Sourcepub unsafe fn onconnect_sync<F, Re>(self, handler: F) -> SocketType
pub unsafe fn onconnect_sync<F, Re>(self, handler: F) -> SocketType
Finalises this route with a synchronous handler that receives the decrypted
body as T.
§Safety
See ServerMechanism::onconnect_sync for the thread-pool safety notes.
Sourcepub fn state<S: Clone + Send + Sync + 'static>(
self,
state: S,
) -> StatefulEncryptedBodyBuilder<T, S>
pub fn state<S: Clone + Send + Sync + 'static>( self, state: S, ) -> StatefulEncryptedBodyBuilder<T, S>
Attaches shared state S, transitioning to StatefulEncryptedBodyBuilder.
Auto Trait Implementations§
impl<T> Freeze for EncryptedBodyBuilder<T>
impl<T> RefUnwindSafe for EncryptedBodyBuilder<T>where
T: RefUnwindSafe,
impl<T> Send for EncryptedBodyBuilder<T>where
T: Send,
impl<T> Sync for EncryptedBodyBuilder<T>where
T: Sync,
impl<T> Unpin for EncryptedBodyBuilder<T>where
T: Unpin,
impl<T> UnsafeUnpin for EncryptedBodyBuilder<T>
impl<T> UnwindSafe for EncryptedBodyBuilder<T>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more