use openworm::net::{CreateAccount, CreateAccountResp, Login, LoginResp}; use crate::{ data::{AccountInfo, ClientData, ServerInfo, ServerList}, net::{ConnectInfo, NetHandle}, session::Session, }; use super::*; pub fn start(rsc: &mut Rsc, data: &ClientData) -> WeakWidget { let mut accounts = Span::empty(Dir::DOWN); let accts = data.accounts(); if accts.is_empty() { accounts.push( wtext("no accounts") .size(20) .center_text() .color(Color::GRAY) .height(60) .add_strong(rsc), ); } else { for account in accts.iter() { let button = Button::new_fg( wtext(&account.username) .size(20) .center_text() .height(60) .add(rsc), color::DARK, rsc, ) .add(rsc); let account = account.clone(); let cert_hex = data .data .load::() .get(&account.url) .unwrap() .cert_hex .clone(); let cert = decode_hex(&cert_hex).unwrap(); keyring::use_native_store(true).unwrap(); rsc.events.register(button, Submit, move |ctx, rsc| { let account = account.clone(); let cert = cert.clone(); let password = ctx.state.data.password(&account); rsc.spawn_task(async move |mut ctx| { let mut fail = |reason: &str| { let reason = reason.to_string(); ctx.update(move |ctx, rsc| { ctx.error(&reason, rsc); }) }; let con = match NetHandle::connect( async |msg| { println!("msg recv :joy:"); }, ConnectInfo { url: account.url.clone(), cert, }, ) .await { Ok(v) => v, Err(e) => { return fail(&e); } }; let Ok(resp) = con .request(Login { username: account.username.clone(), password: password.clone(), }) .await else { return fail("failed to create account"); }; let user_id = match resp { LoginResp::Ok { id } => id, LoginResp::UnknownUsername => { return fail("unknown username"); } LoginResp::InvalidPassword => { return fail("invalid password"); } }; let session = Session { con, user_id }; ctx.update(move |ctx, rsc| { main_view(rsc, session).set_ptr(ctx.main_ui, rsc); }); }); }); accounts.push(button.add_strong(rsc)); } } let connect = Button::submit("connect", rsc); let create = Button::submit("create", rsc); rsc.events.register(connect, Submit, move |_, rsc| { connect.disable(rsc); create.disable(rsc); }); rsc.events.register(create, Submit, move |ctx, rsc| { create_account(rsc).set_ptr(ctx.state.main_ui, rsc); }); ( wtext("Select Account").text_align(Align::CENTER).size(30), accounts, (connect, create).span(Dir::RIGHT).gap(10), ) .span(Dir::DOWN) .gap(30) .modal(400) .add(rsc) } pub fn create_account(rsc: &mut Rsc) -> WeakWidget { let url = field("", "server").add(rsc); let token = field("", "account creation token").add(rsc); let cert = field("", "certificate hex").add(rsc); let username = field("", "username").add(rsc); let password = field("", "password").add(rsc); let create = Button::submit("create", rsc); rsc.events.register(create, Submit, move |ctx, rsc| { let url = rsc[url].content().trim().to_string(); let token = rsc[token].content().trim().to_string(); let cert_hex = rsc[cert].content().trim().to_string(); let Some(cert) = decode_hex(&cert_hex) else { rsc[ctx.state.notif].inner = Some(werror("Invalid certificate hex", rsc)); return; }; let username = rsc[username].content(); let password = rsc[password].content(); create.disable(rsc); rsc.spawn_task(async move |mut ctx| { let mut fail = |reason: &str| { let reason = reason.to_string(); ctx.update(move |ctx, rsc| { ctx.error(&reason, rsc); create.enable(rsc); }) }; keyring::use_native_store(true).unwrap(); let con = match NetHandle::connect( async |msg| { println!("msg recv :joy:"); }, ConnectInfo { url: url.clone(), cert, }, ) .await { Ok(v) => v, Err(e) => { return fail(&e); } }; let Ok(resp) = con .request(CreateAccount { username: username.clone(), password: password.clone(), token, }) .await else { return fail("failed to create account"); }; let user_id = match resp { CreateAccountResp::Ok { id } => id, CreateAccountResp::UsernameExists => { return fail("username already exists"); } CreateAccountResp::InvalidToken => { return fail("invalid account token"); } }; let session = Session { con, user_id }; ctx.update(move |ctx, rsc| { main_view(rsc, session).set_ptr(ctx.main_ui, rsc); ctx.data.create_account( ServerInfo { cert_hex }, AccountInfo { url, username }, &password, ); }); }); }); ( wtext("Create Account").text_align(Align::CENTER).size(30), field_box(url), field_box(token), field_box(cert), field_box(username), field_box(password), create, ) .span(Dir::DOWN) .gap(15) .modal(400) .add(rsc) } pub fn decode_hex(s: &str) -> Option> { if !s.len().is_multiple_of(2) { return None; } (0..s.len()) .step_by(2) .map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok()) .collect() }