socket_client_server/
socket_client_server.rs1use std::sync::{Arc, Mutex};
19use std::time::Duration;
20use serde::{Deserialize, Serialize};
21use bincode::{Encode, Decode};
22use toolkit_zero::socket::SerializationKey;
23use toolkit_zero::socket::server::{Server, ServerMechanism, Status, reply};
24use toolkit_zero::socket::client::{ClientBuilder, Target};
25
26#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)]
30struct Item {
31 id: u32,
32 name: String,
33}
34
35#[derive(Debug, Deserialize, Serialize, Encode, Decode)]
37struct NewItem {
38 name: String,
39}
40
41#[derive(Debug, Deserialize, Serialize)]
43struct Filter {
44 prefix: String,
45}
46
47#[derive(Debug, Serialize, Deserialize)]
49struct SearchResult {
50 matches: Vec<Item>,
51}
52
53#[derive(Debug, Serialize, Deserialize)]
55struct Health {
56 ok: bool,
57}
58
59const PORT: u16 = 19_876;
60
61#[tokio::main]
62async fn main() -> Result<(), Box<dyn std::error::Error>> {
63 let store: Arc<Mutex<Vec<Item>>> = Arc::new(Mutex::new(vec![]));
65
66 let mut server = Server::default();
67
68 server.mechanism(
70 ServerMechanism::get("/health")
71 .onconnect(|| async { reply!(json => Health { ok: true }) })
72 );
73
74 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 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 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 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 reply!(sealed => item, key => SerializationKey::Default)
124 })
125 );
126
127 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 tokio::time::sleep(Duration::from_millis(200)).await;
138 println!("Server started on port {PORT}");
139
140 let client = ClientBuilder::new(Target::Localhost(PORT))
142 .timeout(Duration::from_secs(5))
143 .build_async();
144
145 let health: Health = client.get("/health").send().await?;
147 assert!(health.ok);
148 println!("GET /health → ok={}", health.ok);
149
150 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 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 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 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 tx.send(()).ok();
194 server_handle.await?;
195 println!("\nAll requests successful ✓");
196 Ok(())
197}