aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs11
-rw-r--r--src/service.rs50
2 files changed, 36 insertions, 25 deletions
diff --git a/src/main.rs b/src/main.rs
index 6b48957..c9819d0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,15 +4,22 @@ use hyper::Server;
4use log::trace; 4use log::trace;
5 5
6mod db; 6mod db;
7use db::init_db;
7mod service; 8mod service;
8use service::shortner_service; 9use service::shortner_service;
9 10
11use std::sync::{Arc, Mutex};
12
10fn main() -> Result<()> { 13fn main() -> Result<()> {
11 pretty_env_logger::init(); 14 pretty_env_logger::init();
12 smol::run(async { 15 smol::run(async {
13 let addr = ([127, 0, 0, 1], 3000).into(); 16 let addr = ([127, 0, 0, 1], 3000).into();
14 let service = 17 let service = make_service_fn(move |_| async {
15 make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(shortner_service)) }); 18 Ok::<_, hyper::Error>(service_fn(move |req| {
19 let db_conn = init_db("./urls.db_3").unwrap();
20 shortner_service(req, db_conn)
21 }))
22 });
16 let server = Server::bind(&addr).serve(service); 23 let server = Server::bind(&addr).serve(service);
17 trace!("Listening on http://{}", addr); 24 trace!("Listening on http://{}", addr);
18 server.await.unwrap(); 25 server.await.unwrap();
diff --git a/src/service.rs b/src/service.rs
index 5883b40..41aa048 100644
--- a/src/service.rs
+++ b/src/service.rs
@@ -1,15 +1,14 @@
1use anyhow::{Context, Result}; 1use anyhow::{Context, Result};
2use hyper::header::CONTENT_TYPE; 2use hyper::header::CONTENT_TYPE;
3use hyper::{Body, Method, Request, Response, StatusCode}; 3use hyper::{Body, Method, Request, Response, StatusCode};
4use log::{debug, error, info, trace}; 4use log::{error, info, trace};
5use multer::Multipart; 5use multer::Multipart;
6use nanoid::nanoid; 6use nanoid::nanoid;
7use rusqlite::{params, Connection}; 7use rusqlite::{params, Connection};
8use url::form_urlencoded; 8use url::form_urlencoded;
9 9
10use std::collections::HashMap; 10use std::collections::HashMap;
11 11use std::sync::{Arc, Mutex};
12use crate::db::init_db;
13 12
14fn respond_with_shortlink<S: AsRef<str>>(shortlink: S) -> Response<Body> { 13fn respond_with_shortlink<S: AsRef<str>>(shortlink: S) -> Response<Body> {
15 info!("Successfully generated shortlink"); 14 info!("Successfully generated shortlink");
@@ -39,7 +38,7 @@ fn shorten<S: AsRef<str>>(url: S, conn: &mut Connection) -> Result<String> {
39 } 38 }
40} 39}
41 40
42fn get_link<S: AsRef<str>>(url: S, conn: &mut Connection) -> Result<Option<String>> { 41fn get_link<S: AsRef<str>>(url: S, conn: &Connection) -> Result<Option<String>> {
43 let url = url.as_ref(); 42 let url = url.as_ref();
44 let mut stmt = conn.prepare("select * from urls where shortlink = ?1")?; 43 let mut stmt = conn.prepare("select * from urls where shortlink = ?1")?;
45 let mut rows = stmt.query(params![url.to_string()])?; 44 let mut rows = stmt.query(params![url.to_string()])?;
@@ -72,9 +71,29 @@ async fn process_multipart(
72 Ok(respond_with_status(StatusCode::UNPROCESSABLE_ENTITY)) 71 Ok(respond_with_status(StatusCode::UNPROCESSABLE_ENTITY))
73} 72}
74 73
75pub async fn shortner_service(req: Request<Body>) -> Result<Response<Body>> { 74async fn process_form(req: Request<Body>, conn: &mut Connection) -> Result<Response<Body>> {
76 let mut conn = init_db("./urls.db_3").unwrap(); 75 let b = hyper::body::to_bytes(req)
76 .await
77 .with_context(|| format!("Failed to stream request body!"))?;
78
79 let params = form_urlencoded::parse(b.as_ref())
80 .into_owned()
81 .collect::<HashMap<String, String>>();
77 82
83 if let Some(n) = params.get("shorten") {
84 trace!("POST: {}", &n);
85 let s = shorten(n, conn)?;
86 return Ok(respond_with_shortlink(s));
87 } else {
88 error!("Invalid form");
89 return Ok(respond_with_status(StatusCode::UNPROCESSABLE_ENTITY));
90 }
91}
92
93pub async fn shortner_service(
94 req: Request<Body>,
95 mut conn: Arc<Mutex<Connection>>,
96) -> Result<Response<Body>> {
78 match req.method() { 97 match req.method() {
79 &Method::POST => { 98 &Method::POST => {
80 let boundary = req 99 let boundary = req
@@ -84,22 +103,7 @@ pub async fn shortner_service(req: Request<Body>) -> Result<Response<Body>> {
84 .and_then(|ct| multer::parse_boundary(ct).ok()); 103 .and_then(|ct| multer::parse_boundary(ct).ok());
85 104
86 if boundary.is_none() { 105 if boundary.is_none() {
87 let b = hyper::body::to_bytes(req) 106 return process_form(req, &mut conn).await;
88 .await
89 .with_context(|| format!("Failed to stream request body!"))?;
90
91 let params = form_urlencoded::parse(b.as_ref())
92 .into_owned()
93 .collect::<HashMap<String, String>>();
94
95 if let Some(n) = params.get("shorten") {
96 trace!("POST: {}", &n);
97 let s = shorten(n, &mut conn)?;
98 return Ok(respond_with_shortlink(s));
99 } else {
100 error!("Invalid form");
101 return Ok(respond_with_status(StatusCode::UNPROCESSABLE_ENTITY));
102 }
103 } 107 }
104 108
105 trace!("Attempting to parse multipart request"); 109 trace!("Attempting to parse multipart request");
@@ -108,7 +112,7 @@ pub async fn shortner_service(req: Request<Body>) -> Result<Response<Body>> {
108 &Method::GET => { 112 &Method::GET => {
109 trace!("GET: {}", req.uri()); 113 trace!("GET: {}", req.uri());
110 let shortlink = req.uri().path().to_string(); 114 let shortlink = req.uri().path().to_string();
111 let link = get_link(&shortlink[1..], &mut conn); 115 let link = get_link(&shortlink[1..], &conn);
112 if let Some(l) = link.unwrap() { 116 if let Some(l) = link.unwrap() {
113 trace!("Found in database, redirecting ..."); 117 trace!("Found in database, redirecting ...");
114 Ok(Response::builder() 118 Ok(Response::builder()