aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-03-01 09:11:52 +0000
committerLibravatar cel 🌸 <cel@bunny.garden>2025-03-01 09:11:52 +0000
commitd0e122655926504cc2a29e7239cb88fddaed9c76 (patch)
treeb35890405c1ebe70e45c5101f4400c528e0c38ef
parent18e907386d629966236d0b6a30501f492133d2f6 (diff)
downloadmacaw-d0e122655926504cc2a29e7239cb88fddaed9c76.tar.gz
macaw-d0e122655926504cc2a29e7239cb88fddaed9c76.tar.bz2
macaw-d0e122655926504cc2a29e7239cb88fddaed9c76.zip
feat: store user data in correct dir, or according to config
-rw-r--r--Cargo.lock39
-rw-r--r--Cargo.toml1
-rw-r--r--src/login_modal.rs86
-rw-r--r--src/main.rs160
4 files changed, 191 insertions, 95 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 128f43a..bf79759 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -842,7 +842,7 @@ checksum = "2a76fa97167fa740dcdbfe18e8895601e1bc36525f09b044e00916e717c03a3c"
dependencies = [
"dconf_rs",
"detect-desktop-environment",
- "dirs",
+ "dirs 4.0.0",
"objc",
"rust-ini",
"web-sys",
@@ -934,13 +934,22 @@ dependencies = [
]
[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys 0.5.0",
+]
+
+[[package]]
name = "dirs-sys"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
- "redox_users",
+ "redox_users 0.4.6",
"winapi",
]
@@ -952,11 +961,23 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
- "redox_users",
+ "redox_users 0.4.6",
"windows-sys 0.48.0",
]
[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users 0.5.0",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2334,6 +2355,7 @@ name = "macaw"
version = "0.1.0"
dependencies = [
"confy",
+ "dirs 6.0.0",
"iced",
"indexmap",
"jid",
@@ -3459,6 +3481,17 @@ dependencies = [
]
[[package]]
+name = "redox_users"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
+dependencies = [
+ "getrandom 0.2.15",
+ "libredox",
+ "thiserror 2.0.11",
+]
+
+[[package]]
name = "renderdoc-sys"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 3d1dcbe..50bbf16 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,3 +18,4 @@ indexmap = "2.7.1"
serde = { version = "1.0.218", features = ["derive"] }
thiserror = "2.0.11"
toml = "0.8"
+dirs = "6.0.0"
diff --git a/src/login_modal.rs b/src/login_modal.rs
index 02d878e..5a63158 100644
--- a/src/login_modal.rs
+++ b/src/login_modal.rs
@@ -34,16 +34,16 @@ pub enum Message {
#[derive(Debug, Clone)]
pub enum Error {
- InvalidJID(String),
- DatabaseConnection,
+ InvalidJID,
}
pub enum Action {
None,
ClientCreated(Task<crate::Message>),
+ CreateClient(String, String, bool),
}
-#[derive(Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Clone)]
pub struct Creds {
pub jid: String,
pub password: String,
@@ -69,85 +69,7 @@ impl LoginModal {
let jid_str = self.jid.clone();
let password = self.password.clone();
let remember_me = self.remember_me.clone();
- Action::ClientCreated(
- Task::future(async move {
- let jid: Result<JID, _> = jid_str.parse();
- match jid {
- Ok(j) => {
- let result =
- LuzHandle::new(j.clone(), password.to_string(), "macaw.db")
- .await;
- match result {
- Ok((luz_handle, receiver)) => {
- let mut tasks = Vec::new();
- tasks.push(Task::done(crate::Message::ClientCreated(
- Client {
- client: luz_handle,
- jid: j,
- connection_status: Presence::Offline(
- Offline::default(),
- ),
- },
- )));
- let stream = ReceiverStream::new(receiver);
- let stream =
- stream.map(|message| crate::Message::Luz(message));
- tasks.push(Task::stream(stream));
-
- if remember_me {
- let entry = Entry::new("macaw", "macaw");
- match entry {
- Ok(e) => {
- let creds = Creds {
- jid: jid_str,
- password,
- };
- let creds = toml::to_string(&creds);
- match creds {
- Ok(c) => {
- let result = e.set_password(&c);
- if let Err(e) = result {
- tasks.push(Task::done(crate::Message::Error(
- crate::Error::CredentialsSave(e.into()),
- )));
- }
- }
- Err(e) => tasks.push(Task::done(
- crate::Message::Error(
- crate::Error::CredentialsSave(
- e.into(),
- ),
- ),
- )),
- }
- }
- Err(e) => {
- tasks.push(Task::done(crate::Message::Error(
- crate::Error::CredentialsSave(e.into()),
- )))
- }
- }
- }
- tasks
- }
- Err(_e) => {
- tracing::error!("error (database probably)");
- return vec![Task::done(crate::Message::LoginModal(
- Message::Error(Error::DatabaseConnection),
- ))];
- }
- }
- }
- Err(_) => {
- tracing::error!("parsing jid");
- return vec![Task::done(crate::Message::LoginModal(
- Message::Error(Error::InvalidJID(jid_str.to_string())),
- ))];
- }
- }
- })
- .then(|tasks| Task::batch(tasks)),
- )
+ Action::CreateClient(jid_str, password, remember_me)
}
Message::Error(error) => {
self.error = Some(error);
diff --git a/src/main.rs b/src/main.rs
index 558c608..27314ae 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,6 +2,8 @@ use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
+use std::path::PathBuf;
+use std::str::FromStr;
use std::sync::Arc;
use iced::futures::{SinkExt, Stream, StreamExt};
@@ -30,14 +32,20 @@ use uuid::Uuid;
mod login_modal;
-#[derive(Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Clone)]
pub struct Config {
auto_connect: bool,
+ storage_dir: Option<String>,
+ dburl: Option<String>,
}
impl Default for Config {
fn default() -> Self {
- Self { auto_connect: true }
+ Self {
+ auto_connect: true,
+ storage_dir: None,
+ dburl: None,
+ }
}
}
@@ -109,6 +117,42 @@ impl Deref for Client {
}
}
+async fn luz(jid: &JID, creds: &Creds, cfg: &Config) -> (LuzHandle, mpsc::Receiver<UpdateMessage>) {
+ let luz;
+ if let Some(ref dburl) = cfg.dburl {
+ // TODO: have some sort of crash popup for this stuff
+ let db_path = dburl.strip_prefix("sqlite://").unwrap_or(&dburl);
+ let db_path = PathBuf::from_str(db_path).expect("invalid database path");
+ let db = luz::db::Db::create_connect_and_migrate(db_path)
+ .await
+ .unwrap();
+ luz = LuzHandle::new(jid.clone(), creds.password.to_string(), db);
+ } else if let Some(ref dir) = cfg.storage_dir {
+ let mut data_dir = PathBuf::from_str(&dir).expect("invalid storage directory path");
+ data_dir.push(creds.jid.clone());
+ data_dir.push(creds.jid.clone());
+ data_dir.set_extension("db");
+ let db = luz::db::Db::create_connect_and_migrate(data_dir)
+ .await
+ .unwrap();
+ luz = LuzHandle::new(jid.clone(), creds.password.to_string(), db);
+ } else {
+ let mut data_dir = dirs::data_dir()
+ .expect("operating system does not support retreiving determining default data dir");
+ data_dir.push("macaw");
+ data_dir.push(creds.jid.clone());
+ data_dir.push(creds.jid.clone());
+ // TODO: better lol
+ data_dir.set_extension("db");
+ info!("db_path: {:?}", data_dir);
+ let db = luz::db::Db::create_connect_and_migrate(data_dir)
+ .await
+ .unwrap();
+ luz = LuzHandle::new(jid.clone(), creds.password.to_string(), db);
+ }
+ luz
+}
+
#[tokio::main]
async fn main() -> iced::Result {
tracing_subscriber::fmt::init();
@@ -154,11 +198,8 @@ async fn main() -> iced::Result {
let jid = creds.jid.parse::<JID>();
match jid {
Ok(jid) => {
- let luz = LuzHandle::new(jid.clone(), creds.password.to_string(), "macaw.db").await;
- match luz {
- Ok((handle, recv)) => client = Some((jid.as_bare(), handle, recv)),
- Err(e) => client_creation_error = Some(Error::ClientCreation(e)),
- }
+ let (handle, updates) = luz(&jid, &creds, &cfg).await;
+ client = Some((jid, handle, updates));
}
Err(e) => client_creation_error = Some(Error::CredentialsLoad(e.into())),
}
@@ -168,10 +209,43 @@ async fn main() -> iced::Result {
let stream = ReceiverStream::new(update_recv);
let stream = stream.map(|message| Message::Luz(message));
let task = {
+ let luz_handle1 = luz_handle.clone();
+ let luz_handle2 = luz_handle.clone();
if cfg.auto_connect {
- Task::batch([Task::stream(stream), Task::done(Message::Connect)])
+ Task::batch([
+ Task::perform(async move { luz_handle1.get_roster().await }, |result| {
+ let roster = result.unwrap();
+ let mut macaw_roster = HashMap::new();
+ for contact in roster {
+ macaw_roster.insert(contact.user_jid.clone(), contact);
+ }
+ Message::Roster(macaw_roster)
+ }),
+ Task::perform(async move { luz_handle2.get_chats().await }, |chats| {
+ let chats = chats.unwrap();
+ info!("got chats: {:?}", chats);
+ Message::GotChats(chats)
+ }),
+ Task::stream(stream),
+ Task::done(Message::Connect),
+ ])
} else {
- Task::stream(stream)
+ Task::batch([
+ Task::perform(async move { luz_handle1.get_roster().await }, |result| {
+ let roster = result.unwrap();
+ let mut macaw_roster = HashMap::new();
+ for contact in roster {
+ macaw_roster.insert(contact.user_jid.clone(), contact);
+ }
+ Message::Roster(macaw_roster)
+ }),
+ Task::perform(async move { luz_handle2.get_chats().await }, |chats| {
+ let chats = chats.unwrap();
+ info!("got chats: {:?}", chats);
+ Message::GotChats(chats)
+ }),
+ Task::stream(stream),
+ ])
}
};
iced::application("Macaw", Macaw::update, Macaw::view).run_with(|| {
@@ -185,7 +259,6 @@ async fn main() -> iced::Result {
}),
cfg,
),
- // TODO: autoconnect config
task,
)
})
@@ -345,6 +418,7 @@ impl Macaw {
// .into_iter()
// .map(|chat| (chat.correspondent.clone(), (chat, IndexMap::new())))
// .collect();
+ info!("got chats: {:?}", chats);
Message::GotChats(chats)
}),
Task::done(Message::Connect),
@@ -365,6 +439,7 @@ impl Macaw {
// .into_iter()
// .map(|chat| (chat.correspondent.clone(), (chat, IndexMap::new())))
// .collect();
+ info!("got chats: {:?}", chats);
Message::GotChats(chats)
}),
])
@@ -409,6 +484,71 @@ impl Macaw {
let action = login_modal.update(login_modal_message);
match action {
login_modal::Action::None => Task::none(),
+ login_modal::Action::CreateClient(jid, password, remember_me) => {
+ let creds = Creds { jid, password };
+ let jid = creds.jid.parse::<JID>();
+ let config = self.config.clone();
+ match jid {
+ Ok(jid) => {
+ Task::perform(async move {
+ let (jid, creds, config) = (jid, creds, config);
+ let (handle, recv) = luz(&jid, &creds, &config).await;
+ (handle, recv, jid, creds, config)
+ }, move |(handle, recv, jid, creds, config)| {
+ let creds = creds;
+ let mut tasks = Vec::new();
+ tasks.push(Task::done(crate::Message::ClientCreated(
+ Client {
+ client: handle,
+ jid,
+ connection_status: Presence::Offline(
+ Offline::default(),
+ ),
+ },
+ )));
+ let stream = ReceiverStream::new(recv);
+ let stream =
+ stream.map(|message| crate::Message::Luz(message));
+ tasks.push(Task::stream(stream));
+
+ if remember_me {
+ let entry = Entry::new("macaw", "macaw");
+ match entry {
+ Ok(e) => {
+ let creds = toml::to_string(&creds);
+ match creds {
+ Ok(c) => {
+ let result = e.set_password(&c);
+ if let Err(e) = result {
+ tasks.push(Task::done(crate::Message::Error(
+ crate::Error::CredentialsSave(e.into()),
+ )));
+ }
+ }
+ Err(e) => tasks.push(Task::done(
+ crate::Message::Error(
+ crate::Error::CredentialsSave(
+ e.into(),
+ ),
+ ),
+ )),
+ }
+ }
+ Err(e) => {
+ tasks.push(Task::done(crate::Message::Error(
+ crate::Error::CredentialsSave(e.into()),
+ )))
+ }
+ }
+ }
+ tasks
+ }).then(|tasks| Task::batch(tasks))
+ }
+ Err(e) => Task::done(Message::LoginModal(
+ login_modal::Message::Error(login_modal::Error::InvalidJID),
+ )),
+ }
+ }
login_modal::Action::ClientCreated(task) => task,
}
}