diff options
author | 2025-02-14 23:57:59 +0000 | |
---|---|---|
committer | 2025-02-14 23:57:59 +0000 | |
commit | 0d9e3d27e9b81411b4d4c53e1b1a1c29087d66f3 (patch) | |
tree | 90d6d4db55e281ed2f886c5ad034f28db8dc1b43 /luz/src | |
parent | 8dcdfe405ecafea04b301a16580ab703a10645eb (diff) | |
download | luz-0d9e3d27e9b81411b4d4c53e1b1a1c29087d66f3.tar.gz luz-0d9e3d27e9b81411b4d4c53e1b1a1c29087d66f3.tar.bz2 luz-0d9e3d27e9b81411b4d4c53e1b1a1c29087d66f3.zip |
WIP: data(base)type
Diffstat (limited to '')
-rw-r--r-- | luz/src/chat.rs | 14 | ||||
-rw-r--r-- | luz/src/connection/read.rs | 3 | ||||
-rw-r--r-- | luz/src/lib.rs | 197 | ||||
-rw-r--r-- | luz/src/presence.rs | 4 | ||||
-rw-r--r-- | luz/src/roster.rs | 12 |
5 files changed, 125 insertions, 105 deletions
diff --git a/luz/src/chat.rs b/luz/src/chat.rs index 091b3b6..24ad709 100644 --- a/luz/src/chat.rs +++ b/luz/src/chat.rs @@ -1,3 +1,4 @@ +use jid::JID; use uuid::Uuid; use crate::{roster::Contact, user::User}; @@ -6,22 +7,27 @@ use crate::{roster::Contact, user::User}; pub struct Message { id: Uuid, // contains full user information - from: User, - // TODO: rich text, other contents, threads + from: Correspondent, body: Body, } #[derive(Debug)] pub struct Body { + // TODO: rich text, other contents, threads body: String, } pub struct Chat { - id: Uuid, - user: User, + correspondent: Correspondent, message_history: Vec<Message>, } +#[derive(Debug)] +pub enum Correspondent { + User(User), + Contact(Contact), +} + // TODO: group chats // pub enum Chat { // Direct(DirectChat), diff --git a/luz/src/connection/read.rs b/luz/src/connection/read.rs index c2828ad..d005693 100644 --- a/luz/src/connection/read.rs +++ b/luz/src/connection/read.rs @@ -12,6 +12,7 @@ use tokio::{ sync::{mpsc, oneshot, Mutex}, task::{JoinHandle, JoinSet}, }; +use tracing::info; use crate::{error::Error, UpdateMessage}; @@ -87,7 +88,7 @@ impl Read { // if still haven't received the end tag in time, just kill itself // TODO: is this okay??? what if notification thread dies? Ok(()) = &mut self.disconnect_timedout => { - println!("disconnect_timedout"); + info!("disconnect_timedout"); break; } Some(msg) = self.control_receiver.recv() => { diff --git a/luz/src/lib.rs b/luz/src/lib.rs index 07dc74a..79df494 100644 --- a/luz/src/lib.rs +++ b/luz/src/lib.rs @@ -4,11 +4,11 @@ use std::{ sync::Arc, }; -use chat::{Body, Message}; +use chat::{Body, Chat, Message}; use connection::{write::WriteMessage, SupervisorSender}; use jabber::JID; use presence::{Offline, Online, Presence}; -use roster::Contact; +use roster::{Contact, ContactUpdate}; use sqlx::SqlitePool; use stanza::client::{ iq::{self, Iq, IqType}, @@ -72,89 +72,89 @@ impl Luz { async fn run(mut self) { loop { - tokio::select! { + let msg = tokio::select! { // this is okay, as when created the supervisor (and connection) doesn't exist, but a bit messy _ = &mut self.connection_supervisor_shutdown => { - *self.connected.lock().await = None + *self.connected.lock().await = None; + continue; } Some(msg) = self.receiver.recv() => { - // TODO: consider separating disconnect/connect and commands apart from commandmessage - // TODO: dispatch commands separate tasks - match msg { - CommandMessage::Connect => { - let mut connection_lock = self.connected.lock().await; - match connection_lock.as_ref() { - Some(_) => { - self.sender - .send(UpdateMessage::Error(Error::AlreadyConnected)) - .await; - } - None => { - let mut jid = self.jid.lock().await; - let mut domain = jid.domainpart.clone(); - // TODO: check what happens upon reconnection with same resource (this is probably what one wants to do and why jid should be mutated from a bare jid to one with a resource) - let streams_result = - jabber::connect_and_login(&mut jid, &*self.password, &mut domain) - .await; - match streams_result { - Ok(s) => { - let (shutdown_send, shutdown_recv) = oneshot::channel::<()>(); - let (writer, supervisor) = SupervisorHandle::new( - s, - self.sender.clone(), - self.db.clone(), - shutdown_send, - self.jid.clone(), - self.password.clone(), - self.pending_iqs.clone(), - ); - self.connection_supervisor_shutdown = shutdown_recv; - *connection_lock = Some((writer, supervisor)); - self.sender - .send(UpdateMessage::Connected) - .await; - } - Err(e) => { - self.sender.send(UpdateMessage::Error(e.into())); - } - } - } - }; + msg + }, + else => break, + }; + // TODO: consider separating disconnect/connect and commands apart from commandmessage + // TODO: dispatch commands separate tasks + match msg { + CommandMessage::Connect => { + let mut connection_lock = self.connected.lock().await; + match connection_lock.as_ref() { + Some(_) => { + self.sender + .send(UpdateMessage::Error(Error::AlreadyConnected)) + .await; } - CommandMessage::Disconnect => match self.connected.lock().await.as_mut() { - None => { - self.sender - .send(UpdateMessage::Error(Error::AlreadyDisconnected)) + None => { + let mut jid = self.jid.lock().await; + let mut domain = jid.domainpart.clone(); + // TODO: check what happens upon reconnection with same resource (this is probably what one wants to do and why jid should be mutated from a bare jid to one with a resource) + let streams_result = + jabber::connect_and_login(&mut jid, &*self.password, &mut domain) .await; + match streams_result { + Ok(s) => { + let (shutdown_send, shutdown_recv) = oneshot::channel::<()>(); + let (writer, supervisor) = SupervisorHandle::new( + s, + self.sender.clone(), + self.db.clone(), + shutdown_send, + self.jid.clone(), + self.password.clone(), + self.pending_iqs.clone(), + ); + self.connection_supervisor_shutdown = shutdown_recv; + *connection_lock = Some((writer, supervisor)); + self.sender.send(UpdateMessage::Connected(todo!())).await; + } + Err(e) => { + self.sender.send(UpdateMessage::Error(e.into())); + } } - mut c => { - if let Some((_write_handle, supervisor_handle)) = c.take() { - let _ = supervisor_handle.send(SupervisorCommand::Disconnect).await; - } else { - unreachable!() - }; - } - }, - _ => { - match self.connected.lock().await.as_ref() { - Some((w, s)) => self.tasks.spawn(msg.handle_online( - w.clone(), - s.sender(), - self.jid.clone(), - self.db.clone(), - self.sender.clone(), - self.pending_iqs.clone() - )), - None => self.tasks.spawn(msg.handle_offline( - self.jid.clone(), - self.db.clone(), - self.sender.clone(), - )), - }; } + }; + } + CommandMessage::Disconnect => match self.connected.lock().await.as_mut() { + None => { + self.sender + .send(UpdateMessage::Error(Error::AlreadyDisconnected)) + .await; + } + mut c => { + if let Some((_write_handle, supervisor_handle)) = c.take() { + let _ = supervisor_handle.send(SupervisorCommand::Disconnect).await; + } else { + unreachable!() + }; } }, - else => break, + _ => { + match self.connected.lock().await.as_ref() { + Some((w, s)) => self.tasks.spawn(msg.handle_online( + w.clone(), + s.sender(), + self.jid.clone(), + self.db.clone(), + self.sender.clone(), + self.pending_iqs.clone(), + )), + None => self.tasks.spawn(msg.handle_offline( + self.jid.clone(), + self.db.clone(), + self.sender.clone(), + )), + }; + } } } } @@ -213,7 +213,8 @@ impl CommandMessage { e => println!("error: {:?}", e), }; } - CommandMessage::SendMessage(jid, _) => todo!(), + CommandMessage::SendMessage { id, to, body } => todo!(), + _ => todo!(), } } } @@ -274,10 +275,16 @@ pub enum CommandMessage { /// connect to XMPP chat server. gets roster and publishes initial presence. Connect, /// disconnect from XMPP chat server, sending unavailable presence then closing stream. - Disconnect, + Disconnect(Offline), /// get the roster. if offline, retreive cached version from database. should be stored in application memory GetRoster, - // add a contact to your roster, with a status of none, no subscriptions + /// get all chats. chat will include 10 messages in their message Vec (enough for chat previews) + // TODO: paging and filtering + GetChats(oneshot::Sender<Vec<Chat>>), + /// get message history for chat (does appropriate mam things) + // TODO: paging and filtering + GetMessages(JID, oneshot::Sender<Vec<Message>>), + /// add a contact to your roster, with a status of none, no subscriptions. AddContact(JID), /// send a friend request i.e. a subscription request with a subscription pre-approval. if not already added to roster server adds to roster. BuddyRequest(JID), @@ -295,38 +302,34 @@ pub enum CommandMessage { UnfriendContact(JID), /// remove a contact from the contact list. will remove subscriptions if not already done then delete contact from roster. DeleteContact(JID), - /// set online status - SendStatus(Online), - SendOffline(Offline), + /// update contact + UpdateContact(JID, ContactUpdate), + /// set online status. if disconnected, will be cached so when client connects, will be sent as the initial presence. + SetStatus(Online), /// send a directed presence (usually to a non-contact). // TODO: should probably make it so people can add non-contact auto presence sharing in the client. - SendDirectedPresence { - to: JID, - presence: Presence, - }, - SendMessage { - id: Uuid, - to: JID, - body: Body, - }, + // SendDirectedPresence(JID, Online), + /// send a message to a jid (any kind of jid that can receive a message, e.g. a user or a + /// chatroom). if disconnected, will be cached so when client connects, message will be sent. + SendMessage(JID, Body), } #[derive(Debug)] pub enum UpdateMessage { Error(Error), - Connected(Online), - Disconnected(Offline), - /// full roster (replace full app roster state with this) - Roster(Vec<Contact>), - /// roster update (only update app roster state) - RosterPush(Contact), + Online(Online), + Offline(Offline), + /// received roster (replace full app roster state with this) + FullRoster(Vec<Contact>), + /// (only update app roster state) + RosterUpdate(Contact), Presence { from: JID, presence: Presence, }, MessageDispatched(Uuid), Message { - from: JID, + to: JID, message: Message, }, } diff --git a/luz/src/presence.rs b/luz/src/presence.rs index 0423d52..b7ebe1d 100644 --- a/luz/src/presence.rs +++ b/luz/src/presence.rs @@ -1,13 +1,13 @@ use stanza::client::presence::Show; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Online { show: Option<Show>, status: Option<String>, priority: Option<i8>, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Offline { status: Option<String>, } diff --git a/luz/src/roster.rs b/luz/src/roster.rs index 421ee9d..512d35d 100644 --- a/luz/src/roster.rs +++ b/luz/src/roster.rs @@ -5,11 +5,16 @@ use uuid::Uuid; use crate::user::User; +pub enum ContactUpdate { + Name(Option<String>), + AddToGroup(String), + RemoveFromGroup(String), +} + #[derive(Debug)] pub struct Contact { // jid is the id used to reference everything, but not the primary key user: User, - jid: JID, subscription: Subscription, /// client user defined name name: Option<String>, @@ -19,6 +24,10 @@ pub struct Contact { groups: HashSet<String>, } +impl Contact { + pub fn new(user: User, name: Option<String>, ) +} + #[derive(Debug)] enum Subscription { None, @@ -29,4 +38,5 @@ enum Subscription { OutPendingIn, InPendingOut, Buddy, + Remove, } |