diff --git a/backend/Cargo.toml b/backend/Cargo.toml index fccd9d2..6444b9d 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -16,11 +16,14 @@ repository = "https://www.github.com/HsuJv/webgateway" [dependencies] actix = "0.10.0" +actix-session = "0.4" actix-web = "3.3.2" actix-files = "0.5.0" -tokio-tar = "0.3.0" -urlencoding = "2.1.0" actix-web-actors = "3.0.0" +urlencoding = "2.1.0" +serde_json = "1.0" + +rand = "0.8" # log systems femme = "1.3" @@ -31,8 +34,6 @@ async-log = "2.0.0" panic = "unwind" opt-level = 0 - - [profile.release] panic = 'abort' codegen-units = 1 diff --git a/backend/src/main.rs b/backend/src/main.rs index f27ffdf..e332564 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,10 +1,13 @@ use actix_files as fs; +use actix_session::CookieSession; use actix_web::http::{ContentEncoding, StatusCode}; use actix_web::*; use femme; use log::info; +use rand::Rng; +mod user; mod ws; const STATIC_DIR: &str = "./static/"; @@ -32,11 +35,14 @@ async fn main() -> std::io::Result<()> { setup_logger(); info!("Server starts at http://127.0.0.1:8080"); + let private_key = rand::thread_rng().gen::<[u8; 32]>(); HttpServer::new(move || { App::new() + .wrap(CookieSession::signed(&private_key).secure(false)) .wrap(middleware::Compress::new(ContentEncoding::Gzip)) .service(index) - .service(web::resource("/ws").route(web::get().to(ws::index))) + .service(ws::ws_index) + .service(user::auth::auth) .service( fs::Files::new("/static", STATIC_DIR) .prefer_utf8(true) diff --git a/backend/src/user/auth.rs b/backend/src/user/auth.rs new file mode 100644 index 0000000..25630ce --- /dev/null +++ b/backend/src/user/auth.rs @@ -0,0 +1,12 @@ +use actix_web::*; +use serde_json::json; + +use log::info; + +#[post("/auth")] +pub async fn auth(req: HttpRequest) -> Result { + info!("{:?}", req); + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(json!({"status": "success"}))) +} diff --git a/backend/src/user/mod.rs b/backend/src/user/mod.rs new file mode 100644 index 0000000..0e4a05d --- /dev/null +++ b/backend/src/user/mod.rs @@ -0,0 +1 @@ +pub mod auth; diff --git a/backend/src/ws.rs b/backend/src/ws.rs index b4367c3..ec7011c 100644 --- a/backend/src/ws.rs +++ b/backend/src/ws.rs @@ -1,4 +1,5 @@ use actix::{Actor, StreamHandler}; +use actix_web::*; use actix_web::{web, Error, HttpRequest, HttpResponse}; use actix_web_actors::ws; use log::*; @@ -22,7 +23,8 @@ impl StreamHandler> for MyWs { } } -pub async fn index(req: HttpRequest, stream: web::Payload) -> Result { +#[get("/ws")] +pub async fn ws_index(req: HttpRequest, stream: web::Payload) -> Result { let resp = ws::start(MyWs {}, &req, stream); match &resp { Ok(resp) => info!("{:?}", resp), diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 794ecd1..b7e0aa9 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -31,6 +31,8 @@ console_error_panic_hook = { version = "0.1.6", optional = true } # compared to the default allocator's ~10K. It is slower than the default # allocator, however. wee_alloc = { version = "0.4", optional = true } +serde_json = "1.0" +anyhow = "1.0" [features] default = ["console_error_panic_hook", "wee_alloc"] diff --git a/frontend/src/app.rs b/frontend/src/app.rs index 7fba67a..997184e 100644 --- a/frontend/src/app.rs +++ b/frontend/src/app.rs @@ -70,10 +70,8 @@ impl Component for App { /> } diff --git a/frontend/src/components/auth.rs b/frontend/src/components/auth.rs new file mode 100644 index 0000000..286807c --- /dev/null +++ b/frontend/src/components/auth.rs @@ -0,0 +1,152 @@ +use anyhow; +use serde_json::{json, Value}; +use std::fmt::Debug; +use yew::services::{ + fetch::{FetchTask, Request}, + FetchService, +}; +use yew::{format::Json, services::fetch::Response}; +use yew::{prelude::*, services::ConsoleService}; +pub enum AuthMsg { + UpdateUsername(String), + UpdatePassword(String), + AuthRequest, + AuthResponse(Result), +} + +pub struct AuthComponents { + username: String, + password: String, + link: ComponentLink, + auth_result: String, + fetch_task: Option, +} + +impl Debug for AuthComponents { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "AuthComponents {{ username: {}, password: {} }}", + self.username, self.password + ) + } +} + +impl Component for AuthComponents { + type Message = AuthMsg; + type Properties = (); + + fn create(_: Self::Properties, link: ComponentLink) -> Self { + AuthComponents { + username: String::new(), + password: String::new(), + auth_result: String::new(), + link, + fetch_task: None, + } + } + + fn update(&mut self, msg: Self::Message) -> ShouldRender { + match msg { + AuthMsg::UpdateUsername(username) => { + self.username = username; + self.auth_result.clear(); + } + AuthMsg::UpdatePassword(password) => { + self.password = password; + self.auth_result.clear(); + } + AuthMsg::AuthRequest => { + let auth_info = json!({ + "username": self.username, + "password": self.password, + }); + + // 1. build the request + let request = Request::post("/auth") + .header("Content-Type", "application/json") + .body(Json(&auth_info)) + .expect("Could not build auth request."); + // 2. construct a callback + let callback = + self.link + .callback(|response: Response>>| { + // ConsoleService::error(&format!("{:?}", response)); + let Json(data) = response.into_body(); + AuthMsg::AuthResponse(data) + }); + // 3. pass the request and callback to the fetch service + let task = FetchService::fetch(request, callback).expect("failed to start request"); + // 4. store the task so it isn't canceled immediately + self.fetch_task = Some(task); + } + AuthMsg::AuthResponse(response) => { + if let Ok(response) = response { + self.auth_result = response["status"].to_string(); + } else { + self.auth_result = String::from("Auth failed with unknown reason"); + ConsoleService::error(&format!("{:?}", response.unwrap_err().to_string())); + } + // release resources + self.fetch_task = None; + } + _ => panic!("unexpected message"), + } + // ConsoleService::log(&format!( + // "username: {}, password {}", + // self.username, self.password + // )); + true + } + + fn change(&mut self, _props: Self::Properties) -> ShouldRender { + false + } + + fn view(&self) -> Html { + let link = &self.link; + + let update_uname = link.callback(|e: ChangeData| match e { + ChangeData::Value(val) => AuthMsg::UpdateUsername(val), + _ => panic!("unexpected message"), + }); + + let update_pword = link.callback(|e: ChangeData| match e { + ChangeData::Value(val) => AuthMsg::UpdatePassword(val), + _ => panic!("unexpected message"), + }); + + let auth_post = link.callback(|_| { + // ConsoleService::log("Auth post"); + AuthMsg::AuthRequest + }); + + html! { +
+ + +
+ + +
+ +
+ {self.auth_result_view()} +
+ } + } +} + +impl AuthComponents { + fn auth_result_view(&self) -> Html { + if let Some(_) = &self.fetch_task { + html! { +
{"Authing..."}
+ } + } else { + html! { +
{self.auth_result.clone()}
+ } + } + } +} diff --git a/frontend/src/components/mod.rs b/frontend/src/components/mod.rs new file mode 100644 index 0000000..0e4a05d --- /dev/null +++ b/frontend/src/components/mod.rs @@ -0,0 +1 @@ +pub mod auth; diff --git a/frontend/src/lib.rs b/frontend/src/lib.rs index 0478693..cd81849 100644 --- a/frontend/src/lib.rs +++ b/frontend/src/lib.rs @@ -1,4 +1,5 @@ mod app; +mod components; mod pages; mod utils; diff --git a/frontend/src/pages/page_home.rs b/frontend/src/pages/page_home.rs index 4eb19cb..09d3125 100644 --- a/frontend/src/pages/page_home.rs +++ b/frontend/src/pages/page_home.rs @@ -1,31 +1,26 @@ use yew::prelude::*; -use yew::Component; use yew::ShouldRender; +use yew::{html, Component, Html}; -pub struct PageHome; +use crate::components; + +pub enum HomeMsg {} + +pub struct PageHome { + link: ComponentLink, +} impl Component for PageHome { - type Message = (); + type Message = HomeMsg; type Properties = (); - fn create(_props: Self::Properties, _link: ComponentLink) -> Self { - Self + fn create(_props: Self::Properties, link: ComponentLink) -> Self { + Self { link } } fn view(&self) -> Html { html! { -
-
-
-

- { "Hello World" } -

-

- { "Hello again" } -

-
-
-
+ } } diff --git a/frontend/static/index.html b/frontend/static/index.html index 2ecd2ac..2cf920b 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -17,6 +17,16 @@ padding: 40px; } + .horizontal-centre { + position: relative; + text-align: center; + } + + .vertical-centre { + position: relative; + vertical-align: middle; + } + html, body { height: 100%;