1use actor12::{Actor, Call, Handler, Init, MpscChannel, Multi, spawn};
2use futures::future;
3use std::collections::HashMap;
4use std::future::Future;
5
6pub struct RouterActor {
8 routes: HashMap<String, String>,
9 request_count: u32,
10}
11
12#[derive(Debug)]
14pub struct GetRouteRequest {
15 pub path: String,
16}
17
18#[derive(Debug)]
19pub struct AddRouteRequest {
20 pub path: String,
21 pub handler: String,
22}
23
24#[derive(Debug)]
25pub struct ListRoutesRequest;
26
27#[derive(Debug)]
28pub struct StatsRequest;
29
30#[derive(Debug)]
31pub struct ResetRequest;
32
33#[derive(Debug)]
35pub struct RouteResponse {
36 pub found: bool,
37 pub handler: Option<String>,
38}
39
40impl Actor for RouterActor {
41 type Spec = ();
42 type Message = Multi<Self>;
43 type Channel = MpscChannel<Self::Message>;
44 type Cancel = ();
45 type State = ();
46
47 fn state(_spec: &Self::Spec) -> Self::State {}
48
49 fn init(_ctx: Init<'_, Self>) -> impl Future<Output = Result<Self, Self::Cancel>> + Send + 'static {
50 println!("Router actor initialized");
51 future::ready(Ok(RouterActor {
52 routes: HashMap::new(),
53 request_count: 0,
54 }))
55 }
56}
57
58impl Handler<GetRouteRequest> for RouterActor {
60 type Reply = Result<RouteResponse, anyhow::Error>;
61
62 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: GetRouteRequest) -> Self::Reply {
63 self.request_count += 1;
64
65 let handler = self.routes.get(&msg.path).cloned();
66 let found = handler.is_some();
67
68 println!("GET {}: {} (handler: {:?})", msg.path, if found { "FOUND" } else { "NOT_FOUND" }, handler);
69
70 Ok(RouteResponse { found, handler })
71 }
72}
73
74impl Handler<AddRouteRequest> for RouterActor {
76 type Reply = Result<bool, anyhow::Error>;
77
78 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: AddRouteRequest) -> Self::Reply {
79 self.request_count += 1;
80
81 let was_existing = self.routes.contains_key(&msg.path);
82 self.routes.insert(msg.path.clone(), msg.handler.clone());
83
84 println!("ROUTE ADDED: {} -> {} ({})",
85 msg.path, msg.handler,
86 if was_existing { "UPDATED" } else { "NEW" });
87
88 Ok(!was_existing) }
90}
91
92impl Handler<ListRoutesRequest> for RouterActor {
94 type Reply = Result<Vec<(String, String)>, anyhow::Error>;
95
96 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, _msg: ListRoutesRequest) -> Self::Reply {
97 self.request_count += 1;
98
99 let routes: Vec<(String, String)> = self.routes.iter()
100 .map(|(k, v)| (k.clone(), v.clone()))
101 .collect();
102
103 println!("LISTING {} routes:", routes.len());
104 for (path, handler) in &routes {
105 println!(" {} -> {}", path, handler);
106 }
107
108 Ok(routes)
109 }
110}
111
112impl Handler<StatsRequest> for RouterActor {
114 type Reply = Result<(u32, usize), anyhow::Error>;
115
116 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, _msg: StatsRequest) -> Self::Reply {
117 let stats = (self.request_count, self.routes.len());
118 println!("STATS: {} total requests, {} registered routes", stats.0, stats.1);
119 Ok(stats)
120 }
121}
122
123impl Handler<ResetRequest> for RouterActor {
125 type Reply = Result<(), anyhow::Error>;
126
127 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, _msg: ResetRequest) -> Self::Reply {
128 let old_count = self.request_count;
129 let old_routes = self.routes.len();
130
131 self.routes.clear();
132 self.request_count = 0;
133
134 println!("RESET: Cleared {} routes, reset request count from {}", old_routes, old_count);
135 Ok(())
136 }
137}
138
139impl Handler<String> for RouterActor {
141 type Reply = Result<String, anyhow::Error>;
142
143 async fn handle(&mut self, _ctx: Call<'_, Self, Self::Reply>, msg: String) -> Self::Reply {
144 self.request_count += 1;
145
146 let parts: Vec<&str> = msg.split_whitespace().collect();
147 match parts.as_slice() {
148 ["help"] => {
149 let help = "Available commands:\n\
150 - help: Show this help\n\
151 - status: Show current status\n\
152 - echo <text>: Echo back the text";
153 println!("HELP requested");
154 Ok(help.to_string())
155 }
156 ["status"] => {
157 let status = format!("Router status: {} requests, {} routes",
158 self.request_count, self.routes.len());
159 println!("STATUS requested");
160 Ok(status)
161 }
162 ["echo", rest @ ..] => {
163 let text = rest.join(" ");
164 let response = format!("Echo: {}", text);
165 println!("ECHO: {}", text);
166 Ok(response)
167 }
168 _ => {
169 let response = format!("Unknown command: '{}'. Try 'help'", msg);
170 println!("UNKNOWN COMMAND: {}", msg);
171 Ok(response)
172 }
173 }
174 }
175}
176
177#[tokio::main]
178async fn main() -> anyhow::Result<()> {
179 println!("=== Dynamic Dispatch Example ===\n");
180
181 let router = spawn::<RouterActor>(());
182
183 println!("1. Setting up routes:");
185
186 let _: Result<bool, anyhow::Error> = router.ask_dyn(AddRouteRequest {
187 path: "/api/users".to_string(),
188 handler: "UserHandler".to_string(),
189 }).await;
190
191 let _: Result<bool, anyhow::Error> = router.ask_dyn(AddRouteRequest {
192 path: "/api/posts".to_string(),
193 handler: "PostHandler".to_string(),
194 }).await;
195
196 let _: Result<bool, anyhow::Error> = router.ask_dyn(AddRouteRequest {
197 path: "/health".to_string(),
198 handler: "HealthHandler".to_string(),
199 }).await;
200
201 println!("\n2. Testing route lookups:");
202
203 let response: Result<RouteResponse, anyhow::Error> = router.ask_dyn(GetRouteRequest {
204 path: "/api/users".to_string(),
205 }).await;
206 println!("Lookup result: {:?}", response);
207
208 let response: Result<RouteResponse, anyhow::Error> = router.ask_dyn(GetRouteRequest {
209 path: "/nonexistent".to_string(),
210 }).await;
211 println!("Lookup result: {:?}", response);
212
213 println!("\n3. Listing all routes:");
214 let routes: Result<Vec<(String, String)>, anyhow::Error> = router.ask_dyn(ListRoutesRequest).await;
215 println!("Routes: {:?}", routes);
216
217 println!("\n4. Testing dynamic string commands:");
218
219 let help: Result<String, anyhow::Error> = router.ask_dyn("help".to_string()).await;
220 println!("Help response: {:?}", help);
221
222 let status: Result<String, anyhow::Error> = router.ask_dyn("status".to_string()).await;
223 println!("Status response: {:?}", status);
224
225 let echo: Result<String, anyhow::Error> = router.ask_dyn("echo Hello dynamic world!".to_string()).await;
226 println!("Echo response: {:?}", echo);
227
228 let unknown: Result<String, anyhow::Error> = router.ask_dyn("unknown command".to_string()).await;
229 println!("Unknown command response: {:?}", unknown);
230
231 println!("\n5. Final stats:");
232 let stats: Result<(u32, usize), anyhow::Error> = router.ask_dyn(StatsRequest).await;
233 println!("Final stats: {:?}", stats);
234
235 Ok(())
236}