You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
7.4 KiB

4 years ago
  1. #[macro_use]
  2. extern crate diesel;
  3. use actix_web::{
  4. dev::ServiceRequest, error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse,
  5. HttpServer, Responder,
  6. };
  7. use yarte::Template;
  8. use actix_web_httpauth::{extractors::basic::BasicAuth, middleware::HttpAuthentication};
  9. use actix_http::cookie::SameSite;
  10. use actix_identity::{CookieIdentityPolicy, Identity, IdentityService};
  11. use rand::Rng;
  12. // use actix_http::*;
  13. use actix_files as fs;
  14. use diesel::prelude::*;
  15. use diesel::r2d2::{self, ConnectionManager};
  16. use routes::*;
  17. mod actions;
  18. mod models;
  19. mod routes;
  20. mod schema;
  21. mod types;
  22. #[macro_use]
  23. extern crate log;
  24. use serde::{Deserialize, Serialize};
  25. #[derive(Debug, Serialize, Deserialize)]
  26. struct MyObj {
  27. name: String,
  28. // number: i32,
  29. }
  30. #[get("/{id}/{name}")]
  31. async fn index(info: web::Path<(u32, String)>) -> Result<HttpResponse, Error> {
  32. let (id, name) = (info.0, info.1.clone());
  33. let template = models::CardTemplate {
  34. title: "My Title",
  35. body: name,
  36. num: id,
  37. };
  38. template
  39. .call()
  40. .map(|body| HttpResponse::Ok().content_type("text/html").body(body))
  41. .map_err(|_| error::ErrorInternalServerError("Error while parsing template"))
  42. }
  43. /// This handler uses json extractor
  44. #[post("/extractor")]
  45. async fn extract_my_obj(item: web::Json<MyObj>) -> HttpResponse {
  46. debug!("model: {:?}", item);
  47. HttpResponse::Ok().json(item.0) // <- send response
  48. }
  49. pub struct UserServiceImpl;
  50. impl UserServiceImpl {
  51. pub fn new() -> Self {
  52. UserServiceImpl {}
  53. }
  54. }
  55. pub trait UserService {
  56. fn do_something(&self);
  57. }
  58. impl UserService for UserServiceImpl {
  59. fn do_something(&self) {
  60. println!("hello");
  61. }
  62. }
  63. fn fun1(user_service: &dyn UserService) {
  64. user_service.do_something();
  65. }
  66. fn fun2<T>(user_service: T)
  67. where
  68. T: UserService,
  69. {
  70. user_service.do_something();
  71. }
  72. /// In this example validator returns immediately,
  73. /// but since it is required to return anything
  74. /// that implements `IntoFuture` trait,
  75. /// it can be extended to query database
  76. /// or to do something else in a async manner.
  77. async fn validator(req: ServiceRequest, credentials: BasicAuth) -> Result<ServiceRequest, Error> {
  78. // All users are great and more than welcome!
  79. // let pool = req.app_data::<DbPool>();
  80. // let maybe_header = req.headers().get("Authorization");
  81. // match maybe_header {
  82. // Some(value) => {
  83. // info!("{:?}", *value);
  84. // let x: Result<Basic, _> = Scheme::parse(value);
  85. // let y = x.expect("Error parsing header");
  86. // println!("{}", y.user_id());
  87. // println!("{:?}", y.password().clone());
  88. // }
  89. // None => debug!("Header not found"),
  90. // }
  91. // maybe_header
  92. // .map(|value| {
  93. // let x: Result<Basic, _> = Scheme::parse(value);
  94. // x
  95. // })
  96. // .map(|maybe_basic| {
  97. // maybe_basic
  98. // .map(|x| {
  99. // println!("{}", x.user_id());
  100. // println!("{:?}", x.password().clone());
  101. // })
  102. // .map_err(|x| println!("error parsing reason - {}", x.to_string()))
  103. // // maybe_basic
  104. // });
  105. // let auth = Authorization::<Basic>;
  106. println!("{}", credentials.user_id());
  107. println!("{:?}", credentials.password());
  108. Ok(req)
  109. }
  110. // fn parse(header: &HeaderValue) -> Result<Basic, ParseError> {
  111. // // "Basic *" length
  112. // if header.len() < 7 {
  113. // return Err(ParseError::Invalid);
  114. // }
  115. // let mut parts = header.to_str()?.splitn(2, ' ');
  116. // match parts.next() {
  117. // Some(scheme) if scheme == "Basic" => (),
  118. // _ => return Err(ParseError::MissingScheme),
  119. // }
  120. // let decoded = base64::decode(parts.next().ok_or(ParseError::Invalid)?)?;
  121. // let mut credentials = str::from_utf8(&decoded)?.splitn(2, ':');
  122. // let user_id = credentials
  123. // .next()
  124. // .ok_or(ParseError::MissingField("user_id"))
  125. // .map(|user_id| user_id.to_string().into())?;
  126. // let password = credentials
  127. // .next()
  128. // .ok_or(ParseError::MissingField("password"))
  129. // .map(|password| {
  130. // if password.is_empty() {
  131. // None
  132. // } else {
  133. // Some(password.to_string().into())
  134. // }
  135. // })?;
  136. // Ok(Basic { user_id, password })
  137. // }
  138. #[get("/login")]
  139. async fn login(id: Identity) -> HttpResponse {
  140. let maybe_identity = id.identity();
  141. // id.remember("user1".to_owned());
  142. let response = if let Some(identity) = maybe_identity {
  143. HttpResponse::Ok()
  144. .header("location", "/")
  145. .content_type("text/plain")
  146. .body(format!("Already logged in {}", identity))
  147. } else {
  148. id.remember("user1".to_owned());
  149. HttpResponse::Found().header("location", "/").finish()
  150. };
  151. // HttpResponse::Found().header("location", "/").finish()
  152. response
  153. }
  154. #[get("/logout")]
  155. async fn logout(id: Identity) -> HttpResponse {
  156. let maybe_identity = id.identity();
  157. // id.remember("user1".to_owned());
  158. let response = if let Some(identity) = maybe_identity {
  159. info!("Logging out {user}", user = identity);
  160. id.forget();
  161. HttpResponse::Found().header("location", "/").finish()
  162. } else {
  163. HttpResponse::Ok()
  164. .header("location", "/")
  165. .content_type("text/plain")
  166. .body("Not logged in")
  167. };
  168. // id.forget();
  169. // HttpResponse::Found().header("location", "/").finish()
  170. response
  171. }
  172. #[get("/")]
  173. async fn index2(id: Identity) -> String {
  174. format!(
  175. "Hello {}",
  176. id.identity().unwrap_or_else(|| "Anonymous".to_owned())
  177. )
  178. }
  179. #[actix_rt::main]
  180. async fn main() -> std::io::Result<()> {
  181. std::env::set_var("RUST_LOG", "debug");
  182. env_logger::init();
  183. dotenv::dotenv().ok();
  184. let user_service: Box<dyn UserService> = Box::new(UserServiceImpl::new());
  185. user_service.do_something();
  186. fun1(user_service.as_ref());
  187. let user_service_impl = UserServiceImpl::new();
  188. fun2(user_service_impl);
  189. let basic_auth_middleware = HttpAuthentication::basic(validator);
  190. // fun1(Rc::clone(&user_service).as_ref());
  191. // set up database connection pool
  192. let connspec = std::env::var("DATABASE_URL").expect("DATABASE_URL NOT FOUND");
  193. let manager = ConnectionManager::<SqliteConnection>::new(connspec);
  194. let pool = r2d2::Pool::builder()
  195. .build(manager)
  196. .expect("Failed to create pool.");
  197. let addr = std::env::var("BIND_ADDRESS").expect("BIND ADDRESS NOT FOUND");
  198. info!("Starting server {}", addr);
  199. let private_key = rand::thread_rng().gen::<[u8; 32]>();
  200. let app = move || {
  201. App::new()
  202. .data(pool.clone())
  203. .wrap(IdentityService::new(
  204. CookieIdentityPolicy::new(&private_key)
  205. .name("my-app-auth")
  206. .secure(false)
  207. .same_site(SameSite::Lax), // .same_site(),
  208. ))
  209. .wrap(middleware::Logger::default())
  210. .service(web::scope("/chat").wrap(basic_auth_middleware.clone()))
  211. // .service(extract_my_obj)
  212. // .service(index)
  213. .service(get_user)
  214. .service(add_user)
  215. .service(get_all_users)
  216. .service(login)
  217. .service(logout)
  218. .service(index2)
  219. .service(fs::Files::new("/", "./static"))
  220. };
  221. HttpServer::new(app).bind(addr)?.run().await
  222. }