Created
December 23, 2021 15:27
-
-
Save davidpdrsn/2890612d4e2b9e419b3bf64fce081272 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use axum::{ | |
extract::{Extension, Path}, | |
routing::get, | |
AddExtensionLayer, Router, | |
}; | |
use hyper::service::make_service_fn; | |
use std::{ | |
convert::Infallible, | |
sync::{Arc, Mutex}, | |
}; | |
use tower::Layer; | |
#[tokio::main] | |
async fn main() { | |
let app = Router::new().route("/add-route/:path", get(add_route)); | |
let shared_app = Arc::new(Mutex::new(app.clone())); | |
let make_service = make_service_fn(|_| { | |
let app = shared_app.clone().lock().unwrap().clone(); | |
let app = AddExtensionLayer::new(shared_app.clone()).layer(app); | |
async move { Ok::<_, Infallible>(app) } | |
}); | |
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) | |
.serve(make_service) | |
.await | |
.unwrap(); | |
} | |
async fn add_route( | |
Extension(shared_app): Extension<Arc<Mutex<Router>>>, | |
Path(path): Path<String>, | |
) -> String { | |
let shared_app = &mut *shared_app.lock().unwrap(); | |
{ | |
let path = path.clone(); | |
*shared_app = shared_app.clone().route( | |
&format!("/{}", path), | |
get(|| async move { format!("Dynamic route `GET /{}` called", path.clone()) }), | |
); | |
} | |
format!("Dynamic route `GET /{}` added", path) | |
} |
I think because Router isn’t Sync thus Arc<RwLock> isn’t Send. This leads to a !Send future which is required.
Yes,Router does not implement sync, so switching to RwLock will not compile
fn assert(_: impl Send){}
let app = Router::new().route("/", get(add_route));
assert(app.clone()); // ok
let tem = Arc::new(RwLock::new(app));
assert(tem); // error: the trait `std::marker::Sync` is not implemented for `(dyn axum::boxed::ErasedIntoRoute<_, _, std::convert::Infallible> + 'static)`
Finally, I implemented this with a shared pointer
#[tokio::main]
async fn main() {
// run it
let listener = TcpListener::bind("127.0.0.1:3000").unwrap();
println!("listening on {}", listener.local_addr().unwrap());
let router = Box::new(Router::new().route("/add_route", get(add_route)));
let arc_router_ptr = Arc::new(AtomicPtr::new(Box::into_raw(router)));
axum::Server::from_tcp(listener)
.unwrap()
.serve(make_service_fn(|_: &AddrStream| {
let router = unsafe { arc_router_ptr.load(Ordering::SeqCst).as_ref() }.unwrap().clone();
let app = AddExtensionLayer::new(arc_router_ptr.clone()).layer(router);
async move { Ok::<_, Infallible>(app) }
}))
.await
.unwrap();
}
async fn add_route(arc_router: Extension<Arc<AtomicPtr<Router>>>) {
let old = unsafe { Box::from_raw(arc_router.load(Ordering::SeqCst)) };
let new = old.merge(Router::new().route("/test", get(test)));
arc_router.store(Box::into_raw(Box::new(new)), Ordering::SeqCst);
}
async fn test() -> String {
"new Dynamic route".to_string()
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why does Mutex not compile after replacing it with Rwlock?