[dependencies]hyper = "0.12"serde_json = "1.0.96"futures = "0.1.31"lazy_static = "1.4.0"rust-crypto = "0.2.36"pretty_env_logger = "0.5"log = "0.4"
// hyperurl/src/index.rspub static INDEX_PAGE: &str = r##"<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>hyperurl - A url shortener in Rust</title> <style> body { text-align: center;} </style></head><body><h3>hyperurl - A url shortening service</h3> <p>To shorten a url, make a post request using curl as:</p> <p><code>curl --data "https://creativcoder.github.io" http://localhost:3002/shorten</code></p> <p>You will get a reply as:</p> <p>{ "127.0.0.1:3002/992a7": "https://creativcoder.github.io" }</p> <p>Put the shortened url (127.0.0.1:3002/992a7) in the browser to get redirected to the original website.</p> <p>Made with ❤ with hyper in Rust</p></body></html>"##;
// hyperurl/src/service.rsuse std::sync::RwLock;use std::collections::HashMap;use std::sync::{Arc};use std::str;use hyper::Request;use hyper::{Body, Response};use hyper::rt::{Future, Stream};use hyper::Method;use hyper::StatusCode;use lazy_static::lazy_static;use log::info;use crate::shortener::shorten_url;use futures::future;use crate::index::INDEX_PAGE;use crate::LISTEN_ADDR;type UrlDb = Arc<RwLock<HashMap<String, String>>>;type BoxFut = Box<dyn Future<Item = Response<Body>, Error = hyper::Error> + Send>;lazy_static! { static ref SHORT_URLS: UrlDb = Arc::new(RwLock::new(HashMap::new()));}pub(crate) fn url_service(req: Request<Body>) -> BoxFut { match (req.method(), req.uri().path()) { (&Method::GET, "/") => { let reply = Response::new(Body::from(format!("{}",INDEX_PAGE))); Box::new(future::ok(reply)) } (&Method::GET, _) => { let url_db = SHORT_URLS.read().unwrap(); let uri = req.uri().to_string(); let short_url = format!("{}{}", LISTEN_ADDR, uri); let long_url = url_db.get(&short_url); println!("LONG URL {:?}",long_url); let reply = match long_url { Some(url) => { info!("Redirecting from {} to {}", short_url, url); Response::builder().status(StatusCode::TEMPORARY_REDIRECT) .header("Location", url.to_string()).body(Body::empty()).unwrap() } None => { Response::builder() .status(StatusCode::NOT_FOUND) .body(Body::from(format!("Bad URI: {:?}", uri))).unwrap() } }; Box::new(future::ok(reply)) } (&Method::POST, "/shorten") => { info!("Received request from : {:?}", req.headers()); let reply = req.into_body().concat2().map(move |chunk| { let c = chunk.iter().cloned().collect::<Vec<u8>>(); let url_to_shorten = str::from_utf8(&c).unwrap(); let short_url = shorten_url(url_to_shorten); let reply = Response::new(Body::from(format!("{}", &short_url))); SHORT_URLS.write().unwrap().insert(short_url, url_to_shorten.to_string()); reply }); Box::new(reply) } (_, _) => { let no_route = Response::new(Body::from("No route handler for this path")); Box::new(future::ok(no_route)) } }}
// hyperurl/src/shortener.rsuse crypto::digest::Digest;use crypto::sha2::Sha256;use crate::LISTEN_ADDR;pub(crate) fn shorten_url(url: &str) -> String { let mut sha = Sha256::new(); sha.input_str(url); let mut s = sha.result_str(); s.truncate(5); format!("{}/{}", LISTEN_ADDR, s)}
// hyperurl/src/main.rsuse log::{info, error};use std::env;use hyper::Server;use hyper::service::service_fn;use hyper::rt::{self, Future};mod shortener;mod service;mod index;use crate::service::url_service;const LISTEN_ADDR: &str = "127.0.0.1:3002";fn main() { env::set_var("RUST_LOG","hyperurl=info"); pretty_env_logger::init(); let addr = LISTEN_ADDR.parse().unwrap(); let server = Server::bind(&addr) .serve(|| service_fn(url_service)) .map_err(|e| error!("server error: {}", e)); info!("hyperurl is listening at {}", addr); rt::run(server);}
版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除