use hyper::Method; #[derive (Debug, PartialEq)] pub enum Route <'a> { ClientAuditLog, ClientRelayIsUp, ClientServerGet { listen_code: &'a str, path: &'a str, }, ClientServerList, ClientUnregisteredServers, Debug, DebugEndlessSink, DebugEndlessSource (Option ), DebugGenKey, DebugMysteriousError, RegisterServer, Root, Scraper { rest: &'a str, }, ServerHttpListen { listen_code: &'a str }, ServerHttpResponse { request_code: &'a str, }, } #[derive (Debug, PartialEq)] pub enum Error { BadUriFormat, MethodNotAllowed, NotFound, } pub fn route_url <'a> (method: &Method, path: &'a str) -> Result , Error> { if let Some (listen_code) = path.strip_prefix ("/7ZSFUKGV/http_listen/") { assert_method (method, Method::GET)?; Ok (Route::ServerHttpListen { listen_code }) } else if let Some (request_code) = path.strip_prefix ("/7ZSFUKGV/http_response/") { assert_method (method, Method::POST)?; Ok (Route::ServerHttpResponse { request_code }) } else if path == "/frontend/register" { assert_method (method, Method::POST)?; Ok (Route::RegisterServer) } else if let Some (rest) = path.strip_prefix ("/frontend/servers/") { // DRY T4H76LB3 if rest.is_empty () { assert_method (method, Method::GET)?; Ok (Route::ClientServerList) } else if let Some (idx) = rest.find ('/') { let listen_code = &rest [0..idx]; Ok (Route::ClientServerGet { listen_code, path: &rest [idx..], }) } else { assert_method (method, Method::GET)?; Err (Error::BadUriFormat) } } else if path == "/frontend/unregistered_servers" { assert_method (method, Method::GET)?; Ok (Route::ClientUnregisteredServers) } else if path == "/frontend/audit_log" { assert_method (method, Method::GET)?; Ok (Route::ClientAuditLog) } else if let Some (rest) = path.strip_prefix ("/frontend/debug/") { if rest.is_empty () { assert_method (method, Method::GET)?; Ok (Route::Debug) } else if rest == "endless_source" { assert_method (method, Method::GET)?; Ok (Route::DebugEndlessSource (None)) } else if rest == "endless_source_throttled" { assert_method (method, Method::GET)?; Ok (Route::DebugEndlessSource (Some (1024 / 64))) } else if rest == "endless_sink" { assert_method (method, Method::POST)?; Ok (Route::DebugEndlessSink) } else if rest == "gen_key" { assert_method (method, Method::GET)?; Ok (Route::DebugGenKey) } else { Err (Error::NotFound) } } else if path == "/" { assert_method (method, Method::GET)?; Ok (Route::Root) } else if path == "/frontend/relay_up_check" { assert_method (method, Method::GET)?; Ok (Route::ClientRelayIsUp) } else if path == "/frontend/test_mysterious_error" { assert_method (method, Method::GET)?; Ok (Route::DebugMysteriousError) } else if let Some (rest) = path.strip_prefix ("/scraper/") { assert_method (method, Method::GET)?; Ok (Route::Scraper { rest }) } else { tracing::error! ("URL routing failed for `{}`", path); Err (Error::NotFound) } } fn assert_method > (method: M, expected: Method) -> Result <(), Error> { if method == expected { Ok (()) } else { Err (Error::MethodNotAllowed) } } #[cfg (test)] mod tests { use super::*; #[test] fn routing () { for (input, expected) in vec! [ ("/", Ok (Route::Root)), ].into_iter () { let actual = route_url (&Method::GET, input); assert_eq! (actual, expected); } for (input, expected) in vec! [ ("/", Err (Error::MethodNotAllowed)), ].into_iter () { let actual = route_url (&Method::POST, input); assert_eq! (actual, expected); } } }