pub struct Context {
pub method: Method,
pub path: String,
pub params: HashMap<String, String>,
pub headers: HashMap<String, String>,
pub body: Vec<u8>,
pub db_pool: Arc<ConnectionPool>,
/* private fields */
}Expand description
请求上下文
Fields§
§method: Method§path: String§params: HashMap<String, String>§headers: HashMap<String, String>§body: Vec<u8>§db_pool: Arc<ConnectionPool>数据库连接池
Implementations§
Source§impl Context
impl Context
pub fn new( method: Method, path: String, params: HashMap<String, String>, headers: HashMap<String, String>, body: Vec<u8>, ) -> Self
pub fn with_pool(self, pool: SharedPool) -> Self
pub fn with_db_pool(self, db_pool: Arc<ConnectionPool>) -> Self
Sourcepub fn get_db_pool(&self) -> Arc<ConnectionPool> ⓘ
pub fn get_db_pool(&self) -> Arc<ConnectionPool> ⓘ
Examples found in repository?
examples/web_app.rs (line 36)
35 fn create(&self, ctx: &Context) -> Result<(), Error> {
36 let db_pool = ctx.get_db_pool();
37 let mut conn = db_pool.get()?;
38 let mut qb = QueryBuilder::<ResUser>::new(conn.driver_mut());
39 qb.create_table()?;
40 qb.insert(self)?;
41 Ok(())
42 }
43}
44
45fn hello_handler(ctx: Context) -> Response {
46 let default_name = "World".to_string();
47 let name = ctx.param("name").unwrap_or(&default_name);
48 Response::html(format!("<h1>Hello, {}!</h1>", name))
49}
50
51fn headers_handler(ctx: Context) -> Response {
52 let mut body = String::from("<h1>Request Headers</h1><ul>");
53 for (k, v) in &ctx.headers {
54 body.push_str(&format!("<li><b>{}</b>: {}</li>", k, v));
55 }
56 body.push_str("</ul>");
57 Response::html(body)
58}
59
60fn form_handler(ctx: Context) -> Response {
61 let values = ctx.form_values();
62 let mut body = String::from("<h1>Form Data</h1><ul>");
63 for (k, v) in &values {
64 body.push_str(&format!("<li><b>{}</b>: {}</li>", k, v));
65 }
66 body.push_str("</ul>");
67 Response::html(body)
68}
69
70fn form_page_handler(_ctx: Context) -> Response {
71 let html = r#"<!DOCTYPE html>
72<html>
73<head><meta charset="utf-8"><title>Form Test</title></head>
74<body>
75<h1>Form Test</h1>
76<h2>URL-Encoded Form</h2>
77<form action="/form" method="post">
78 <input name="username" placeholder="Username"><br>
79 <input name="email" placeholder="Email"><br>
80 <input name="age" placeholder="Age"><br>
81 <button type="submit">Submit URL-Encoded</button>
82</form>
83<h2>Multipart Form,create user</h2>
84<form action="/api/user" method="post" enctype="multipart/form-data">
85 <input name="name" placeholder="Name"><br>
86 <input name="email" placeholder="Email"><br>
87 <input name="age" placeholder="Age"><br>
88 <button type="submit">Submit Multipart</button>
89</form>
90</body>
91</html>"#;
92 Response::html(html)
93}
94
95fn ws_handler(mut ws: WebSocket) {
96 let welcome = r#"{"type":"welcome","message":"Connected to WebSocket server"}"#;
97 ws.send_text(welcome);
98
99 loop {
100 match ws.read_message() {
101 Some(Message::Text(text)) => {
102 let reply = format!(r#"{{"type":"echo","data":"{}"}}"#, text);
103 ws.send_text(&reply);
104 }
105 Some(Message::Binary(data)) => {
106 ws.send_binary(&data);
107 }
108 Some(Message::Ping(data)) => {
109 ws.send_pong(&data);
110 }
111 Some(Message::Close(_)) => {
112 break;
113 }
114 _ => break,
115 }
116 }
117}
118
119fn pool_stats_handler(ctx: Context) -> Response {
120 match ctx.pool_stats() {
121 Some(stats) => {
122 let json = json!({
123 "active_connections": stats.active_connections,
124 "total_connections": stats.total_connections,
125 "rejected_connections": stats.rejected_connections,
126 "max_connections": if stats.max_connections == 0 { "unlimited".to_string() } else { stats.max_connections.to_string() },
127 });
128 Response::json(json.to_string())
129 }
130 None => Response::json(r#"{"error":"pool not available"}"#),
131 }
132}
133
134fn create_user_handler(ctx: Context) -> Result<Response, Error> {
135 let values = ctx.form_values();
136 let user = ResUser::new(
137 values["name"].to_string(),
138 values["email"].to_string(),
139 values["age"].parse::<i32>().unwrap(),
140 );
141 user.create(&ctx)?;
142 Ok(Response::json(user))
143}
144
145fn get_users_handler(ctx: Context) -> Result<Response, Error> {
146 // ctx.get_db_pool()?;
147 let mut conn = ctx.get_db_pool().get()?;
148 let mut db = QueryBuilder::<ResUser>::new(conn.driver_mut());
149 let users = db.find_all()?;
150 Ok(Response::json(users))
151}pub fn get_db(&self) -> Result<PoolConnection, Error>
Sourcepub fn pool_stats(&self) -> Option<PoolStats>
pub fn pool_stats(&self) -> Option<PoolStats>
Examples found in repository?
examples/web_app.rs (line 120)
119fn pool_stats_handler(ctx: Context) -> Response {
120 match ctx.pool_stats() {
121 Some(stats) => {
122 let json = json!({
123 "active_connections": stats.active_connections,
124 "total_connections": stats.total_connections,
125 "rejected_connections": stats.rejected_connections,
126 "max_connections": if stats.max_connections == 0 { "unlimited".to_string() } else { stats.max_connections.to_string() },
127 });
128 Response::json(json.to_string())
129 }
130 None => Response::json(r#"{"error":"pool not available"}"#),
131 }
132}Sourcepub fn param(&self, key: &str) -> Option<&String>
pub fn param(&self, key: &str) -> Option<&String>
Examples found in repository?
examples/web_app.rs (line 47)
45fn hello_handler(ctx: Context) -> Response {
46 let default_name = "World".to_string();
47 let name = ctx.param("name").unwrap_or(&default_name);
48 Response::html(format!("<h1>Hello, {}!</h1>", name))
49}
50
51fn headers_handler(ctx: Context) -> Response {
52 let mut body = String::from("<h1>Request Headers</h1><ul>");
53 for (k, v) in &ctx.headers {
54 body.push_str(&format!("<li><b>{}</b>: {}</li>", k, v));
55 }
56 body.push_str("</ul>");
57 Response::html(body)
58}
59
60fn form_handler(ctx: Context) -> Response {
61 let values = ctx.form_values();
62 let mut body = String::from("<h1>Form Data</h1><ul>");
63 for (k, v) in &values {
64 body.push_str(&format!("<li><b>{}</b>: {}</li>", k, v));
65 }
66 body.push_str("</ul>");
67 Response::html(body)
68}
69
70fn form_page_handler(_ctx: Context) -> Response {
71 let html = r#"<!DOCTYPE html>
72<html>
73<head><meta charset="utf-8"><title>Form Test</title></head>
74<body>
75<h1>Form Test</h1>
76<h2>URL-Encoded Form</h2>
77<form action="/form" method="post">
78 <input name="username" placeholder="Username"><br>
79 <input name="email" placeholder="Email"><br>
80 <input name="age" placeholder="Age"><br>
81 <button type="submit">Submit URL-Encoded</button>
82</form>
83<h2>Multipart Form,create user</h2>
84<form action="/api/user" method="post" enctype="multipart/form-data">
85 <input name="name" placeholder="Name"><br>
86 <input name="email" placeholder="Email"><br>
87 <input name="age" placeholder="Age"><br>
88 <button type="submit">Submit Multipart</button>
89</form>
90</body>
91</html>"#;
92 Response::html(html)
93}
94
95fn ws_handler(mut ws: WebSocket) {
96 let welcome = r#"{"type":"welcome","message":"Connected to WebSocket server"}"#;
97 ws.send_text(welcome);
98
99 loop {
100 match ws.read_message() {
101 Some(Message::Text(text)) => {
102 let reply = format!(r#"{{"type":"echo","data":"{}"}}"#, text);
103 ws.send_text(&reply);
104 }
105 Some(Message::Binary(data)) => {
106 ws.send_binary(&data);
107 }
108 Some(Message::Ping(data)) => {
109 ws.send_pong(&data);
110 }
111 Some(Message::Close(_)) => {
112 break;
113 }
114 _ => break,
115 }
116 }
117}
118
119fn pool_stats_handler(ctx: Context) -> Response {
120 match ctx.pool_stats() {
121 Some(stats) => {
122 let json = json!({
123 "active_connections": stats.active_connections,
124 "total_connections": stats.total_connections,
125 "rejected_connections": stats.rejected_connections,
126 "max_connections": if stats.max_connections == 0 { "unlimited".to_string() } else { stats.max_connections.to_string() },
127 });
128 Response::json(json.to_string())
129 }
130 None => Response::json(r#"{"error":"pool not available"}"#),
131 }
132}
133
134fn create_user_handler(ctx: Context) -> Result<Response, Error> {
135 let values = ctx.form_values();
136 let user = ResUser::new(
137 values["name"].to_string(),
138 values["email"].to_string(),
139 values["age"].parse::<i32>().unwrap(),
140 );
141 user.create(&ctx)?;
142 Ok(Response::json(user))
143}
144
145fn get_users_handler(ctx: Context) -> Result<Response, Error> {
146 // ctx.get_db_pool()?;
147 let mut conn = ctx.get_db_pool().get()?;
148 let mut db = QueryBuilder::<ResUser>::new(conn.driver_mut());
149 let users = db.find_all()?;
150 Ok(Response::json(users))
151}
152
153fn slow_handler(_ctx: Context) -> Response {
154 use std::time::Duration;
155 std::thread::sleep(Duration::from_secs(20));
156 Response::html("<h1>Slow response completed!</h1>".to_string())
157}
158
159// ============== 静态路由处理器 ==============
160fn handle_home(_ctx: Context) -> Response {
161 let body = r#"<html>
162 <head>
163 <title>GRweb Web Server</title>
164 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
165 </head>
166 <body>
167 <h1>🚀 Welcome to GRweb Web Server</h1>
168 <p>High-performance web server powered by GRweb!</p>
169
170 <h2>Available Routes:</h2>
171 <ul>
172 <li><a href="/">/</a> - Home</li>
173 <li><a href="/hello">/hello</a> - Hello page</li>
174 <li><a href="/json">/json</a> - JSON response</li>
175 <li><a href="/about">/about</a> - About page</li>
176 <li><a href="/status">/status</a> - Server status</li>
177 <li><a href="/form">/form</a> - Form test</li>
178 <li><a href="/headers">/headers</a> - Request headers test</li>
179 <li><a href="/user/123">/user/123</a> - Dynamic user (123)</li>
180 <li><a href="/user/alice">/user/alice</a> - Dynamic user (alice)</li>
181 <li><a href="/post/2024/01/hello-world">/post/2024/01/hello-world</a> - Dynamic post</li>
182 </ul>
183
184 <h2>Performance:</h2>
185 <ul>
186 <li>QPS: ~95,000</li>
187 <li>Latency: ~0.59ms</li>
188 <li>Memory: ~3MB</li>
189 </ul>
190 </body>
191 </html>"#;
192 Response::html(body)
193}
194
195fn handle_hello(_ctx: Context) -> Response {
196 let body = r#"<html>
197 <head>
198 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
199 </head>
200 <body>
201 <h1>👋 Hello from GRweb!</h1>
202 <p>Served by goroutine with high performance!</p>
203 <p>This request was handled by a lightweight M:N scheduler.</p>
204 <p><a href="/">← Back to home</a></p>
205 </body>
206 </html>"#;
207 Response::html(body)
208}
209
210fn handle_json(_ctx: Context) -> Response {
211 let body = r#"{
212 "status": "ok",
213 "message": "Hello from GRweb",
214 "framework": "GRweb",
215 "version": "0.2.0",
216 "performance": {
217 "qps": 95000,
218 "latency_ms": 0.59,
219 "max_latency_ms": 4.82
220 },
221 "features": [
222 "goroutine",
223 "channel",
224 "M:N scheduling",
225 "work stealing",
226 "non-blocking I/O",
227 "dynamic routing"
228 ],
229 "database_connected": true
230 }"#;
231 Response::json(body)
232}
233
234fn handle_about(_ctx: Context) -> Response {
235 let body = r#"<html>
236 <head>
237 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
238 </head>
239 <body>
240 <h1>About GRweb</h1>
241 <p>GRweb is a lightweight, high-performance runtime for Rust that provides Go-like concurrency.</p>
242
243 <h2>Core Features:</h2>
244 <ul>
245 <li><strong>M:N Goroutine Scheduling</strong> - Efficient user-space threads</li>
246 <li><strong>Work Stealing</strong> - Automatic load balancing</li>
247 <li><strong>Channel-based Communication</strong> - Safe concurrent message passing</li>
248 <li><strong>Non-blocking I/O</strong> - High throughput networking</li>
249 <li><strong>Low Memory Footprint</strong> - ~3MB base memory</li>
250 <li><strong>High Throughput</strong> - 95,000 req/s</li>
251 <li><strong>Low Latency</strong> - ~0.59ms average</li>
252 <li><strong>Database Integration</strong> - Integrated connection pooling</li>
253 </ul>
254
255 <h2>Architecture:</h2>
256 <ul>
257 <li>G (Goroutine) - User-space task</li>
258 <li>P (Processor) - Logical CPU core</li>
259 <li>M (Machine) - OS thread</li>
260 <li>Scheduler - Work stealing across Ps</li>
261 </ul>
262
263 <p><a href="/">← Back to home</a></p>
264 </body>
265 </html>"#;
266 Response::html(body)
267}
268
269fn handle_status(_ctx: Context) -> Response {
270 let mut body = String::new();
271 body.push_str(
272 r#"<html>
273 <head>
274 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
275 <title>Server Status</title>
276 </head>
277 <body>
278 <h1>📊 Server Status</h1>
279 <table border="1" cellpadding="10">
280 <tr><th>Metric</th><th>Value</th></tr>
281 <tr><td>Framework</td><td>GRweb v0.2.0</td></tr>
282 <tr><td>Status</td><td style="color:green">✓ Running</td></tr>
283 <tr><td>QPS</td><td>~95,000</td></tr>
284 <tr><td>Average Latency</td><td>~0.59ms</td></tr>
285 <tr><td>Max Latency</td><td>~4.82ms</td></tr>
286 <tr><td>Memory Usage</td><td>~3MB</td></tr>
287 <tr><td>Concurrency Model</td><td>M:N Goroutines</td></tr>
288 <tr><td>Scheduler</td><td>Work Stealing</td></tr>
289 <tr><td>Database Pool</td><td>Integrated</td></tr>
290 </table>
291 <p><a href="/">← Back to home</a></p>
292 </body>
293 </html>"#,
294 );
295 Response::html(body)
296}
297
298fn handle_user(ctx: Context) -> Response {
299 let user_id = ctx.param("id").map(|s| s.as_str()).unwrap_or("unknown");
300 // 如果没有数据库连接池,则使用原始逻辑
301 let mut body = String::new();
302 body.push_str(
303 r#"<html>
304 <head>
305 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
306 </head>
307 <body>
308 <h1>👤 User Profile</h1>
309 <p><strong>User ID:</strong> "#,
310 );
311 body.push_str(user_id);
312 body.push_str(
313 r#"</p>
314 <p><strong>Page:</strong> Dynamic route handling</p>
315 <p>This page demonstrates dynamic routing with path parameters.</p>
316 <p><a href="/">← Back to home</a></p>
317 </body>
318 </html>"#,
319 );
320
321 Response::html(body)
322}
323
324fn handle_post(ctx: Context) -> Response {
325 let year = ctx.param("year").map(|s| s.as_str()).unwrap_or("unknown");
326 let month = ctx.param("month").map(|s| s.as_str()).unwrap_or("unknown");
327 let slug = ctx.param("slug").map(|s| s.as_str()).unwrap_or("unknown");
328
329 let mut body = String::new();
330 body.push_str(
331 r#"<html>
332 <head>
333 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
334 </head>
335 <body>
336 <h1>📝 Blog Post</h1>
337 <p><strong>Date:</strong> "#,
338 );
339 body.push_str(year);
340 body.push_str("-");
341 body.push_str(month);
342 body.push_str(
343 r#"</p>
344 <p><strong>Slug:</strong> "#,
345 );
346 body.push_str(slug);
347 body.push_str(
348 r#"</p>
349 <p>This is a dynamically routed blog post page.</p>
350 <p>The routing pattern <code>/post/:year/:month/:slug</code> matches this URL.</p>
351 <p><a href="/">← Back to home</a></p>
352 </body>
353 </html>"#,
354 );
355
356 Response::html(body)
357}pub fn header(&self, key: &str) -> Option<&String>
pub fn body_string(&self) -> String
pub fn body_json<T: DeserializeOwned>(&self) -> Result<T, Error>
pub fn form_value(&self, key: &str) -> Option<String>
Sourcepub fn form_values(&self) -> HashMap<String, String>
pub fn form_values(&self) -> HashMap<String, String>
Examples found in repository?
examples/web_app.rs (line 61)
60fn form_handler(ctx: Context) -> Response {
61 let values = ctx.form_values();
62 let mut body = String::from("<h1>Form Data</h1><ul>");
63 for (k, v) in &values {
64 body.push_str(&format!("<li><b>{}</b>: {}</li>", k, v));
65 }
66 body.push_str("</ul>");
67 Response::html(body)
68}
69
70fn form_page_handler(_ctx: Context) -> Response {
71 let html = r#"<!DOCTYPE html>
72<html>
73<head><meta charset="utf-8"><title>Form Test</title></head>
74<body>
75<h1>Form Test</h1>
76<h2>URL-Encoded Form</h2>
77<form action="/form" method="post">
78 <input name="username" placeholder="Username"><br>
79 <input name="email" placeholder="Email"><br>
80 <input name="age" placeholder="Age"><br>
81 <button type="submit">Submit URL-Encoded</button>
82</form>
83<h2>Multipart Form,create user</h2>
84<form action="/api/user" method="post" enctype="multipart/form-data">
85 <input name="name" placeholder="Name"><br>
86 <input name="email" placeholder="Email"><br>
87 <input name="age" placeholder="Age"><br>
88 <button type="submit">Submit Multipart</button>
89</form>
90</body>
91</html>"#;
92 Response::html(html)
93}
94
95fn ws_handler(mut ws: WebSocket) {
96 let welcome = r#"{"type":"welcome","message":"Connected to WebSocket server"}"#;
97 ws.send_text(welcome);
98
99 loop {
100 match ws.read_message() {
101 Some(Message::Text(text)) => {
102 let reply = format!(r#"{{"type":"echo","data":"{}"}}"#, text);
103 ws.send_text(&reply);
104 }
105 Some(Message::Binary(data)) => {
106 ws.send_binary(&data);
107 }
108 Some(Message::Ping(data)) => {
109 ws.send_pong(&data);
110 }
111 Some(Message::Close(_)) => {
112 break;
113 }
114 _ => break,
115 }
116 }
117}
118
119fn pool_stats_handler(ctx: Context) -> Response {
120 match ctx.pool_stats() {
121 Some(stats) => {
122 let json = json!({
123 "active_connections": stats.active_connections,
124 "total_connections": stats.total_connections,
125 "rejected_connections": stats.rejected_connections,
126 "max_connections": if stats.max_connections == 0 { "unlimited".to_string() } else { stats.max_connections.to_string() },
127 });
128 Response::json(json.to_string())
129 }
130 None => Response::json(r#"{"error":"pool not available"}"#),
131 }
132}
133
134fn create_user_handler(ctx: Context) -> Result<Response, Error> {
135 let values = ctx.form_values();
136 let user = ResUser::new(
137 values["name"].to_string(),
138 values["email"].to_string(),
139 values["age"].parse::<i32>().unwrap(),
140 );
141 user.create(&ctx)?;
142 Ok(Response::json(user))
143}Trait Implementations§
Auto Trait Implementations§
impl Freeze for Context
impl !RefUnwindSafe for Context
impl Send for Context
impl Sync for Context
impl Unpin for Context
impl UnsafeUnpin for Context
impl !UnwindSafe for Context
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