State

在 handler 之间共享状态,主要靠3种方式:

  • State extractor
  • request 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 方式,只是给一个例子。