Skip to main content

Context

Struct Context 

Source
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

Source

pub fn new( method: Method, path: String, params: HashMap<String, String>, headers: HashMap<String, String>, body: Vec<u8>, ) -> Self

Source

pub fn with_pool(self, pool: SharedPool) -> Self

Source

pub fn with_db_pool(self, db_pool: Arc<ConnectionPool>) -> Self

Source

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}
Source

pub fn get_db(&self) -> Result<PoolConnection, Error>

Source

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}
Source

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}
Source

pub fn header(&self, key: &str) -> Option<&String>

Source

pub fn body_string(&self) -> String

Source

pub fn body_json<T: DeserializeOwned>(&self) -> Result<T, Error>

Source

pub fn form_value(&self, key: &str) -> Option<String>

Source

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§

Source§

impl Clone for Context

Source§

fn clone(&self) -> Context

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.