├── .gitignore ├── Makefile ├── src ├── lib.rs ├── handler.rs ├── route.rs ├── router.rs └── main.rs ├── Cargo.toml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | cargo watch -x run -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod router; 2 | pub mod route; 3 | pub mod handler; 4 | 5 | pub use router::Router; 6 | pub use route::Route; 7 | pub use handler::DebuggableHandler; 8 | pub use handler::Handler; -------------------------------------------------------------------------------- /src/handler.rs: -------------------------------------------------------------------------------- 1 | use hyper::{Request}; 2 | 3 | pub type Handler = Box) + Send + Sync>; 4 | 5 | pub struct DebuggableHandler; 6 | 7 | impl std::fmt::Debug for DebuggableHandler { 8 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 9 | write!(f, "") 10 | } 11 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zeke" 3 | version = "0.1.6" 4 | edition = "2021" 5 | authors = ["Phillip England "] 6 | description = "a http library for rust built on top of tokio" 7 | license = "MIT" 8 | 9 | [dependencies] 10 | hyper = { version = "1", features = ["full"] } 11 | tokio = { version = "1", features = ["full"] } 12 | http-body-util = "0.1" 13 | hyper-util = { version = "0.1", features = ["full"] } 14 | -------------------------------------------------------------------------------- /src/route.rs: -------------------------------------------------------------------------------- 1 | use crate::handler::DebuggableHandler; 2 | use crate::handler::Handler; 3 | 4 | pub struct Route<'a> { 5 | pub path: &'a str, 6 | pub method: &'a str, 7 | pub handler: Handler, 8 | } 9 | 10 | impl<'a> std::fmt::Debug for Route<'a> { 11 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 12 | f.debug_struct("Route") 13 | .field("path", &self.path) 14 | .field("method", &self.method) 15 | .field("handler", &DebuggableHandler) 16 | .finish() 17 | } 18 | } -------------------------------------------------------------------------------- /src/router.rs: -------------------------------------------------------------------------------- 1 | use crate::route::Route; 2 | use crate::handler::Handler; 3 | 4 | use hyper::Request; 5 | 6 | 7 | #[derive(Debug)] 8 | pub struct Router<'a> { 9 | routes: std::collections::HashMap>, 10 | } 11 | 12 | impl<'a> Router<'a> { 13 | pub fn new() -> Self { 14 | Self { 15 | routes: std::collections::HashMap::new(), 16 | } 17 | } 18 | 19 | pub fn add(&mut self, method: &'a str, path: &'a str, handler: F) 20 | where 21 | F: Fn(Request) + 'a + 'static + Send + Sync, 22 | { 23 | let boxed_handler: Handler = Box::new(handler); 24 | let route = Route { 25 | path, 26 | method, 27 | handler: boxed_handler, 28 | }; 29 | self.routes.insert(path.to_string(), route); 30 | } 31 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use http_body_util::Full; 4 | use http_body_util::{combinators::BoxBody, BodyExt}; 5 | use hyper::body::Bytes; 6 | use hyper::header::HeaderValue; 7 | use hyper::server::conn::http1; 8 | use hyper::service::service_fn; 9 | use hyper::{Method, StatusCode}; 10 | use hyper::{Request, Response}; 11 | use hyper_util::rt::TokioIo; 12 | use tokio::net::TcpListener; 13 | use zeke::Router; 14 | 15 | use std::sync::Arc; 16 | 17 | 18 | 19 | #[tokio::main] 20 | async fn main() -> Result<(), Box> { 21 | // config 22 | let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); 23 | let listener = TcpListener::bind(addr).await?; 24 | 25 | // routes 26 | let mut router = Router::new(); 27 | router.add("GET", "/", |req: Request| {}); 28 | 29 | let shared_router = Arc::new(router); 30 | 31 | // println!("{:?}", shared_router); 32 | 33 | loop { 34 | let (stream, _) = listener.accept().await?; 35 | let io = TokioIo::new(stream); 36 | let shared_router = Arc::clone(&shared_router); 37 | tokio::task::spawn(async move { 38 | if let Err(err) = http1::Builder::new() 39 | .serve_connection(io, service_fn(|req: Request| { 40 | println!("{:?}", shared_router); 41 | catch_all(req) 42 | })) 43 | .await 44 | { 45 | eprintln!("Error serving connection: {:?}", err); 46 | } 47 | }); 48 | } 49 | } 50 | 51 | // function to catch all incoming requests 52 | async fn catch_all( 53 | req: Request, 54 | ) -> Result>, hyper::Error> { 55 | match req.uri().path() { 56 | "/" => match req.method() { 57 | &Method::GET => { 58 | let mut res = Response::new(box_response("

