Files
openworm/src/bin/client/ui/connect.rs
2026-02-21 00:19:57 -05:00

225 lines
7.2 KiB
Rust

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::<ServerList>()
.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<Vec<u8>> {
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()
}