Skip to content

Instantly share code, notes, and snippets.

@snoyberg

snoyberg/main.rs Secret

Created August 26, 2021 02:28
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save snoyberg/c6c54ed38ec8fac966e362eb212ab421 to your computer and use it in GitHub Desktop.
Save snoyberg/c6c54ed38ec8fac966e362eb212ab421 to your computer and use it in GitHub Desktop.
Learning Tower
mod http {
use std::collections::HashMap;
pub struct Request {
pub path_and_query: String,
pub headers: HashMap<String, String>,
pub body: Vec<u8>,
}
#[derive(Debug)]
pub struct Response {
pub status: u32,
pub headers: HashMap<String, String>,
pub body: Vec<u8>,
}
}
mod fakeserver {
use std::collections::HashMap;
use tower::{Service, ServiceExt};
pub async fn run<App>(mut app: App)
where
App: Service<crate::http::Request, Response = crate::http::Response>,
App::Error: std::fmt::Debug,
App::Future: Send + 'static,
{
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let req = crate::http::Request {
path_and_query: "/fake/path?page=1".to_owned(),
headers: HashMap::new(),
body: Vec::new(),
};
let app = match app.ready().await {
Err(e) => {
eprintln!("Service not able to accept requests: {:?}", e);
continue;
}
Ok(app) => app,
};
let future = app.call(req);
tokio::spawn(async move {
match future.await {
Ok(res) => println!("Successful response: {:?}", res),
Err(e) => eprintln!("Error occurred: {:?}", e),
}
});
}
}
}
mod app {
use std::{
future::Future,
pin::Pin,
sync::{atomic::AtomicUsize, Arc},
task::Poll,
};
pub struct DemoApp {
counter: Arc<AtomicUsize>,
}
impl Default for DemoApp {
fn default() -> Self {
DemoApp {
counter: Arc::new(AtomicUsize::new(0)),
}
}
}
impl tower::Service<crate::http::Request> for DemoApp {
type Response = crate::http::Response;
type Error = anyhow::Error;
#[allow(clippy::type_complexity)]
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(
&mut self,
_cx: &mut std::task::Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) // always ready to accept a connection
}
fn call(&mut self, mut req: crate::http::Request) -> Self::Future {
let counter = self.counter.clone();
Box::pin(async move {
println!("Handling a request for {}", req.path_and_query);
let counter = counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
anyhow::ensure!(counter % 4 != 2, "Failing 25% of the time, just for fun");
req.headers
.insert("X-Counter".to_owned(), counter.to_string());
let res = crate::http::Response {
status: 200,
headers: req.headers,
body: req.body,
};
Ok::<_, anyhow::Error>(res)
})
}
}
}
#[tokio::main]
async fn main() {
fakeserver::run(app::DemoApp::default()).await;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment