diff --git a/Cargo.lock b/Cargo.lock
index a18775d..9ceb68b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -491,9 +491,9 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.3.10"
+version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689"
+checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e"
dependencies = [
"bytes",
"fnv",
@@ -1152,6 +1152,19 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "routerify"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "496c1d3718081c45ba9c31fbfc07417900aa96f4070ff90dc29961836b7a9945"
+dependencies = [
+ "http",
+ "hyper",
+ "lazy_static",
+ "percent-encoding",
+ "regex",
+]
+
[[package]]
name = "rust-ini"
version = "0.13.0"
@@ -1690,6 +1703,7 @@ dependencies = [
"hyper-tls",
"pkce",
"redis",
+ "routerify",
"secrecy",
"serde 1.0.133",
"serde_derive",
diff --git a/Cargo.toml b/Cargo.toml
index 7f466fb..f3d9a41 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,4 +36,5 @@ serde_json = "1.0.75"
derive_more = "0.99.17"
thiserror = "1.0.30"
anyhow = "1.0.53"
-sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "json", "chrono", "uuid", "macros", "tls" ] }
\ No newline at end of file
+sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "json", "chrono", "uuid", "macros", "tls" ] }
+routerify = "3.0.0"
\ No newline at end of file
diff --git a/src/app/server.rs b/src/app/server.rs
index b62f4f0..9635175 100644
--- a/src/app/server.rs
+++ b/src/app/server.rs
@@ -1,13 +1,12 @@
-use http::Request;
-use hyper::{Server, Client, Body};
-use hyper::service::{make_service_fn, service_fn};
+use hyper::{Server, Client};
use hyper_tls::HttpsConnector;
+use routerify::RouterService;
use std::{net::SocketAddr};
use dotenv::dotenv;
use redis::{Client as RedisClient};
use crate::helpers::request::HyperClient;
-use crate::routes::server::routes;
+use crate::routes::server::{router};
use crate::setup::variables::SettingsVars;
type GenericError = hyper::Error;
@@ -16,16 +15,16 @@ type GenericError = hyper::Error;
pub struct AppState {
pub redis: RedisClient,
pub hyper: HyperClient,
- pub req: Request
,
+ // pub req: Request,
pub env_vars: SettingsVars,
}
impl AppState {
- fn new( req: Request, hyper: HyperClient, redis: RedisClient) -> Self {
+ fn new(hyper: HyperClient, redis: RedisClient) -> Self {
// is this expensive? Should this rather be done at the point of intializing the hyper_client e.t.c, and then implement
// clone (Iterator trait) for settingsVars?
let env_vars = SettingsVars::new();
- Self { redis, hyper, req, env_vars}
+ Self { redis, hyper, env_vars}
}
}
@@ -35,23 +34,42 @@ pub async fn server() {
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
let https = HttpsConnector::new();
let hyper_pool = Client::builder().build::<_, hyper::Body>(https);
- let hyper_client = hyper_pool.clone();
+ // let hyper_client = hyper_pool.clone();
let redis_client= RedisClient::open("redis://127.0.0.1/").expect("Redis connection failed");
- // let hyper_client = redis_client.get_async_connection().await.un
+ // let hyper_client = redis_client.get_async_connection().await.unwrap();
// let mgr = ConnectionManager::new(redis_client).await.unwrap();
- let service = make_service_fn(move|_| {
- let redis = redis_client.clone();
- let client = hyper_client.clone();
+ // let service = make_service_fn(move|_| {
+ // let redis = redis_client.clone();
+ // let client = hyper_client.clone();
- async {
- Ok::<_, GenericError>(service_fn(move |req| {
- let state = AppState::new(req, client.to_owned(), redis.to_owned());
- routes(state)
- }))
- }
- });
+ // async {
+ // Ok::<_, GenericError>(service_fn(move |req| {
+ // let state = AppState::new(req, client.to_owned(), redis.to_owned());
+ // routes(state)
+ // }))
+ // }
+ // });
+
+ // let service = make_service_fn(move|_| {
+ // let redis = redis_client.clone();
+ // let client = hyper_client.clone();
+
+ // async {
+ // Ok::<_, GenericError>(service_fn(move |req| {
+ // routes(req, client.to_owned(), redis.to_owned())
+ // }))
+ // }
+ // });
+
+ let env_vars = SettingsVars::new();
+
+ let state = AppState::new(hyper_pool.to_owned(), redis_client.to_owned());
+
+ let router = router(state);
+
+ let service = RouterService::new(router).unwrap();
let server = Server::bind(&addr).serve(service);
diff --git a/src/controllers/ Implement Iterator for SettingsVars t.rs b/src/controllers/ Implement Iterator for SettingsVars t.rs
new file mode 100644
index 0000000..53326d7
--- /dev/null
+++ b/src/controllers/ Implement Iterator for SettingsVars t.rs
@@ -0,0 +1,2 @@
+// Implement Iterator for SettingsVars to allow clone
+// Continue sqlx migration
\ No newline at end of file
diff --git a/src/controllers/authorize_bot.rs b/src/controllers/authorize_bot.rs
index 785a666..540965e 100644
--- a/src/controllers/authorize_bot.rs
+++ b/src/controllers/authorize_bot.rs
@@ -1,4 +1,4 @@
-use hyper::{Method, Body, Response};
+use hyper::{Method, Body, Response, Request};
use redis::{AsyncCommands};
use crate::app::server::AppState;
@@ -9,6 +9,8 @@ use crate::helpers::{
scope::Scope,
keyval::KeyVal,
};
+
+
use crate::setup::{variables::SettingsVars};
use crate::middlewares::request_builder::RequestBuilder;
diff --git a/src/controllers/destroy.rs b/src/controllers/destroy.rs
index c306842..4e1cf9a 100644
--- a/src/controllers/destroy.rs
+++ b/src/controllers/destroy.rs
@@ -1,5 +1,6 @@
use std::{collections::HashMap};
use hyper::{Body, Request, Method};
+use routerify::prelude::*;
use futures::{stream, StreamExt};
use serde_json::Value;
use tokio;
@@ -67,6 +68,7 @@ impl PostIds {
if duplicates.is_some() || empty_string.is_some() || not_number.is_some() {
panic!("{} must be an array of ids or an empty array", key)
}
+ // Consider verifying that the string is a valid number when parsed - all twitter ids are numbers
let ids = s.get(&key.to_string()).unwrap()
.iter().map(|k| (k.clone(), key)).collect::>();
@@ -85,14 +87,17 @@ impl PostIds {
// rename this module to destory which then contains destory RTs and destory Posts
-pub async fn handle_delete(app_state: AppState) -> TResult {
- let AppState {redis, req, hyper, ..} = app_state;
+pub async fn handle_delete(req: Request) -> TResult {
+
+ let AppState {redis, hyper, ..} = req.data::().unwrap();
let mut con = redis.get_async_connection().await?;
let access_token: String = redis::cmd("GET").arg(&["access_token"]).query_async(&mut con).await?;
+ let req_body = &req.into_body();
+
// req body for the ids must be a vector of strings(id of tweets)
- let req_body = req.into_body();
+ // let req_body = req.into_body();
let byte_body = hyper::body::to_bytes(req_body).await?.to_owned();
let body: Ids = serde_json::from_slice(&byte_body)?;
diff --git a/src/controllers/handle_redirect.rs b/src/controllers/handle_redirect.rs
index 6012877..c4e9e2a 100644
--- a/src/controllers/handle_redirect.rs
+++ b/src/controllers/handle_redirect.rs
@@ -1,6 +1,6 @@
-use http::Method;
-use hyper::{StatusCode};
+use hyper::{StatusCode, Body, Method, Request};
use redis::{Client as RedisClient};
+use routerify::prelude::*;
use crate::{helpers::{
response::{TResult, ApiBody, make_request, ResponseBuilder},
request::{HyperClient}, keyval::KeyVal, commons::GrantType},
@@ -40,9 +40,9 @@ async fn access_token(hyper_client: HyperClient, redis_client: RedisClient, auth
// req: Request, hyper_client: HyperClient, redis_client: RedisClient
-pub async fn handle_redirect(app_state: AppState) -> TResult {
+pub async fn handle_redirect(req: Request) -> TResult {
- let AppState {redis, hyper, req, env_vars} = app_state;
+ let AppState {redis, hyper, env_vars} = req.data::().unwrap();
let SettingsVars{state, api_key, twitter_v1, ..} = env_vars;
let mut con = redis.get_async_connection().await?;
@@ -88,9 +88,9 @@ pub async fn handle_redirect(app_state: AppState) -> TResult {
let is_v2_callback = query_params.verify_present(vec!["code".into(), "state".into()]);
if let Some(dict) = is_v2_callback {
- if query_params.validate("state".into(), state) {
+ if query_params.validate("state".into(), state.clone()) {
let code = dict.get("code").unwrap().to_string();
- access_token(hyper.clone(), redis, code).await?;
+ access_token(hyper.clone(), redis.clone(), code).await?;
return ResponseBuilder::new("Access Granted".into(), Some(""), StatusCode::OK.as_u16()).reply();
}
diff --git a/src/controllers/health_check.rs b/src/controllers/health_check.rs
index 2fadf8e..8b15033 100644
--- a/src/controllers/health_check.rs
+++ b/src/controllers/health_check.rs
@@ -1,8 +1,10 @@
-use hyper::{StatusCode};
+use hyper::{Body, StatusCode, Request};
+use routerify::prelude::*;
-use crate::helpers::response::{TResult, ApiBody, ResponseBuilder};
+use crate::{helpers::response::{TResult, ApiBody, ResponseBuilder}, app::server::AppState};
-pub fn health_check() -> TResult {
+pub async fn health_check(req: Request) -> TResult {
+ let state = req.data::().unwrap();
ResponseBuilder::new("Ok".into(), Some(""), StatusCode::OK.as_u16()).reply()
}
\ No newline at end of file
diff --git a/src/controllers/not_found.rs b/src/controllers/not_found.rs
index bebe563..7963e29 100644
--- a/src/controllers/not_found.rs
+++ b/src/controllers/not_found.rs
@@ -1,8 +1,8 @@
-use hyper::{StatusCode};
+use hyper::{StatusCode, Body, Request};
-use crate::{helpers::response::{TResult, ApiBody, ResponseBuilder}, app::server::AppState};
+use crate::{helpers::response::{TResult, ApiBody, ResponseBuilder}};
-pub async fn not_found (_state: AppState) -> TResult {
+pub async fn not_found (_req: Request) -> TResult {
ResponseBuilder::new("Resorce not found".into(), Some(""), StatusCode::NOT_FOUND.as_u16()).reply()
}
diff --git a/src/controllers/user_lookup.rs b/src/controllers/user_lookup.rs
index 4a181a0..4558f0d 100644
--- a/src/controllers/user_lookup.rs
+++ b/src/controllers/user_lookup.rs
@@ -1,4 +1,6 @@
-use hyper::{Method, StatusCode};
+use http::Request;
+use hyper::{Method, StatusCode, Body};
+use routerify::prelude::*;
use crate::{helpers::{
response::{ResponseBuilder, TResult, ApiBody, make_request, TwitterResponseHashData}},
@@ -8,9 +10,11 @@ use crate::{helpers::{
// use this endpoint to verify the validity of the username when they want to request for their timeline when using OAuth2.0
-pub async fn user_lookup(app_state: AppState) -> TResult {
+pub async fn user_lookup(req: Request) -> TResult {
+
+ let app_state = req.data::().unwrap();
// todo!() move this to params once route management is migrated to routerify
- let AppState{redis, req, hyper, env_vars, ..} = app_state;
+ let AppState{redis, hyper, env_vars, ..} = app_state;
let SettingsVars {twitter_v2, ..} = env_vars;
let username = req.uri().query().unwrap().split("=").collect::>()[1];
diff --git a/src/routes/server.rs b/src/routes/server.rs
index ae790e4..53ae2cb 100644
--- a/src/routes/server.rs
+++ b/src/routes/server.rs
@@ -1,6 +1,13 @@
+use std::convert::Infallible;
use hyper::{Request, Body, Method};
use crate::app::server::AppState;
+use redis::{Client as RedisClient};
+use routerify::{Router, Middleware};
+
+
+use crate::errors::response::TError;
+use crate::helpers::request::HyperClient;
use crate::helpers::response::{ApiBody};
use crate::{helpers::response::TResult};
use crate::controllers::{not_found, authorize_bot,
@@ -10,25 +17,42 @@ use crate::controllers::{not_found, authorize_bot,
-pub async fn routes(
- state: AppState
-) -> TResult {
- // migrate this to [routerify](https://docs.rs/routerify/latest/routerify/) eventually
- let req = &state.req;
-
- match (req.method(), req.uri().path(), req.uri().query()) {
- (&Method::GET, "/", _) => health_check(),
- (&Method::GET, "/enable", _) => authorize_bot(state).await,
- (&Method::GET, "/oauth/callback", x) => handle_redirect(state).await,
- (&Method::POST, "/revoke", _) => revoke_token(state).await,
- (&Method::GET, "/refresh", _) => refresh_token(state).await,
- (&Method::GET, "/user", x) => user_lookup(state).await,
- (&Method::GET, "/timeline", x) => get_timeline(state).await,
- (&Method::POST, "/remove", _) => handle_delete(state).await,
- (&Method::GET, "/oauth1/request", _) => request_token(state).await,
- (&Method::GET, "/oauth1/", _) => request_token(state).await,
- _ => {
- not_found(state).await
- }
- }
+// pub async fn routes(
+// state: AppState
+// ) -> TResult {
+// // migrate this to [routerify](https://docs.rs/routerify/latest/routerify/) eventually
+// let req = &state.req;
+
+// match (req.method(), req.uri().path(), req.uri().query()) {
+// (&Method::GET, "/", _) => health_check(),
+// (&Method::GET, "/enable", _) => authorize_bot(state).await,
+// (&Method::GET, "/oauth/callback", x) => handle_redirect(state).await,
+// (&Method::POST, "/revoke", _) => revoke_token(state).await,
+// (&Method::GET, "/refresh", _) => refresh_token(state).await,
+// (&Method::GET, "/user", x) => user_lookup(state).await,
+// (&Method::GET, "/timeline", x) => get_timeline(state).await,
+// (&Method::POST, "/remove", _) => handle_delete(state).await,
+// (&Method::GET, "/oauth1/request", _) => request_token(state).await,
+// (&Method::GET, "/oauth1/", _) => request_token(state).await,
+// _ => {
+// not_found(state).await
+// }
+// }
+// }
+
+
+
+pub fn router(state: AppState) -> Router {
+ Router::builder()
+ // Specify the state data which will be available to every route handlers,
+ // error handler and middlewares.
+ .data(state)
+ // .middleware(Middleware::pre(logger))
+ .get("/", health_check)
+ .get("/oauth/callback", handle_redirect)
+ // .get("/enable", authorize_bot)
+ .any(not_found)
+ // .err_handler_with_info(error_handler)
+ .build()
+ .unwrap()
}
\ No newline at end of file