Hello, World!

")); 59 | res.headers_mut() 60 | .insert("Content-Type", HeaderValue::from_static("text/html")); 61 | return Ok(res); 62 | } 63 | _ => { 64 | let mut invalid_method = Response::new(box_response("invalid method")); 65 | *invalid_method.status_mut() = StatusCode::METHOD_NOT_ALLOWED; 66 | return Ok(invalid_method); 67 | } 68 | }, 69 | _ => { 70 | let mut not_found = Response::new(box_response("

404 not found

")); 71 | *not_found.status_mut() = StatusCode::NOT_FOUND; 72 | not_found 73 | .headers_mut() 74 | .insert("Content-Type", HeaderValue::from_static("text/html")); 75 | return Ok(not_found); 76 | } 77 | } 78 | } 79 | 80 | // utility function to box up our response body 81 | fn box_response>(chunk: T) -> BoxBody { 82 | Full::new(chunk.into()) 83 | .map_err(|never| match never {}) 84 | .boxed() 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zeke 2 | 3 | A set of simple http primitives used to build web services, written in Rust. 4 | 5 | ## Quickstart 6 | 7 | ### Installation 8 | 9 | In your `cargo.toml`: 10 | 11 | ```toml 12 | [dependencies] 13 | zeke = '0.1.3' 14 | ``` 15 | 16 | ### Create a Router 17 | 18 | Routers are used to define and serve our http endpoints. 19 | 20 | ```rs 21 | #[tokio::main] 22 | async fn main() { 23 | let r = Router::new(); 24 | } 25 | ``` 26 | 27 | ### Create a Handler 28 | 29 | Any function that returns a Handler can be associated with an endpoint: 30 | 31 | ```rs 32 | #[tokio::main] 33 | async fn main() { 34 | let r = Router::new(); 35 | r.add(Route::new("GET /", hello_world())); 36 | } 37 | 38 | async fn hello_world() -> Handler { 39 | return Handler::new(|request| { 40 | // enables our handlers to by async 41 | Box::pin(async move { 42 | let response = Response::new() 43 | .status(200); 44 | return (request, response); 45 | }) 46 | }); 47 | } 48 | ``` 49 | 50 | ### Serving 51 | 52 | To serve the application, called `Router.serve`: 53 | 54 | ```rs 55 | #[tokio::main] 56 | async fn main() { 57 | // --snip 58 | let result = r.serve(&host).await; 59 | if result.is_err() { 60 | println!("Error: {:?}", err); 61 | } 62 | } 63 | ``` 64 | 65 | ### Context Keys 66 | 67 | Any data shared between middleware, handlers, and outerware is referred to as `context`. 68 | 69 | Keys are required to encode and decode context. An enum which implements the `Contextable` trait can be used to keep track of these keys: 70 | 71 | ```rs 72 | pub enum AppContext { 73 | Trace, 74 | } 75 | 76 | impl Contextable for AppContext { 77 | fn key(&self) -> &'static str { 78 | match self { 79 | AppContext::Trace => {"TRACE"}, 80 | } 81 | } 82 | } 83 | ``` 84 | 85 | ### HttpTrace 86 | 87 | HttpTrace is a `context` (because it is intended to be shared between middleware, handlers, and outware) that helps us keep track of how long each request cycle takes. 88 | 89 | You must derive `Serialize` and `Deserialize` for any data intended to be used as `context`. 90 | 91 | ```rs 92 | #[derive(Debug, Serialize, Deserialize)] 93 | pub struct HttpTrace { 94 | pub time_stamp: String, 95 | } 96 | 97 | impl HttpTrace { 98 | pub fn get_time_elapsed(&self) -> String { 99 | if let Ok(time_set) = DateTime::parse_from_rfc3339(&self.time_stamp) { 100 | let time_set = time_set.with_timezone(&Utc); 101 | let now = Utc::now(); 102 | let duration = now.signed_duration_since(time_set); 103 | let micros = duration.num_microseconds(); 104 | match micros { 105 | Some(micros) => { 106 | if micros < 1000 { 107 | return format!("{}µ", micros); 108 | } 109 | }, 110 | None => { 111 | 112 | } 113 | } 114 | let millis = duration.num_milliseconds(); 115 | return format!("{}ms", millis); 116 | } else { 117 | return "failed to parse time_stamp".to_string(); 118 | } 119 | } 120 | } 121 | ``` 122 | 123 | ### Middleware 124 | 125 | Any function that returns a `Middleware` can be used as middleware in our application. 126 | 127 | Let's make use of the `HttpTrace` type we created in the previous section. 128 | 129 | The following middleware will initialize `HttpTrace` prior to calling our handler: 130 | 131 | ```rs 132 | pub async fn mw_trace() -> Middleware { 133 | Middleware::new(|mut request: &mut Request| { 134 | let trace = HttpTrace { 135 | time_stamp: chrono::Utc::now().to_rfc3339(), 136 | }; 137 | let trace_encoded = serde_json::to_string(&trace); 138 | if trace_encoded.is_err() { 139 | return Some(Response::new() 140 | .status(500) 141 | .body("failed to encode trace") 142 | ); 143 | } 144 | let trace_encoded = trace_encoded.unwrap(); 145 | request.set_context(AppContext::Trace, trace_encoded); 146 | None 147 | }) 148 | } 149 | ``` 150 | 151 | Let's take a moment to notice a few key things going on here. 152 | 153 | 1. We initalize our trace type and then encode it into json: 154 | 155 | ```rs 156 | let trace = HttpTrace{ 157 | time_stamp: chrono::Utc::now().to_rfc3339(), 158 | }; 159 | let trace_encoded = serde_json::to_string(&trace); 160 | ``` 161 | 162 | 2. We ensure the trace has been encoded correctly: 163 | 164 | ```rs 165 | if trace_encoded.is_err() { 166 | return Some(Response::new() 167 | .status(500) 168 | .body("failed to encode trace") 169 | ); 170 | } 171 | ``` 172 | 173 | 3. Finally (and most importantly) we call set_context on our `Request` type, using our AppContext::Trace key 174 | 175 | ```rs 176 | let trace_encoded = trace_encoded.unwrap(); 177 | request.set_context(AppContext::Trace, trace_encoded); 178 | ``` 179 | 180 | Now the json data for the `HttpTrace` type is associated with the `Request` type and can be used later in the request cycle. 181 | 182 | We can attach our middleware to a `Route` like so: 183 | 184 | ```rs 185 | #[tokio::main] 186 | async fn main() { 187 | let r = Router::new(); 188 | r.add(Route::new("GET /", hello_world()) 189 | .middleware(mw_trace()) 190 | ); 191 | let result = r.serve(&host).await; 192 | if result.is_err() { 193 | println!("Error: {:?}", err); 194 | } 195 | } 196 | ``` 197 | 198 | ### Outerware 199 | 200 | Any function that returns a `Middleware` can be used as outerware in our application. 201 | 202 | Middleware is ran *before* the handler is called. 203 | 204 | Outerware is ran *after* the handler is called. 205 | 206 | We can create an outerware to decode our `HttpTrace` type after the request cycle is over. We can then calculate how much time it took the entire request to process and print it to the terminal. 207 | 208 | ```rs 209 | pub async fn mw_trace_log() -> Middleware { 210 | Middleware::new(|request: &mut Request | { 211 | let trace = request.get_context(AppContext::Trace); 212 | if trace.is_empty() { 213 | return Some(Response::new() 214 | .status(500) 215 | .body("failed to get trace") 216 | ); 217 | } 218 | let trace: HttpTrace = serde_json::from_str(&trace).unwrap(); 219 | let elapsed_time = trace.get_time_elapsed(); 220 | let log_message = format!("[{:?}][{}][{}]", request.method, request.path, elapsed_time); 221 | println!("{}", log_message); 222 | None 223 | }) 224 | } 225 | ``` 226 | 227 | Let's take a closer look at a few things. 228 | 229 | 1. We use our `AppContext::Trace` key to get the encoded `HttpTrace` using `request.get_context`. 230 | 231 | ```rs 232 | let trace = request.get_context(AppContext::Trace); 233 | ``` 234 | 235 | 2. We ensure the trace exists: 236 | 237 | ```rs 238 | if trace == "" { 239 | return Some(Response::new() 240 | .status(500) 241 | .body("failed to get trace") 242 | ); 243 | } 244 | ``` 245 | 246 | 3. We decode the `HttpTrace`: 247 | 248 | ```rs 249 | let trace: HttpTrace = serde_json::from_str(&trace).unwrap(); 250 | ``` 251 | 252 | 4. Finally, we calculate the elapsed time and log results to the terminal: 253 | 254 | ```rs 255 | let elapsed_time = trace.get_time_elapsed(); 256 | let log_message = format!("[{:?}][{}][{}]", request.method, request.path, elapsed_time); 257 | println!("{}", log_message); 258 | ``` 259 | 260 | We can use this outerware in our application like so: 261 | 262 | ```rs 263 | #[tokio::main] 264 | async fn main() { 265 | let r = Router::new(); 266 | r.add(Route::new("GET /", hello_world()) 267 | .middleware(mw_trace().await) 268 | .outerware(mw_trace_log().await) 269 | ); 270 | let result = r.serve(&host).await; 271 | if result.is_err() { 272 | println!("Error: {:?}", err); 273 | } 274 | } 275 | ``` 276 | 277 | ### Middleware Groups 278 | 279 | Any function that returns a `MiddlewareGroup` can be used as a middleware group in our application. 280 | 281 | Middleware groups enable us to group middleware together. Let's see if we can group our `mw_trace` and `mw_trace_log` functions together: 282 | 283 | ```rs 284 | pub fn mw_group_trace() -> MiddlewareGroup { 285 | return MiddlewareGroup::new(vec![mw_trace().await], vec![mw_trace_log().await]); 286 | } 287 | ``` 288 | 289 | Now we can simply use the group: 290 | 291 | ```rs 292 | #[tokio::main] 293 | async fn main() { 294 | let r = Router::new(); 295 | r.add(Route::new("GET /", hello_world()) 296 | .group(mw_group_trace().await) 297 | ); 298 | let result = r.serve(&host).await; 299 | if result.is_err() { 300 | println!("Error: {:?}", err); 301 | } 302 | } 303 | ``` 304 | 305 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.3.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 25 | 26 | [[package]] 27 | name = "backtrace" 28 | version = "0.3.71" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" 31 | dependencies = [ 32 | "addr2line", 33 | "cc", 34 | "cfg-if", 35 | "libc", 36 | "miniz_oxide", 37 | "object", 38 | "rustc-demangle", 39 | ] 40 | 41 | [[package]] 42 | name = "bitflags" 43 | version = "2.5.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 46 | 47 | [[package]] 48 | name = "bytes" 49 | version = "1.6.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 52 | 53 | [[package]] 54 | name = "cc" 55 | version = "1.0.96" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" 58 | 59 | [[package]] 60 | name = "cfg-if" 61 | version = "1.0.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 64 | 65 | [[package]] 66 | name = "equivalent" 67 | version = "1.0.1" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 70 | 71 | [[package]] 72 | name = "fnv" 73 | version = "1.0.7" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 76 | 77 | [[package]] 78 | name = "futures-channel" 79 | version = "0.3.30" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 82 | dependencies = [ 83 | "futures-core", 84 | ] 85 | 86 | [[package]] 87 | name = "futures-core" 88 | version = "0.3.30" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 91 | 92 | [[package]] 93 | name = "futures-sink" 94 | version = "0.3.30" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 97 | 98 | [[package]] 99 | name = "futures-task" 100 | version = "0.3.30" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 103 | 104 | [[package]] 105 | name = "futures-util" 106 | version = "0.3.30" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 109 | dependencies = [ 110 | "futures-core", 111 | "futures-task", 112 | "pin-project-lite", 113 | "pin-utils", 114 | ] 115 | 116 | [[package]] 117 | name = "gimli" 118 | version = "0.28.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 121 | 122 | [[package]] 123 | name = "h2" 124 | version = "0.4.4" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" 127 | dependencies = [ 128 | "bytes", 129 | "fnv", 130 | "futures-core", 131 | "futures-sink", 132 | "futures-util", 133 | "http", 134 | "indexmap", 135 | "slab", 136 | "tokio", 137 | "tokio-util", 138 | "tracing", 139 | ] 140 | 141 | [[package]] 142 | name = "hashbrown" 143 | version = "0.14.5" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 146 | 147 | [[package]] 148 | name = "hermit-abi" 149 | version = "0.3.9" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 152 | 153 | [[package]] 154 | name = "http" 155 | version = "1.1.0" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 158 | dependencies = [ 159 | "bytes", 160 | "fnv", 161 | "itoa", 162 | ] 163 | 164 | [[package]] 165 | name = "http-body" 166 | version = "1.0.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" 169 | dependencies = [ 170 | "bytes", 171 | "http", 172 | ] 173 | 174 | [[package]] 175 | name = "http-body-util" 176 | version = "0.1.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" 179 | dependencies = [ 180 | "bytes", 181 | "futures-core", 182 | "http", 183 | "http-body", 184 | "pin-project-lite", 185 | ] 186 | 187 | [[package]] 188 | name = "httparse" 189 | version = "1.8.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 192 | 193 | [[package]] 194 | name = "httpdate" 195 | version = "1.0.3" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 198 | 199 | [[package]] 200 | name = "hyper" 201 | version = "1.3.1" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" 204 | dependencies = [ 205 | "bytes", 206 | "futures-channel", 207 | "futures-util", 208 | "h2", 209 | "http", 210 | "http-body", 211 | "httparse", 212 | "httpdate", 213 | "itoa", 214 | "pin-project-lite", 215 | "smallvec", 216 | "tokio", 217 | "want", 218 | ] 219 | 220 | [[package]] 221 | name = "hyper-util" 222 | version = "0.1.3" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" 225 | dependencies = [ 226 | "bytes", 227 | "futures-channel", 228 | "futures-util", 229 | "http", 230 | "http-body", 231 | "hyper", 232 | "pin-project-lite", 233 | "socket2", 234 | "tokio", 235 | "tower", 236 | "tower-service", 237 | "tracing", 238 | ] 239 | 240 | [[package]] 241 | name = "indexmap" 242 | version = "2.2.6" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 245 | dependencies = [ 246 | "equivalent", 247 | "hashbrown", 248 | ] 249 | 250 | [[package]] 251 | name = "itoa" 252 | version = "1.0.11" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 255 | 256 | [[package]] 257 | name = "libc" 258 | version = "0.2.154" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" 261 | 262 | [[package]] 263 | name = "lock_api" 264 | version = "0.4.12" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 267 | dependencies = [ 268 | "autocfg", 269 | "scopeguard", 270 | ] 271 | 272 | [[package]] 273 | name = "log" 274 | version = "0.4.21" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 277 | 278 | [[package]] 279 | name = "memchr" 280 | version = "2.7.2" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 283 | 284 | [[package]] 285 | name = "miniz_oxide" 286 | version = "0.7.2" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 289 | dependencies = [ 290 | "adler", 291 | ] 292 | 293 | [[package]] 294 | name = "mio" 295 | version = "0.8.11" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 298 | dependencies = [ 299 | "libc", 300 | "wasi", 301 | "windows-sys 0.48.0", 302 | ] 303 | 304 | [[package]] 305 | name = "num_cpus" 306 | version = "1.16.0" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 309 | dependencies = [ 310 | "hermit-abi", 311 | "libc", 312 | ] 313 | 314 | [[package]] 315 | name = "object" 316 | version = "0.32.2" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 319 | dependencies = [ 320 | "memchr", 321 | ] 322 | 323 | [[package]] 324 | name = "once_cell" 325 | version = "1.19.0" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 328 | 329 | [[package]] 330 | name = "parking_lot" 331 | version = "0.12.2" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" 334 | dependencies = [ 335 | "lock_api", 336 | "parking_lot_core", 337 | ] 338 | 339 | [[package]] 340 | name = "parking_lot_core" 341 | version = "0.9.10" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 344 | dependencies = [ 345 | "cfg-if", 346 | "libc", 347 | "redox_syscall", 348 | "smallvec", 349 | "windows-targets 0.52.5", 350 | ] 351 | 352 | [[package]] 353 | name = "pin-project" 354 | version = "1.1.5" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 357 | dependencies = [ 358 | "pin-project-internal", 359 | ] 360 | 361 | [[package]] 362 | name = "pin-project-internal" 363 | version = "1.1.5" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 366 | dependencies = [ 367 | "proc-macro2", 368 | "quote", 369 | "syn", 370 | ] 371 | 372 | [[package]] 373 | name = "pin-project-lite" 374 | version = "0.2.14" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 377 | 378 | [[package]] 379 | name = "pin-utils" 380 | version = "0.1.0" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 383 | 384 | [[package]] 385 | name = "proc-macro2" 386 | version = "1.0.81" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" 389 | dependencies = [ 390 | "unicode-ident", 391 | ] 392 | 393 | [[package]] 394 | name = "quote" 395 | version = "1.0.36" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 398 | dependencies = [ 399 | "proc-macro2", 400 | ] 401 | 402 | [[package]] 403 | name = "redox_syscall" 404 | version = "0.5.1" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" 407 | dependencies = [ 408 | "bitflags", 409 | ] 410 | 411 | [[package]] 412 | name = "rustc-demangle" 413 | version = "0.1.23" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 416 | 417 | [[package]] 418 | name = "scopeguard" 419 | version = "1.2.0" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 422 | 423 | [[package]] 424 | name = "signal-hook-registry" 425 | version = "1.4.2" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 428 | dependencies = [ 429 | "libc", 430 | ] 431 | 432 | [[package]] 433 | name = "slab" 434 | version = "0.4.9" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 437 | dependencies = [ 438 | "autocfg", 439 | ] 440 | 441 | [[package]] 442 | name = "smallvec" 443 | version = "1.13.2" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 446 | 447 | [[package]] 448 | name = "socket2" 449 | version = "0.5.7" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 452 | dependencies = [ 453 | "libc", 454 | "windows-sys 0.52.0", 455 | ] 456 | 457 | [[package]] 458 | name = "syn" 459 | version = "2.0.60" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" 462 | dependencies = [ 463 | "proc-macro2", 464 | "quote", 465 | "unicode-ident", 466 | ] 467 | 468 | [[package]] 469 | name = "tokio" 470 | version = "1.37.0" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" 473 | dependencies = [ 474 | "backtrace", 475 | "bytes", 476 | "libc", 477 | "mio", 478 | "num_cpus", 479 | "parking_lot", 480 | "pin-project-lite", 481 | "signal-hook-registry", 482 | "socket2", 483 | "tokio-macros", 484 | "windows-sys 0.48.0", 485 | ] 486 | 487 | [[package]] 488 | name = "tokio-macros" 489 | version = "2.2.0" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" 492 | dependencies = [ 493 | "proc-macro2", 494 | "quote", 495 | "syn", 496 | ] 497 | 498 | [[package]] 499 | name = "tokio-util" 500 | version = "0.7.11" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 503 | dependencies = [ 504 | "bytes", 505 | "futures-core", 506 | "futures-sink", 507 | "pin-project-lite", 508 | "tokio", 509 | ] 510 | 511 | [[package]] 512 | name = "tower" 513 | version = "0.4.13" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 516 | dependencies = [ 517 | "futures-core", 518 | "futures-util", 519 | "pin-project", 520 | "pin-project-lite", 521 | "tokio", 522 | "tower-layer", 523 | "tower-service", 524 | "tracing", 525 | ] 526 | 527 | [[package]] 528 | name = "tower-layer" 529 | version = "0.3.2" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 532 | 533 | [[package]] 534 | name = "tower-service" 535 | version = "0.3.2" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 538 | 539 | [[package]] 540 | name = "tracing" 541 | version = "0.1.40" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 544 | dependencies = [ 545 | "log", 546 | "pin-project-lite", 547 | "tracing-core", 548 | ] 549 | 550 | [[package]] 551 | name = "tracing-core" 552 | version = "0.1.32" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 555 | dependencies = [ 556 | "once_cell", 557 | ] 558 | 559 | [[package]] 560 | name = "try-lock" 561 | version = "0.2.5" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 564 | 565 | [[package]] 566 | name = "unicode-ident" 567 | version = "1.0.12" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 570 | 571 | [[package]] 572 | name = "want" 573 | version = "0.3.1" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 576 | dependencies = [ 577 | "try-lock", 578 | ] 579 | 580 | [[package]] 581 | name = "wasi" 582 | version = "0.11.0+wasi-snapshot-preview1" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 585 | 586 | [[package]] 587 | name = "windows-sys" 588 | version = "0.48.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 591 | dependencies = [ 592 | "windows-targets 0.48.5", 593 | ] 594 | 595 | [[package]] 596 | name = "windows-sys" 597 | version = "0.52.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 600 | dependencies = [ 601 | "windows-targets 0.52.5", 602 | ] 603 | 604 | [[package]] 605 | name = "windows-targets" 606 | version = "0.48.5" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 609 | dependencies = [ 610 | "windows_aarch64_gnullvm 0.48.5", 611 | "windows_aarch64_msvc 0.48.5", 612 | "windows_i686_gnu 0.48.5", 613 | "windows_i686_msvc 0.48.5", 614 | "windows_x86_64_gnu 0.48.5", 615 | "windows_x86_64_gnullvm 0.48.5", 616 | "windows_x86_64_msvc 0.48.5", 617 | ] 618 | 619 | [[package]] 620 | name = "windows-targets" 621 | version = "0.52.5" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 624 | dependencies = [ 625 | "windows_aarch64_gnullvm 0.52.5", 626 | "windows_aarch64_msvc 0.52.5", 627 | "windows_i686_gnu 0.52.5", 628 | "windows_i686_gnullvm", 629 | "windows_i686_msvc 0.52.5", 630 | "windows_x86_64_gnu 0.52.5", 631 | "windows_x86_64_gnullvm 0.52.5", 632 | "windows_x86_64_msvc 0.52.5", 633 | ] 634 | 635 | [[package]] 636 | name = "windows_aarch64_gnullvm" 637 | version = "0.48.5" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 640 | 641 | [[package]] 642 | name = "windows_aarch64_gnullvm" 643 | version = "0.52.5" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 646 | 647 | [[package]] 648 | name = "windows_aarch64_msvc" 649 | version = "0.48.5" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 652 | 653 | [[package]] 654 | name = "windows_aarch64_msvc" 655 | version = "0.52.5" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 658 | 659 | [[package]] 660 | name = "windows_i686_gnu" 661 | version = "0.48.5" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 664 | 665 | [[package]] 666 | name = "windows_i686_gnu" 667 | version = "0.52.5" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 670 | 671 | [[package]] 672 | name = "windows_i686_gnullvm" 673 | version = "0.52.5" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 676 | 677 | [[package]] 678 | name = "windows_i686_msvc" 679 | version = "0.48.5" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 682 | 683 | [[package]] 684 | name = "windows_i686_msvc" 685 | version = "0.52.5" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 688 | 689 | [[package]] 690 | name = "windows_x86_64_gnu" 691 | version = "0.48.5" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 694 | 695 | [[package]] 696 | name = "windows_x86_64_gnu" 697 | version = "0.52.5" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 700 | 701 | [[package]] 702 | name = "windows_x86_64_gnullvm" 703 | version = "0.48.5" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 706 | 707 | [[package]] 708 | name = "windows_x86_64_gnullvm" 709 | version = "0.52.5" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 712 | 713 | [[package]] 714 | name = "windows_x86_64_msvc" 715 | version = "0.48.5" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 718 | 719 | [[package]] 720 | name = "windows_x86_64_msvc" 721 | version = "0.52.5" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 724 | 725 | [[package]] 726 | name = "zeke" 727 | version = "0.1.6" 728 | dependencies = [ 729 | "http-body-util", 730 | "hyper", 731 | "hyper-util", 732 | "tokio", 733 | ] 734 | --------------------------------------------------------------------------------