在 handler 之间共享状态,主要靠3种方式:
State
extractorrequest
extension- closure
State #
state
不可变的话没有意义,所以需要是 mutable shared state。下面是个例子。
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use axum::extract::{Path, State};
use axum::response::Json;
use axum::Router;
use axum::routing::{delete, get, patch, post};
use log::debug;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
struct MyState {
count: i64,
updated_at: i64, // timestamp
}
fn now() -> i64 { chrono::Utc::now().timestamp() }
impl MyState {
fn new() -> Self { MyState { count: -1, updated_at: now() } }
}
impl Default for MyState {
fn default() -> Self { Self::new() }
}
// 关注这里
type SharedState = Arc<RwLock<HashMap<String, MyState>>>;
async fn handler(state: State<SharedState>, Path(key): Path<String>) -> Json<i64> {
debug!("key: {}", key);
// TODO: is it atomic operation here?
// TODO: try get_mut
let read_lock = state.read().unwrap();
let loc = read_lock.get(&key).cloned().unwrap_or_default();
drop(read_lock);
let mut write_lock = state.write().unwrap();
write_lock.insert(key.to_string(), MyState { count: loc.count + 1, updated_at: now() });
Json(loc.count)
}
async fn reset_handler(state: State<SharedState>, Path(key): Path<String>) -> Json<u32> {
let mut write_lock = state.write().unwrap();
write_lock.insert(key.to_string(), MyState { count: 0, updated_at: now() });
Json(0)
}
async fn delete_handler(state: State<SharedState>, Path(key): Path<String>) -> Json<Option<MyState>> {
let mut write_lock = state.write().unwrap();
Json(write_lock.remove(&key))
}
async fn all_key_values(state: State<SharedState>) -> Json<HashMap<String, MyState>> {
Json(state.read().unwrap().clone())
}
#[tokio::main]
async fn main() {
std::env::set_var("RUST_LOG", "DEBUG");
env_logger::init();
let shared_state = Arc::new(RwLock::new(HashMap::new()));
let app = Router::new()
.route("/kv", get(all_key_values))
.route("/kv/:key", post(handler))
.route("/kv/:key/reset", patch(reset_handler))
.route("/kv/:key", delete(delete_handler))
.with_state(shared_state);
let addr = ([127, 0, 0, 1], 3003).into();
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
request extension #
TODO
closure #
我认为是一种 hack 方式,只是给一个例子。