/// "Server logic" is implemented in this function. Given an HTTP Request it then figures out
/// whether the request is valid, and if it is calculates the shortest path possible and returns
/// that value to the user
"Server logic" is implemented in this function. Given an HTTP Request it then figures out
whether the request is valid, and if it is calculates the shortest path possible and returns
that value to the user
" Server logic " is implemented in this function . Given an HTTP Request it then figures out whether the request is valid and if it is calculates the shortest path possible and returns that value to the user
fn respond(req: Request<Bytes>) -> impl Future<Item = Response<String>, Error = io::Error> {
    let mut ret = Response::builder();
    let body = {
        // We always return either an empty body or some JSON and this is the buffer it gets put in
        let mut bod = String::new();
        // If the request is a POST request to the /path endpoint check to see if it's valid
        if *req.method() == Method::POST {
            match req.uri().path() {
                "/path" => {
                    ret.header("Content-Type", "application/json");
                    // Clone the state so we can have access to the paths
                    let state = STATE.clone();
                    let mut paths = state.paths.lock();
                    // This is pretty lose and it would be best to return an RPC response here on
                    // failure, but we can probably consider this okay for the purposes of an
                    // example as Rust sends utf8 strings only
                    let body = str::from_utf8(req.body()).unwrap();
                    // Parse the request and check that it is valid
                    if let Ok(req_json) = rpc::Request::from_json(body) {
                        // json-rpc allows us to set a method. We can use this as a way to send
                        // many requests to one endpoint but have it act differently based off the
                        // type of method asked for
                        let method = &req_json.method == "get_path";
                        // Due to jsons loosely typed nature we need to make sure we get an object
                        // here
                        let params = req_json.params.is_object();
                        if method && params {
                            if let (Some(Value::String(start)), Some(Value::String(end))) =
                                (req_json.params.get("start"), req_json.params.get("end"))
                            {
                                // Get the start and end NodeIds from the input
                                let start: u64 = City::from(start.as_str()).into();
                                let end: u64 = City::from(end.as_str()).into();
                                // Find the shortest path if possible
                                if let Some((time, path)) = astar(
                                    &*paths,
                                    start,
                                    |finish: u64| finish == end,
                                    |e| *e.weight(),
                                    |_| 0,
                                ) {
                                    let mut journey = state.journey.lock();
                                    // Add the length in seconds to the time now as the journey
                                    // length
                                    let time_out = Local::now()
                                        .checked_add_signed(Duration::seconds(time as i64))
                                        .unwrap();
                                    journey.push((time_out, path.clone()));
                                    // Add the weights to the graph
                                    for nodes in path.as_slice().windows(2) {
                                        // We know these are valid paths else A* would not have worked
                                        let mut edge =
                                            paths.edge_weight_mut(nodes[0], nodes[1]).unwrap();
                                        // Increase the crowdedness
                                        *edge = *edge + CAR;
                                    }
                                    // Send back the path as strings for the user
                                    let path = path.into_iter()
                                        .map(|i| {
                                            // TODO Make this abstraction sound and not leaky
                                            // Did this to get around some weird conversion trait
                                            // bounds but this should be handled properly at some point
                                            match i {
                                                0 => "New York City",
                                                1 => "Boston",
                                                2 => "Providence",
                                                3 => "Bar Harbor",
                                                _ => "DNE",
                                            }
                                        })
                                        .collect::<Vec<&str>>();
                                    // Set the body of the response
                                    match rpc::Response::new(
                                        json!({ "distance": time, "path": path }),
                                        req_json.id,
                                    ).to_json()
                                    {
                                        Ok(json) => bod = json,
                                        Err(e) => {
                                            return future::err(io::Error::new(
                                                io::ErrorKind::Other,
                                                e.compat(),
                                            ))
                                        }
                                    }
                                } else {
                                    // Send back an error message if invalid cities are used
                                    match rpc::Response::new(
                                        json!("Invalid start or end city given"),
                                        req_json.id,
                                    ).to_json()
                                    {
                                        Ok(json) => bod = json,
                                        Err(e) => {
                                            return future::err(io::Error::new(
                                                io::ErrorKind::Other,
                                                e.compat(),
                                            ))
                                        }
                                    }
                                }
                            // TODO clean up the `if let else` statements with better abstractions
                            } else {
                                ret.status(StatusCode::BAD_REQUEST);
                            }
                        } else {
                            ret.status(StatusCode::BAD_REQUEST);
                        }
                    } else {
                        ret.status(StatusCode::BAD_REQUEST);
                    }
                }
                _ => {
                    ret.status(StatusCode::NOT_FOUND);
                }
            }
        } else {
            ret.status(StatusCode::NOT_FOUND);
        }
        // Return the body
        bod
    };
    future::ok(ret.body(body).unwrap())
}
fn respond ( req : Request < Bytes > ) -> impl Future < Item = Response < String > , Error = io :: Error > { let mut ret = Response :: builder ( ) ; let body = { // We always return either an empty body or some JSON and this is the buffer it gets put in let mut bod = String :: new ( ) ; // If the request is a POST request to the /path endpoint check to see if it's valid if * req . method ( ) == Method :: POST { match req . uri ( ) . path ( ) { " " => { ret . header ( " " , " " ) ; // Clone the state so we can have access to the paths let state = STATE . clone ( ) ; let mut paths = state . paths . lock ( ) ; // This is pretty lose and it would be best to return an RPC response here on // failure, but we can probably consider this okay for the purposes of an // example as Rust sends utf8 strings only let body = str :: from_utf8 ( req . body ( ) ) . unwrap ( ) ; // Parse the request and check that it is valid if let Ok ( req_json ) = rpc :: Request :: from_json ( body ) { // json-rpc allows us to set a method. We can use this as a way to send // many requests to one endpoint but have it act differently based off the // type of method asked for let method = & req_json . method == " " ; // Due to jsons loosely typed nature we need to make sure we get an object // here let params = req_json . params . is_object ( ) ; if method && params { if let ( Some ( Value :: String ( start ) ) , Some ( Value :: String ( end ) ) ) = ( req_json . params . get ( " " ) , req_json . params . get ( " " ) ) { // Get the start and end NodeIds from the input let start : u64 = City :: from ( start . as_str ( ) ) . into ( ) ; let end : u64 = City :: from ( end . as_str ( ) ) . into ( ) ; // Find the shortest path if possible if let Some ( ( time , path ) ) = astar ( & * paths , start , | finish : u64 | finish == end , | e | * e . weight ( ) , | _ | 0 , ) { let mut journey = state . journey . lock ( ) ; // Add the length in seconds to the time now as the journey // length let time_out = Local :: now ( ) . checked_add_signed ( Duration :: seconds ( time as i64 ) ) . unwrap ( ) ; journey . push ( ( time_out , path . clone ( ) ) ) ; // Add the weights to the graph for nodes in path . as_slice ( ) . windows ( 2 ) { // We know these are valid paths else A* would not have worked let mut edge = paths . edge_weight_mut ( nodes [ 0 ] , nodes [ 1 ] ) . unwrap ( ) ; // Increase the crowdedness * edge = * edge + CAR ; } // Send back the path as strings for the user let path = path . into_iter ( ) . map ( | i | { // TODO Make this abstraction sound and not leaky // Did this to get around some weird conversion trait // bounds but this should be handled properly at some point match i { 0 => " " , 1 => " " , 2 => " " , 3 => " " , _ => " " , } } ) . collect :: < Vec < & str > > ( ) ; // Set the body of the response match rpc :: Response :: new ( json ! ( { " " time " " path } ) , req_json . id , ) . to_json ( ) { Ok ( json ) => bod = json , Err ( e ) => { return future :: err ( io :: Error :: new ( io :: ErrorKind :: Other , e . compat ( ) , ) ) } } } else { // Send back an error message if invalid cities are used match rpc :: Response :: new ( json ! ( " " ) , req_json . id , ) . to_json ( ) { Ok ( json ) => bod = json , Err ( e ) => { return future :: err ( io :: Error :: new ( io :: ErrorKind :: Other , e . compat ( ) , ) ) } } } // TODO clean up the `if let else` statements with better abstractions } else { ret . status ( StatusCode :: BAD_REQUEST ) ; } } else { ret . status ( StatusCode :: BAD_REQUEST ) ; } } else { ret . status ( StatusCode :: BAD_REQUEST ) ; } } _ => { ret . status ( StatusCode :: NOT_FOUND ) ; } } } else { ret . status ( StatusCode :: NOT_FOUND ) ; } // Return the body bod } ; future :: ok ( ret . body ( body ) . unwrap ( ) ) }
"Server logic" is implemented in this function.
" Server logic " is implemented in this function .
req
Request<Bytes>