Logging in and Signing up on the client done

Tons of bug fixes too
This commit is contained in:
2024-10-12 01:28:24 -04:00
Unverified
parent 50c0d6a051
commit dc454ccf3a
18 changed files with 367 additions and 181 deletions

View File

@@ -1,3 +1,8 @@
use tokio::sync::broadcast;
use tokio::sync::broadcast::{Receiver, Sender};
use tracing::log::info;
use realm_shared::types::ErrorCode;
use crate::types::ClientUser;
use crate::ui::panels;
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
@@ -9,9 +14,32 @@ pub struct TemplateApp {
pub selected: bool,
pub selected_serverid: Option<String>,
pub selected_roomid: Option<String>,
pub current_user: Option<ClientUser>,
#[serde(skip)] // This how you opt-out of serialization of a field
#[serde(skip)]
pub value: f32,
#[serde(skip)]
pub login_window_open: bool,
#[serde(skip)]
pub login_window_username: String,
#[serde(skip)]
pub login_window_code: String,
#[serde(skip)]
pub login_window_server_address: String,
#[serde(skip)]
pub login_window_email: String,
#[serde(skip)]
pub login_ready_for_code_input: bool,
#[serde(skip)]
pub signup_window_open: bool,
#[serde(skip)]
pub login_start_channel: (Sender<Result<(), ErrorCode>>, Receiver<Result<(), ErrorCode>>),
#[serde(skip)]
pub login_ending_channel: (Sender<Result<String, ErrorCode>>, Receiver<Result<String, ErrorCode>>),
}
impl Default for TemplateApp {
@@ -22,7 +50,19 @@ impl Default for TemplateApp {
selected: false,
selected_serverid: None,
selected_roomid: None,
current_user: None,
value: 2.7,
login_window_open: false,
login_window_username: String::new(),
login_window_code: String::new(),
login_window_server_address: String::new(),
login_start_channel: broadcast::channel(10),
login_ending_channel: broadcast::channel(10),
login_ready_for_code_input: false,
login_window_email: String::new(),
signup_window_open: false,
}
}
}
@@ -49,8 +89,26 @@ impl eframe::App for TemplateApp {
// Put your widgets into a `SidePanel`, `TopBottomPanel`, `CentralPanel`, `Window` or `Area`.
// For inspiration and more examples, go to https://emilk.github.io/egui
while let Ok(result) = self.login_start_channel.1.try_recv() {
match result {
Ok(_) => self.login_ready_for_code_input = true,
Err(e) => tracing::error!("Error in login/account creation flow: {:?}", e),
}
}
while let Ok(result) = self.login_ending_channel.1.try_recv() {
match result {
Ok(token) => {
info!("Login successful! Token: {token}");
self.login_ready_for_code_input = false;
},
Err(e) => tracing::error!("Error in login flow: {:?}", e),
}
}
// File -> Quit
panels::top_panel(ctx);
panels::top_panel(self, ctx);
panels::servers(self, ctx);

View File

@@ -1,4 +1,5 @@
fn main() -> eframe::Result {
#[tokio::main]
async fn main() -> eframe::Result {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let native_options = eframe::NativeOptions {

View File

@@ -0,0 +1,9 @@
#[derive(serde::Deserialize, serde::Serialize)]
pub struct ClientUser {
pub id: i64,
pub username: String,
pub email: String,
pub avatar: String,
pub servers: Vec<String>,
pub token: String,
}

View File

@@ -1,25 +1,180 @@
use egui::{Context, SelectableLabel};
use tarpc::context;
use tarpc::tokio_serde::formats::Json;
use realm_auth::types::RealmAuthClient;
use realm_shared::types::ErrorCode::RPCError;
use regex::Regex;
use crate::app::TemplateApp;
pub fn top_panel(ctx: &Context) {
pub fn top_panel(app: &mut TemplateApp, ctx: &Context) {
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar:
egui::menu::bar(ui, |ui| {
// NOTE: no File->Quit on web pages!
let is_web = cfg!(target_arch = "wasm32");
if !is_web {
ui.menu_button("File", |ui| {
if ui.button("Quit").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.add_space(16.0);
}
ui.menu_button("File", |ui| {
if ui.button("Sign Up").clicked() {
app.signup_window_open = true;
}
if ui.button("Login").clicked() {
app.login_window_open = true;
}
if ui.button("Logout").clicked() {
// TODO: Logout
}
if ui.button("Quit").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.add_space(16.0);
egui::widgets::global_dark_light_mode_buttons(ui);
});
});
egui::Window::new("Signup")
.open(&mut app.signup_window_open)
.min_size((500.0, 200.0))
.show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label("Server Address: ");
ui.text_edit_singleline(&mut app.login_window_server_address);
});
ui.horizontal(|ui| {
ui.label("Username: ");
ui.text_edit_singleline(&mut app.login_window_username);
});
ui.horizontal(|ui| {
ui.label("Email: ");
ui.text_edit_singleline(&mut app.login_window_email);
});
if ui.button("Create Account").clicked() {
let login_window_server_address = app.login_window_server_address.clone();
let login_window_username = app.login_window_username.clone();
let login_window_email = app.login_window_email.clone();
let send_channel = app.login_start_channel.0.clone();
let _handle = tokio::spawn(async move {
let mut transport = tarpc::serde_transport::tcp::connect(login_window_server_address, Json::default);
transport.config_mut().max_frame_length(usize::MAX);
let result = transport.await;
let connection = match result {
Ok(connection) => connection,
Err(e) => {
tracing::error!("Failed to connect to server: {}", e);
return;
}
};
let client = RealmAuthClient::new(tarpc::client::Config::default(), connection).spawn();
let result = client.create_account_flow(context::current(), login_window_username, login_window_email).await;
match result {
Ok(r) => send_channel.send(r).unwrap(),
Err(_) => send_channel.send(Err(RPCError)).unwrap(),
};
});
ui.close_menu()
}
});
egui::Window::new("Login")
.open(&mut app.login_window_open)
.min_size((500.0, 200.0))
.show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label("Server Address: ");
ui.text_edit_singleline(&mut app.login_window_server_address);
});
ui.horizontal(|ui| {
ui.label("Username: ");
ui.text_edit_singleline(&mut app.login_window_username);
});
if ui.button("Send Login Code").clicked() {
let login_window_server_address = app.login_window_server_address.clone();
let login_window_username = app.login_window_username.clone();
let send_channel = app.login_start_channel.0.clone();
let _handle = tokio::spawn(async move {
let mut transport = tarpc::serde_transport::tcp::connect(login_window_server_address, Json::default);
transport.config_mut().max_frame_length(usize::MAX);
let result = transport.await;
let connection = match result {
Ok(connection) => connection,
Err(e) => {
tracing::error!("Failed to connect to server: {}", e);
return;
}
};
let client = RealmAuthClient::new(tarpc::client::Config::default(), connection).spawn();
let result = client.create_login_flow(context::current(), Some(login_window_username), None).await;
match result {
Ok(r) => send_channel.send(r).unwrap(),
Err(_) => send_channel.send(Err(RPCError)).unwrap(),
};
});
ui.close_menu()
}
});
egui::Window::new("Auth Code")
.open(&mut app.login_ready_for_code_input)
.min_size((500.0, 200.0))
.show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label("Code: ");
if ui.text_edit_singleline(&mut app.login_window_code).changed() {
let re = Regex::new(r"[^0-9]+").unwrap();
app.login_window_code = re.replace_all(&app.login_window_code, "").to_string();
}
});
if ui.button("Login").clicked() {
let login_window_server_address = app.login_window_server_address.clone();
let login_window_code = app.login_window_code.clone();
let login_window_username = app.login_window_username.clone();
let send_channel = app.login_ending_channel.0.clone();
let _handle = tokio::spawn(async move {
let mut transport = tarpc::serde_transport::tcp::connect(login_window_server_address, Json::default);
transport.config_mut().max_frame_length(usize::MAX);
let result = transport.await;
let connection = match result {
Ok(connection) => connection,
Err(e) => {
tracing::error!("Failed to connect to server: {}", e);
return;
}
};
let client = RealmAuthClient::new(tarpc::client::Config::default(), connection).spawn();
let result = client.finish_login_flow(context::current(), login_window_username, login_window_code.parse::<u32>().unwrap()).await;
match result {
Ok(r) => {
send_channel.send(r).unwrap();
}
Err(e) => {
send_channel.send(Err(RPCError)).unwrap();
}
}
});
ui.close_menu()
}
});
}
pub fn servers(app: &mut TemplateApp, ctx: &Context) {