use std::{str::FromStr, sync::Arc}; use filamento::{db::Db, error::{CommandError, ConnectionError}, files::{opfs::OPFSError, FilesMem, FilesOPFS}, UpdateMessage}; use jid::JID; use thiserror::Error; use leptos::prelude::*; use tokio::sync::mpsc::Receiver; use tracing::debug; use crate::{client::Client, files::Files}; use super::AppState; #[derive(Clone, Debug, Error)] pub enum LoginError { #[error("Missing Password")] MissingPassword, #[error("Missing JID")] MissingJID, #[error("Invalid JID: {0}")] InvalidJID(#[from] jid::ParseError), #[error("Connection Error: {0}")] ConnectionError(#[from] CommandError), #[error("OPFS: {0}")] OPFS(#[from] OPFSError), } #[component] pub fn LoginPage( set_app: WriteSignal, set_client: WriteSignal)>>, ) -> impl IntoView { let jid = RwSignal::new("".to_string()); let password = RwSignal::new("".to_string()); let remember_me = RwSignal::new(false); let connect_on_login = RwSignal::new(true); let (error, set_error) = signal(None::); let error_message = move || { error.with(|error| { if let Some(error) = error { view! {
{error.to_string()}
}.into_any() } else { view! {}.into_any() } }) }; let (login_pending, set_login_pending) = signal(false); let login = Action::new_local(move |_| { async move { set_login_pending.set(true); if jid.read_untracked().is_empty() { set_error.set(Some(LoginError::MissingJID)); set_login_pending.set(false); return; } if password.read_untracked().is_empty() { set_error.set(Some(LoginError::MissingPassword)); set_login_pending.set(false); return; } let jid = match JID::from_str(&jid.read_untracked()) { Ok(j) => j, Err(e) => { set_error.set(Some(e.into())); set_login_pending.set(false); return; } }; let remember_me = remember_me.get_untracked(); // initialise the client let db = if remember_me { debug!("creating db in opfs"); Db::create_connect_and_migrate(jid.as_bare().to_string()) .await .unwrap() } else { debug!("creating db in memory"); Db::create_connect_and_migrate_memory().await.unwrap() }; let files = if remember_me { let opfs = FilesOPFS::new(jid.as_bare().to_string()).await; match opfs { Ok(f) => Files::Opfs(f), Err(e) => { set_error.set(Some(e.into())); set_login_pending.set(false); return; } } } else { Files::Mem(FilesMem::new()) }; let (client, updates) = filamento::Client::new( jid.clone(), password.read_untracked().clone(), db, files.clone(), ); let resource = ArcRwSignal::new(None::); let client = Client { client, resource: resource.clone(), jid: Arc::new(jid.to_bare()), file_store: files, }; if *connect_on_login.read_untracked() { match client.connect().await { Ok(r) => { resource.set(Some(r)) } Err(e) => { set_error.set(Some(e.into())); set_login_pending.set(false); return; } } } // debug!("before setting app state"); set_client.set(Some((client, updates))); set_app.set(AppState::LoggedIn); } }); view! {

Macaw Instant Messenger

{error_message}
} }