From f0c275120a039ce6c839094bcd3818cbde2a4bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Fri, 8 Oct 2021 23:42:15 +0200 Subject: [PATCH] Fix drop create modal, add deploy info --- README.md | 3 +- actors/database-actor/src/issues.rs | 26 ++++-- docs/Deploy.md | 127 ++++++++++++++++++++++++++++ web/src/lib.rs | 103 +++++++++++----------- web/src/location.rs | 49 ++++++++--- web/src/modals/update.rs | 5 +- web/src/ws/mod.rs | 96 ++++++++++++--------- 7 files changed, 295 insertions(+), 114 deletions(-) create mode 100644 docs/Deploy.md diff --git a/README.md b/README.md index 5bdf7ce1..57bef07f 100644 --- a/README.md +++ b/README.md @@ -180,8 +180,7 @@ cargo run --bin jirs_server ```bash curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh cd jirs_client -yarn -./scripts/prod.sh +./web/scripts/prod.sh ``` ```bash diff --git a/actors/database-actor/src/issues.rs b/actors/database-actor/src/issues.rs index 5b3927d4..be78889d 100644 --- a/actors/database-actor/src/issues.rs +++ b/actors/database-actor/src/issues.rs @@ -193,7 +193,11 @@ impl CreateIssue { crate::issue_statuses::LoadIssueStatuses { project_id: msg.project_id, } - .execute(conn)? + .execute(conn) + .map_err(|e| { + common::log::error!("Failed to find issue status. {:?}", e); + e + })? .first() .ok_or(crate::DatabaseError::Issue( crate::IssueError::NoIssueStatuses, @@ -223,12 +227,22 @@ impl CreateIssue { reporter_id: msg.reporter_id, epic_id: msg.epic_id, } - .execute(conn)?; - crate::issue_assignees::AsignMultiple { - issue_id: issue.id, - user_ids: assign_users, + .execute(conn) + .map_err(|e| { + common::log::error!("Failed to insert issue. {:?}", e); + e + })?; + if !assign_users.is_empty() { + crate::issue_assignees::AsignMultiple { + issue_id: issue.id, + user_ids: assign_users, + } + .execute(conn) + .map_err(|e| { + common::log::error!("Failed to apply multiple assignee to issue. {:?}", e); + e + })?; } - .execute(conn)?; issues.find(issue.id).get_result(conn).map_err(|e| { common::log::error!("{:?}", e); crate::DatabaseError::GenericFailure( diff --git a/docs/Deploy.md b/docs/Deploy.md new file mode 100644 index 00000000..ceb23652 --- /dev/null +++ b/docs/Deploy.md @@ -0,0 +1,127 @@ +# Deploy with Nginx + +You can deploy easily JIRS to any PC including Raspberry PI. To do this you will need compile it from source code. + +We will use following setup, but you can modify it. + +* `issues.example.com` - domain +* `postgres://postgres@192.168.1.144:5432/jirs` - database on other machine and within inner network + +* `/var/jirs` - main directory +* `/var/jirs/clone` - cloned source code +* `/var/jirs/web` - All static assets including wasm library +* `/var/jirs/config` - config files +* `/var/jirs/uploads` - uploaded files + +### JIRS Config files + +* `config/db.toml` (REQUIRED) + +```toml +concurrency = 2 +database_url = "postgres://postgres@192.168.1.144:5432/jirs" +``` + +* `config/web.toml` (public_path is required) + +```toml +concurrency = 2 +port = "5000" +bind = "0.0.0.0" +ssl = false +tmp_dir = "/tmp" +public_path = "issues.example.com" +``` + +* `config/fs.toml` (must match nginx config) + +```toml +store_path = "./uploads" +client_path = "/uploads" +tmp_path = "/tmp" +concurrency = 2 +``` + +* `config/mail.toml` (REQUIRED) + +```toml +concurrency = 2 +user = "apikey" +pass = "SG.ARJL0wAxQk-LLJca9FJ5Lg.ahs7dyashd8a7shd7ahsd978h" +host = "smtp.sendgrid.net" +from = "admin@issues.example.com" +``` + +### NGINX config file + +```nginx +server { + listen 80; + server_name issues.example.com; + + root /var/jirs/web; + try_files $uri $uri/index.html index.html; + + location ~ /uploads/ { + root /var/jirs; + } + + location ~ .js { + add_header 'Content-Type' 'application/javascript'; + add_header 'Access-Control-Allow-Origin' '*'; + } + location ~ .css { + add_header 'Content-Type' 'text/css'; + } + location ~ .wasm { + add_header 'Content-Type' 'application/wasm'; + add_header 'Access-Control-Allow-Origin' '*'; + } + + location /ws/ { + proxy_pass http://localhost:5000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } + location /avatar { + proxy_pass http://localhost:5000; + } + location ~ / { + add_header 'Content-Type' 'text/html'; + add_header 'Access-Control-Allow-Origin' '*'; + root /var/jirs/web; + try_files $uri $uri/index.html /index.html; + } +} +``` + +### Compile application + +```bash +cargo install --force wasm-pack +cargo install --force rsass +``` + +Ensure `$HOME/.cargo/bin` is in `$PATH` + +* Compile server + +```bash +cargo build --bin jirs_server --release --no-default-features --features local-storage +cp ./target/release/jirs_server /usr/bin/jirs_server +``` + +* Compile web client + +```bash +./web/scripts/prod.sh + +cp -r /tmp/wasm/* /var/jirs/web +``` + +If it fails (there is no wasm-opt for Raspberry PI) you must disable wasm-opt or compile it on any other PC and just +copy everything to `/var/jirs/web` + + diff --git a/web/src/lib.rs b/web/src/lib.rs index 0622b8ca..72d57abb 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -156,60 +156,59 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders) { if model.ws.is_none() { open_socket(model, orders); } + let mut msg = msg; let msg = match msg { - Msg::WebSocketChange(change) => { - match change { - WebSocketChanged::WebSocketOpened => { - flush_queue(model, orders); - send_ws_msg(WsMsg::Ping, model.ws.as_ref(), orders); - authorize_or_redirect(model, orders); - orders.skip(); - return; - } - WebSocketChanged::SendPing => { - send_ws_msg(WsMsg::Ping, model.ws.as_ref(), orders); - orders.skip(); - return; - } - WebSocketChanged::WebSocketMessage(incoming) => { - orders.perform_cmd(read_incoming(incoming)); - orders.skip(); - return; - } - WebSocketChanged::WsMsg(ws_msg) => { - ws::update(ws_msg, model, orders); - orders.skip(); - return; - } - WebSocketChanged::WebSocketMessageLoaded(v) => { - match bincode::deserialize(v.as_slice()) { - Ok(WsMsg::Ping | WsMsg::Pong) => { - orders.skip().perform_cmd(cmds::timeout(300, || { - Msg::WebSocketChange(WebSocketChanged::SendPing) - })); - } - Ok(m) => { - log::info!("INCOMING {:?}", m); - orders - .skip() - .send_msg(Msg::WebSocketChange(WebSocketChanged::WsMsg(m))); - } - _ => (), - }; - return; - } - WebSocketChanged::WebSocketClosed => { - open_socket(model, orders); - return; - } - WebSocketChanged::Bounced(ws_msg) => { - model.ws_queue.push(ws_msg); - open_socket(model, orders); - return; - } - }; - } + Msg::WebSocketChange(change) => match change { + WebSocketChanged::WebSocketOpened => { + flush_queue(model, orders); + send_ws_msg(WsMsg::Ping, model.ws.as_ref(), orders); + authorize_or_redirect(model, orders); + orders.skip(); + return; + } + WebSocketChanged::SendPing => { + send_ws_msg(WsMsg::Ping, model.ws.as_ref(), orders); + orders.skip(); + return; + } + WebSocketChanged::WebSocketMessage(incoming) => { + orders.perform_cmd(read_incoming(incoming)); + orders.skip(); + return; + } + WebSocketChanged::WsMsg(mut ws_msg) => { + ws::update(&mut ws_msg, model, orders); + orders.skip(); + Msg::WebSocketChange(WebSocketChanged::WsMsg(ws_msg)) + } + WebSocketChanged::WebSocketMessageLoaded(v) => { + match bincode::deserialize(v.as_slice()) { + Ok(WsMsg::Ping | WsMsg::Pong) => { + orders.skip().perform_cmd(cmds::timeout(300, || { + Msg::WebSocketChange(WebSocketChanged::SendPing) + })); + } + Ok(m) => { + log::info!("INCOMING {:?}", m); + orders + .skip() + .send_msg(Msg::WebSocketChange(WebSocketChanged::WsMsg(m))); + } + _ => (), + }; + return; + } + WebSocketChanged::WebSocketClosed => { + open_socket(model, orders); + return; + } + WebSocketChanged::Bounced(ws_msg) => { + model.ws_queue.push(ws_msg); + open_socket(model, orders); + return; + } + }, _ => msg, }; diff --git a/web/src/location.rs b/web/src/location.rs index e9ca6054..446610d1 100644 --- a/web/src/location.rs +++ b/web/src/location.rs @@ -1,14 +1,41 @@ -pub fn host_url() -> &'static str { - if cfg!(debug_assertions) { - "http://localhost:5000" - } else { - "https://localhost:5000" +static mut HOST: String = String::new(); +static mut WS: String = String::new(); + +fn ensure_host() { + unsafe { + if HOST.is_empty() { + HOST = format!( + "{}//{}", + seed::window().location().protocol().unwrap(), + seed::window().location().host().unwrap() + ); + let host: String = seed::window().location().host().unwrap(); + let is_local = host.ends_with("lvh.me") + || host.contains("localhost") + || host.starts_with("127.") + || host.contains("0.0.0.0"); + WS = format!( + "{}//{}/ws/", + match seed::window().location().protocol().unwrap().as_str() { + "http:" => "ws:", + _ => "wss:", + }, + if is_local { + "localhost:5000" + } else { + host.as_str() + } + ); + } } } + +pub fn host_url() -> &'static str { + ensure_host(); + unsafe { HOST.as_str() } +} + pub fn ws_url() -> &'static str { - if cfg!(debug_assertions) { - "ws://localhost:5000/ws/" - } else { - "wss://localhost:5000/ws/" - } -} \ No newline at end of file + ensure_host(); + unsafe { WS.as_str() } +} diff --git a/web/src/modals/update.rs b/web/src/modals/update.rs index 881f877d..60cf7628 100644 --- a/web/src/modals/update.rs +++ b/web/src/modals/update.rs @@ -113,7 +113,10 @@ fn push_modal(modal_type: &ModalType, model: &mut Model, orders: &mut impl Order } fn drop_modal(model: &mut Model, orders: &mut impl Orders) { - let modal = model.modal_stack_mut().pop().unwrap(); + let modal = match model.modal_stack_mut().pop() { + Some(modal) => modal, + _ => return, + }; let modals = model.modals_mut(); match modal { ModalType::AddIssue(_) => { diff --git a/web/src/ws/mod.rs b/web/src/ws/mod.rs index c4910fbe..eb80c12a 100644 --- a/web/src/ws/mod.rs +++ b/web/src/ws/mod.rs @@ -45,9 +45,10 @@ pub fn send_ws_msg(msg: WsMsg, ws: Option<&WebSocket>, orders: &mut impl Orders< return; } }; - let binary = bincode::serialize(&msg).unwrap(); - ws.send_bytes(binary.as_slice()) - .expect("Failed to send ws msg"); + let binary = bincode::serialize(&msg).unwrap_or_default(); + if let Err(e) = ws.send_bytes(binary.as_slice()) { + log::error!("Failed to send ws msg. {:?}", e); + } } pub fn open_socket(model: &mut Model, orders: &mut impl Orders) { @@ -92,12 +93,12 @@ pub async fn read_incoming(msg: WebSocketMessage) -> Msg { Msg::WebSocketChange(WebSocketChanged::WebSocketMessageLoaded(bytes)) } -pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { +pub fn update(msg: &mut WsMsg, model: &mut Model, orders: &mut impl Orders) { match msg { // auth WsMsg::Session(WsMsgSession::AuthorizeLoaded(Ok((user, setting)))) => { - model.user = Some(user); - model.user_settings = Some(setting); + model.user = Some(user.clone()); + model.user_settings = Some(setting.clone()); if is_non_logged_area() { go_to_board(orders); @@ -134,7 +135,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { } // project WsMsg::Project(WsMsgProject::ProjectsLoaded(v)) => { - model.projects = v; + model.projects = std::mem::take(v); init_current_project(model, orders); orders.send_msg(Msg::ResourceChanged( ResourceKind::Project, @@ -145,7 +146,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { // user projects WsMsg::UserProjectsLoaded(v) => { model.current_user_project = v.iter().find(|up| up.is_current).cloned(); - model.user_projects = v; + model.user_projects = std::mem::take(v); init_current_project(model, orders); orders.send_msg(Msg::ResourceChanged( ResourceKind::UserProject, @@ -160,7 +161,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { up.is_current = up.id == user_project.id; model.user_projects.push(up); } - model.current_user_project = Some(user_project); + model.current_user_project = Some(user_project.clone()); init_current_project(model, orders); orders.send_msg(Msg::ResourceChanged( ResourceKind::UserProject, @@ -170,23 +171,23 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { } // user settings WsMsg::User(WsMsgUser::AvatarUrlChanged(id, url)) => { - if let Some(user) = model.user.as_mut().filter(|u| u.id == id) { + if let Some(user) = model.user.as_mut().filter(|u| u.id == *id) { user.avatar_url = Some(url.clone()); } if let Some(user) = model.users_by_id.get_mut(&id) { user.avatar_url = Some(url.clone()); } - if let Some(user) = model.users.iter_mut().find(|u| u.id == id) { - user.avatar_url = Some(url); + if let Some(user) = model.users.iter_mut().find(|u| u.id == *id) { + user.avatar_url = Some(url.clone()); } orders.send_msg(Msg::ResourceChanged( ResourceKind::User, OperationKind::SingleModified, - Some(id), + Some(*id), )); } WsMsg::User(WsMsgUser::UserSettingUpdated(setting)) => { - model.user_settings = Some(setting); + model.user_settings = Some(setting.clone()); orders.send_msg(Msg::ResourceChanged( ResourceKind::UserSetting, OperationKind::SingleModified, @@ -196,7 +197,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { // issue statuses WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusesLoaded(v)) => { - model.issue_statuses = v; + model.issue_statuses = std::mem::take(v); model .issue_statuses .sort_by(|a, b| a.position.cmp(&b.position)); @@ -208,7 +209,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { } WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusCreated(is)) => { let id = is.id; - model.issue_statuses.push(is); + model.issue_statuses.push(is.clone()); model .issue_statuses .sort_by(|a, b| a.position.cmp(&b.position)); @@ -218,10 +219,10 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { Some(id), )); } - WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusUpdated(mut changed)) => { + WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusUpdated(changed)) => { let id = changed.id; if let Some(idx) = model.issue_statuses.iter().position(|c| c.id == changed.id) { - std::mem::swap(&mut model.issue_statuses[idx], &mut changed); + std::mem::swap(&mut model.issue_statuses[idx], changed); } model .issue_statuses @@ -236,7 +237,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { let mut old = vec![]; std::mem::swap(&mut model.issue_statuses, &mut old); for is in old { - if is.id != dropped_id { + if is.id != *dropped_id { model.issue_statuses.push(is); } } @@ -246,11 +247,11 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { orders.send_msg(Msg::ResourceChanged( ResourceKind::IssueStatus, OperationKind::SingleRemoved, - Some(dropped_id), + Some(*dropped_id), )); } // issues - WsMsg::Project(WsMsgProject::ProjectIssuesLoaded(mut v)) => { + WsMsg::Project(WsMsgProject::ProjectIssuesLoaded(v)) => { v.sort_by(|a, b| (a.list_position as i64).cmp(&(b.list_position as i64))); { let _ = std::mem::replace(model.issues_mut(), v.clone()); @@ -266,12 +267,24 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { None, )); } + WsMsg::Issue(WsMsgIssue::IssueCreated(issue)) => { + let id = issue.id; + model.issues_by_id.insert(id, issue.clone()); + if let Some(idx) = model.issues().iter().position(|i| i.id == issue.id) { + let _ = std::mem::replace(&mut model.issues_mut()[idx], issue.clone()); + } + orders.send_msg(Msg::ResourceChanged( + ResourceKind::Issue, + OperationKind::SingleCreated, + Some(id), + )); + } WsMsg::Issue(WsMsgIssue::IssueUpdated(issue)) => { let id = issue.id; model.issues_by_id.remove(&id); model.issues_by_id.insert(id, issue.clone()); if let Some(idx) = model.issues().iter().position(|i| i.id == issue.id) { - let _ = std::mem::replace(&mut model.issues_mut()[idx], issue); + let _ = std::mem::replace(&mut model.issues_mut()[idx], issue.clone()); } orders.send_msg(Msg::ResourceChanged( ResourceKind::Issue, @@ -280,10 +293,9 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { )); } WsMsg::Issue(WsMsgIssue::IssueDeleted(id, _count)) => { - let mut old = vec![]; - std::mem::swap(model.issues_mut(), &mut old); + let old = std::mem::take(model.issues_mut()); for is in old { - if is.id == id { + if is.id == *id { continue; } model.issues_mut().push(is); @@ -291,7 +303,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { orders.send_msg(Msg::ResourceChanged( ResourceKind::Issue, OperationKind::SingleRemoved, - Some(id), + Some(*id), )); } // users @@ -308,7 +320,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { )); } // comments - WsMsg::Comment(WsMsgComment::IssueCommentsLoaded(mut comments)) => { + WsMsg::Comment(WsMsgComment::IssueCommentsLoaded(comments)) => { let issue_id = match &model.modals().edit_issue { Some(modal) => modal.id, _ => return, @@ -318,7 +330,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { } comments.sort_by(|a, b| a.updated_at.cmp(&b.updated_at)); model.comments = comments.clone(); - for comment in comments { + for comment in std::mem::take(comments) { model.comments_by_id.insert(comment.id, comment); } orders.send_msg(Msg::ResourceChanged( @@ -331,7 +343,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { let comment_id = comment.id; if let Some(idx) = model.comments.iter().position(|c| c.id == comment.id) { let _ = std::mem::replace(&mut model.comments[idx], comment.clone()); - model.comments_by_id.insert(comment.id, comment); + model.comments_by_id.insert(comment.id, comment.clone()); } orders.send_msg(Msg::ResourceChanged( ResourceKind::Comment, @@ -340,20 +352,20 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { )); } WsMsg::Comment(WsMsgComment::CommentDeleted(comment_id, _count)) => { - if let Some(idx) = model.comments.iter().position(|c| c.id == comment_id) { + if let Some(idx) = model.comments.iter().position(|c| c.id == *comment_id) { model.comments.remove(idx); } model.comments_by_id.remove(&comment_id); orders.send_msg(Msg::ResourceChanged( ResourceKind::Comment, OperationKind::SingleRemoved, - Some(comment_id), + Some(*comment_id), )); } // messages - WsMsg::Message(WsMsgMessage::MessageUpdated(mut received)) => { + WsMsg::Message(WsMsgMessage::MessageUpdated(received)) => { if let Some(idx) = model.messages.iter().position(|m| m.id == received.id) { - std::mem::swap(&mut model.messages[idx], &mut received); + std::mem::swap(&mut model.messages[idx], received); } model.messages.sort_by(|a, b| a.id.cmp(&b.id)); orders.send_msg(Msg::ResourceChanged( @@ -363,7 +375,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { )); } WsMsg::Message(WsMsgMessage::MessagesLoaded(v)) => { - model.messages = v; + model.messages = std::mem::take(v); model.messages.sort_by(|a, b| a.id.cmp(&b.id)); orders.send_msg(Msg::ResourceChanged( ResourceKind::Message, @@ -372,14 +384,14 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { )); } WsMsg::Message(WsMsgMessage::MessageMarkedSeen(id, _count)) => { - if let Some(idx) = model.messages.iter().position(|m| m.id == id) { + if let Some(idx) = model.messages.iter().position(|m| m.id == *id) { model.messages.remove(idx); } model.messages.sort_by(|a, b| a.id.cmp(&b.id)); orders.send_msg(Msg::ResourceChanged( ResourceKind::Message, OperationKind::SingleRemoved, - Some(id), + Some(*id), )); } @@ -387,7 +399,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { WsMsg::Epic(WsMsgEpic::EpicsLoaded(epics)) => { model.epics = epics.clone(); for epic in epics { - model.epics_by_id.insert(epic.id, epic); + model.epics_by_id.insert(epic.id, epic.clone()); } orders.send_msg(Msg::ResourceChanged( ResourceKind::Epic, @@ -399,7 +411,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { let id = epic.id; model.epics.push(epic.clone()); model.epics.sort_by(|a, b| a.id.cmp(&b.id)); - model.epics_by_id.insert(epic.id, epic); + model.epics_by_id.insert(epic.id, epic.clone()); orders.send_msg(Msg::ResourceChanged( ResourceKind::Epic, OperationKind::SingleCreated, @@ -411,7 +423,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { if let Some(idx) = model.epics.iter().position(|e| e.id == epic.id) { let _ = std::mem::replace(&mut model.epics[idx], epic.clone()); } - model.epics_by_id.insert(epic.id, epic); + model.epics_by_id.insert(epic.id, epic.clone()); model.epics.sort_by(|a, b| a.id.cmp(&b.id)); orders.send_msg(Msg::ResourceChanged( ResourceKind::Epic, @@ -420,7 +432,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { )); } WsMsg::Epic(WsMsgEpic::EpicDeleted(id, _count)) => { - if let Some(idx) = model.epics.iter().position(|e| e.id == id) { + if let Some(idx) = model.epics.iter().position(|e| e.id == *id) { model.epics.remove(idx); } model.epics_by_id.remove(&id); @@ -428,7 +440,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { orders.send_msg(Msg::ResourceChanged( ResourceKind::Epic, OperationKind::SingleRemoved, - Some(id), + Some(*id), )); } WsMsg::Session(WsMsgSession::AuthenticateSuccess) => { @@ -436,7 +448,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders) { page.login_success = true; } WsMsg::Session(WsMsgSession::BindTokenOk(access_token)) => { - match write_auth_token(Some(access_token)) { + match write_auth_token(Some(*access_token)) { Ok(msg) => { orders.skip().send_msg(msg); }