implement handle_online() and handle_offline() for CommandMessage
This commit is contained in:
parent
945f140616
commit
c0d2aae038
|
@ -139,6 +139,20 @@ pub struct WriteHandle {
|
|||
sender: mpsc::Sender<WriteMessage>,
|
||||
}
|
||||
|
||||
impl WriteHandle {
|
||||
pub async fn write(&self, stanza: Stanza) -> Result<(), Reason> {
|
||||
let (send, recv) = oneshot::channel();
|
||||
self.send(WriteMessage {
|
||||
stanza,
|
||||
respond_to: send,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| Reason::ChannelSend)?;
|
||||
// TODO: timeout
|
||||
recv.await?
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for WriteHandle {
|
||||
type Target = mpsc::Sender<WriteMessage>;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ impl From<RosterError> for ConnectionError {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct StatusError(Reason);
|
||||
pub struct StatusError(pub Reason);
|
||||
|
||||
impl From<StatusError> for Error {
|
||||
fn from(e: StatusError) -> Self {
|
||||
|
@ -55,7 +55,7 @@ pub enum Reason {
|
|||
// TODO: organisastion of error into internal error thing
|
||||
Timeout,
|
||||
Stream(stanza::stream_error::Error),
|
||||
Stanza(stanza::stanza_error::Error),
|
||||
Stanza(Option<stanza::client::error::Error>),
|
||||
Jabber(jabber::Error),
|
||||
XML(peanuts::Error),
|
||||
SQL(sqlx::Error),
|
||||
|
@ -63,6 +63,8 @@ pub enum Reason {
|
|||
LostConnection,
|
||||
OneshotRecv(oneshot::error::RecvError),
|
||||
UnexpectedStanza(Stanza),
|
||||
Disconnected,
|
||||
ChannelSend,
|
||||
}
|
||||
|
||||
impl From<oneshot::error::RecvError> for Reason {
|
||||
|
|
640
luz/src/lib.rs
640
luz/src/lib.rs
|
@ -20,7 +20,7 @@ use tokio::{
|
|||
sync::{mpsc, oneshot, Mutex},
|
||||
task::JoinSet,
|
||||
};
|
||||
use tracing::info;
|
||||
use tracing::{info, Instrument};
|
||||
use user::User;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -286,24 +286,72 @@ impl CommandMessage {
|
|||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::GetChats(sender) => todo!(),
|
||||
CommandMessage::GetChat(jid, sender) => todo!(),
|
||||
CommandMessage::GetMessages(jid, sender) => todo!(),
|
||||
CommandMessage::DeleteChat(jid, sender) => todo!(),
|
||||
CommandMessage::DeleteMessage(uuid, sender) => todo!(),
|
||||
CommandMessage::GetUser(jid, sender) => todo!(),
|
||||
CommandMessage::AddContact(jid, sender) => todo!(),
|
||||
CommandMessage::BuddyRequest(jid, sender) => todo!(),
|
||||
CommandMessage::SubscriptionRequest(jid, sender) => todo!(),
|
||||
CommandMessage::AcceptBuddyRequest(jid, sender) => todo!(),
|
||||
CommandMessage::AcceptSubscriptionRequest(jid, sender) => todo!(),
|
||||
CommandMessage::UnsubscribeFromContact(jid, sender) => todo!(),
|
||||
CommandMessage::UnsubscribeContact(jid, sender) => todo!(),
|
||||
CommandMessage::UnfriendContact(jid, sender) => todo!(),
|
||||
CommandMessage::DeleteContact(jid, sender) => todo!(),
|
||||
CommandMessage::UpdateContact(jid, contact_update, sender) => todo!(),
|
||||
CommandMessage::SetStatus(online, sender) => todo!(),
|
||||
CommandMessage::SendMessage(jid, body, sender) => todo!(),
|
||||
CommandMessage::GetChats(sender) => {
|
||||
let chats = db.read_chats().await.map_err(|e| e.into());
|
||||
sender.send(chats);
|
||||
}
|
||||
CommandMessage::GetChat(jid, sender) => {
|
||||
let chats = db.read_chat(jid).await.map_err(|e| e.into());
|
||||
sender.send(chats);
|
||||
}
|
||||
CommandMessage::GetMessages(jid, sender) => {
|
||||
let messages = db.read_message_history(jid).await.map_err(|e| e.into());
|
||||
sender.send(messages);
|
||||
}
|
||||
CommandMessage::DeleteChat(jid, sender) => {
|
||||
let result = db.delete_chat(jid).await.map_err(|e| e.into());
|
||||
sender.send(result);
|
||||
}
|
||||
CommandMessage::DeleteMessage(uuid, sender) => {
|
||||
let result = db.delete_message(uuid).await.map_err(|e| e.into());
|
||||
sender.send(result);
|
||||
}
|
||||
CommandMessage::GetUser(jid, sender) => {
|
||||
let user = db.read_user(jid).await.map_err(|e| e.into());
|
||||
sender.send(user);
|
||||
}
|
||||
// TODO: offline queue to modify roster
|
||||
CommandMessage::AddContact(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::BuddyRequest(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::SubscriptionRequest(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::AcceptBuddyRequest(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::AcceptSubscriptionRequest(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::UnsubscribeFromContact(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::UnsubscribeContact(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::UnfriendContact(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::DeleteContact(jid, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::UpdateContact(jid, contact_update, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
CommandMessage::SetStatus(online, sender) => {
|
||||
let result = db
|
||||
.upsert_cached_status(online)
|
||||
.await
|
||||
.map_err(|e| StatusError(e.into()));
|
||||
sender.send(result);
|
||||
}
|
||||
// TODO: offline message queue
|
||||
CommandMessage::SendMessage(jid, body, sender) => {
|
||||
sender.send(Err(Reason::Disconnected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +360,7 @@ impl CommandMessage {
|
|||
write_handle: WriteHandle,
|
||||
supervisor_control: SupervisorSender,
|
||||
// TODO: jid could lose resource by the end
|
||||
jid: Arc<Mutex<JID>>,
|
||||
client_jid: Arc<Mutex<JID>>,
|
||||
db: Db,
|
||||
update_sender: mpsc::Sender<UpdateMessage>,
|
||||
pending_iqs: Arc<Mutex<HashMap<String, oneshot::Sender<Result<Stanza, Reason>>>>>,
|
||||
|
@ -324,7 +372,7 @@ impl CommandMessage {
|
|||
// TODO: jid resource should probably be stored within the connection
|
||||
let owned_jid: JID;
|
||||
{
|
||||
owned_jid = jid.lock().await.clone();
|
||||
owned_jid = client_jid.lock().await.clone();
|
||||
}
|
||||
let iq_id = Uuid::new_v4().to_string();
|
||||
let (send, iq_recv) = oneshot::channel();
|
||||
|
@ -400,24 +448,502 @@ impl CommandMessage {
|
|||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::GetChats(sender) => todo!(),
|
||||
CommandMessage::GetChat(jid, sender) => todo!(),
|
||||
CommandMessage::GetMessages(jid, sender) => todo!(),
|
||||
CommandMessage::DeleteChat(jid, sender) => todo!(),
|
||||
CommandMessage::DeleteMessage(uuid, sender) => todo!(),
|
||||
CommandMessage::GetUser(jid, sender) => todo!(),
|
||||
CommandMessage::AddContact(jid, sender) => todo!(),
|
||||
CommandMessage::BuddyRequest(jid, sender) => todo!(),
|
||||
CommandMessage::SubscriptionRequest(jid, sender) => todo!(),
|
||||
CommandMessage::AcceptBuddyRequest(jid, sender) => todo!(),
|
||||
CommandMessage::AcceptSubscriptionRequest(jid, sender) => todo!(),
|
||||
CommandMessage::UnsubscribeFromContact(jid, sender) => todo!(),
|
||||
CommandMessage::UnsubscribeContact(jid, sender) => todo!(),
|
||||
CommandMessage::UnfriendContact(jid, sender) => todo!(),
|
||||
CommandMessage::DeleteContact(jid, sender) => todo!(),
|
||||
CommandMessage::UpdateContact(jid, contact_update, sender) => todo!(),
|
||||
CommandMessage::SetStatus(online, sender) => todo!(),
|
||||
CommandMessage::SendMessage(jid, body, sender) => todo!(),
|
||||
CommandMessage::GetChats(sender) => {
|
||||
let chats = db.read_chats().await.map_err(|e| e.into());
|
||||
sender.send(chats);
|
||||
}
|
||||
CommandMessage::GetChat(jid, sender) => {
|
||||
let chats = db.read_chat(jid).await.map_err(|e| e.into());
|
||||
sender.send(chats);
|
||||
}
|
||||
CommandMessage::GetMessages(jid, sender) => {
|
||||
let messages = db.read_message_history(jid).await.map_err(|e| e.into());
|
||||
sender.send(messages);
|
||||
}
|
||||
CommandMessage::DeleteChat(jid, sender) => {
|
||||
let result = db.delete_chat(jid).await.map_err(|e| e.into());
|
||||
sender.send(result);
|
||||
}
|
||||
CommandMessage::DeleteMessage(uuid, sender) => {
|
||||
let result = db.delete_message(uuid).await.map_err(|e| e.into());
|
||||
sender.send(result);
|
||||
}
|
||||
CommandMessage::GetUser(jid, sender) => {
|
||||
let user = db.read_user(jid).await.map_err(|e| e.into());
|
||||
sender.send(user);
|
||||
}
|
||||
// TODO: offline queue to modify roster
|
||||
CommandMessage::AddContact(jid, sender) => {
|
||||
let owned_jid;
|
||||
{
|
||||
owned_jid = client_jid.lock().await.clone();
|
||||
}
|
||||
let iq_id = Uuid::new_v4().to_string();
|
||||
let set_stanza = Stanza::Iq(Iq {
|
||||
from: Some(owned_jid),
|
||||
id: iq_id.clone(),
|
||||
to: None,
|
||||
r#type: IqType::Set,
|
||||
lang: None,
|
||||
query: Some(iq::Query::Roster(stanza::roster::Query {
|
||||
ver: None,
|
||||
items: vec![stanza::roster::Item {
|
||||
approved: None,
|
||||
ask: false,
|
||||
jid,
|
||||
name: None,
|
||||
subscription: None,
|
||||
groups: Vec::new(),
|
||||
}],
|
||||
})),
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let (send, recv) = oneshot::channel();
|
||||
{
|
||||
pending_iqs.lock().await.insert(iq_id.clone(), send);
|
||||
}
|
||||
// TODO: write_handle send helper function
|
||||
let result = write_handle.write(set_stanza).await;
|
||||
if let Err(_) = result {
|
||||
sender.send(result);
|
||||
return;
|
||||
}
|
||||
let iq_result = recv.await;
|
||||
match iq_result {
|
||||
Ok(i) => match i {
|
||||
Ok(iq_result) => match iq_result {
|
||||
Stanza::Iq(Iq {
|
||||
from: _,
|
||||
id,
|
||||
to: _,
|
||||
r#type,
|
||||
lang: _,
|
||||
query: _,
|
||||
errors: _,
|
||||
}) if id == iq_id && r#type == IqType::Result => {
|
||||
sender.send(Ok(()));
|
||||
return;
|
||||
}
|
||||
Stanza::Iq(Iq {
|
||||
from: _,
|
||||
id,
|
||||
to: _,
|
||||
r#type,
|
||||
lang: _,
|
||||
query: _,
|
||||
errors,
|
||||
}) if id == iq_id && r#type == IqType::Error => {
|
||||
if let Some(error) = errors.first() {
|
||||
sender.send(Err(Reason::Stanza(Some(error.clone()))));
|
||||
} else {
|
||||
sender.send(Err(Reason::Stanza(None)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
s => {
|
||||
sender.send(Err(Reason::UnexpectedStanza(s)));
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sender.send(Err(e.into()));
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sender.send(Err(e.into()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::BuddyRequest(jid, sender) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid.clone()),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Subscribe),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
match result {
|
||||
Err(_) => {
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
Ok(()) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Subscribed),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::SubscriptionRequest(jid, sender) => {
|
||||
// TODO: i should probably have builders
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Subscribe),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
CommandMessage::AcceptBuddyRequest(jid, sender) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid.clone()),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Subscribed),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
match result {
|
||||
Err(_) => {
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
Ok(()) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Subscribe),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::AcceptSubscriptionRequest(jid, sender) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Subscribe),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
CommandMessage::UnsubscribeFromContact(jid, sender) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Unsubscribe),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
CommandMessage::UnsubscribeContact(jid, sender) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Unsubscribed),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
CommandMessage::UnfriendContact(jid, sender) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid.clone()),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Unsubscribe),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
match result {
|
||||
Err(_) => {
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
Ok(()) => {
|
||||
let presence = Stanza::Presence(stanza::client::presence::Presence {
|
||||
from: None,
|
||||
id: None,
|
||||
to: Some(jid),
|
||||
r#type: Some(stanza::client::presence::PresenceType::Unsubscribed),
|
||||
lang: None,
|
||||
show: None,
|
||||
status: None,
|
||||
priority: None,
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let result = write_handle.write(presence).await;
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::DeleteContact(jid, sender) => {
|
||||
let owned_jid;
|
||||
{
|
||||
owned_jid = client_jid.lock().await.clone();
|
||||
}
|
||||
let iq_id = Uuid::new_v4().to_string();
|
||||
let set_stanza = Stanza::Iq(Iq {
|
||||
from: Some(owned_jid),
|
||||
id: iq_id.clone(),
|
||||
to: None,
|
||||
r#type: IqType::Set,
|
||||
lang: None,
|
||||
query: Some(iq::Query::Roster(stanza::roster::Query {
|
||||
ver: None,
|
||||
items: vec![stanza::roster::Item {
|
||||
approved: None,
|
||||
ask: false,
|
||||
jid,
|
||||
name: None,
|
||||
subscription: Some(stanza::roster::Subscription::Remove),
|
||||
groups: Vec::new(),
|
||||
}],
|
||||
})),
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let (send, recv) = oneshot::channel();
|
||||
{
|
||||
pending_iqs.lock().await.insert(iq_id.clone(), send);
|
||||
}
|
||||
let result = write_handle.write(set_stanza).await;
|
||||
if let Err(_) = result {
|
||||
sender.send(result);
|
||||
return;
|
||||
}
|
||||
let iq_result = recv.await;
|
||||
match iq_result {
|
||||
Ok(i) => match i {
|
||||
Ok(iq_result) => match iq_result {
|
||||
Stanza::Iq(Iq {
|
||||
from: _,
|
||||
id,
|
||||
to: _,
|
||||
r#type,
|
||||
lang: _,
|
||||
query: _,
|
||||
errors: _,
|
||||
}) if id == iq_id && r#type == IqType::Result => {
|
||||
sender.send(Ok(()));
|
||||
return;
|
||||
}
|
||||
Stanza::Iq(Iq {
|
||||
from: _,
|
||||
id,
|
||||
to: _,
|
||||
r#type,
|
||||
lang: _,
|
||||
query: _,
|
||||
errors,
|
||||
}) if id == iq_id && r#type == IqType::Error => {
|
||||
if let Some(error) = errors.first() {
|
||||
sender.send(Err(Reason::Stanza(Some(error.clone()))));
|
||||
} else {
|
||||
sender.send(Err(Reason::Stanza(None)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
s => {
|
||||
sender.send(Err(Reason::UnexpectedStanza(s)));
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sender.send(Err(e.into()));
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sender.send(Err(e.into()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::UpdateContact(jid, contact_update, sender) => {
|
||||
let owned_jid;
|
||||
{
|
||||
owned_jid = client_jid.lock().await.clone();
|
||||
}
|
||||
let iq_id = Uuid::new_v4().to_string();
|
||||
let groups = Vec::from_iter(
|
||||
contact_update
|
||||
.groups
|
||||
.into_iter()
|
||||
.map(|group| stanza::roster::Group(Some(group))),
|
||||
);
|
||||
let set_stanza = Stanza::Iq(Iq {
|
||||
from: Some(owned_jid),
|
||||
id: iq_id.clone(),
|
||||
to: None,
|
||||
r#type: IqType::Set,
|
||||
lang: None,
|
||||
query: Some(iq::Query::Roster(stanza::roster::Query {
|
||||
ver: None,
|
||||
items: vec![stanza::roster::Item {
|
||||
approved: None,
|
||||
ask: false,
|
||||
jid,
|
||||
name: contact_update.name,
|
||||
subscription: None,
|
||||
groups,
|
||||
}],
|
||||
})),
|
||||
errors: Vec::new(),
|
||||
});
|
||||
let (send, recv) = oneshot::channel();
|
||||
{
|
||||
pending_iqs.lock().await.insert(iq_id.clone(), send);
|
||||
}
|
||||
let result = write_handle.write(set_stanza).await;
|
||||
if let Err(_) = result {
|
||||
sender.send(result);
|
||||
return;
|
||||
}
|
||||
let iq_result = recv.await;
|
||||
match iq_result {
|
||||
Ok(i) => match i {
|
||||
Ok(iq_result) => match iq_result {
|
||||
Stanza::Iq(Iq {
|
||||
from: _,
|
||||
id,
|
||||
to: _,
|
||||
r#type,
|
||||
lang: _,
|
||||
query: _,
|
||||
errors: _,
|
||||
}) if id == iq_id && r#type == IqType::Result => {
|
||||
sender.send(Ok(()));
|
||||
return;
|
||||
}
|
||||
Stanza::Iq(Iq {
|
||||
from: _,
|
||||
id,
|
||||
to: _,
|
||||
r#type,
|
||||
lang: _,
|
||||
query: _,
|
||||
errors,
|
||||
}) if id == iq_id && r#type == IqType::Error => {
|
||||
if let Some(error) = errors.first() {
|
||||
sender.send(Err(Reason::Stanza(Some(error.clone()))));
|
||||
} else {
|
||||
sender.send(Err(Reason::Stanza(None)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
s => {
|
||||
sender.send(Err(Reason::UnexpectedStanza(s)));
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sender.send(Err(e.into()));
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sender.send(Err(e.into()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandMessage::SetStatus(online, sender) => {
|
||||
let result = db.upsert_cached_status(online.clone()).await;
|
||||
if let Err(e) = result {
|
||||
let _ = update_sender
|
||||
.send(UpdateMessage::Error(Error::CacheUpdate(e.into())))
|
||||
.await;
|
||||
}
|
||||
let result = write_handle
|
||||
.write(Stanza::Presence(online.into()))
|
||||
.await
|
||||
.map_err(|e| StatusError(e));
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
// TODO: offline message queue
|
||||
CommandMessage::SendMessage(jid, body, sender) => {
|
||||
let id = Uuid::new_v4();
|
||||
let owned_jid: JID;
|
||||
{
|
||||
// TODO: timeout
|
||||
owned_jid = client_jid.lock().await.clone();
|
||||
}
|
||||
let message = Stanza::Message(stanza::client::message::Message {
|
||||
from: Some(owned_jid.clone()),
|
||||
id: Some(id.to_string()),
|
||||
to: Some(jid.clone()),
|
||||
// TODO: specify message type
|
||||
r#type: stanza::client::message::MessageType::Chat,
|
||||
// TODO: lang ?
|
||||
lang: None,
|
||||
subject: None,
|
||||
body: Some(stanza::client::message::Body {
|
||||
lang: None,
|
||||
body: Some(body.body.clone()),
|
||||
}),
|
||||
thread: None,
|
||||
});
|
||||
let result = write_handle.write(message).await;
|
||||
match result {
|
||||
Ok(_) => {
|
||||
let message = Message {
|
||||
id,
|
||||
from: owned_jid,
|
||||
body,
|
||||
};
|
||||
if let Err(e) = db.create_message(message, jid).await.map_err(|e| e.into())
|
||||
{
|
||||
let _ = update_sender.send(UpdateMessage::Error(Error::CacheUpdate(e)));
|
||||
}
|
||||
let _ = sender.send(Ok(()));
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = sender.send(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -484,46 +1010,46 @@ pub enum CommandMessage {
|
|||
GetRoster(oneshot::Sender<Result<Vec<Contact>, RosterError>>),
|
||||
/// get all chats. chat will include 10 messages in their message Vec (enough for chat previews)
|
||||
// TODO: paging and filtering
|
||||
GetChats(oneshot::Sender<Result<Vec<Chat>, Error>>),
|
||||
GetChats(oneshot::Sender<Result<Vec<Chat>, Reason>>),
|
||||
/// get a specific chat by jid
|
||||
GetChat(JID, oneshot::Sender<Result<Chat, Error>>),
|
||||
GetChat(JID, oneshot::Sender<Result<Chat, Reason>>),
|
||||
/// get message history for chat (does appropriate mam things)
|
||||
// TODO: paging and filtering
|
||||
GetMessages(JID, oneshot::Sender<Result<Vec<Message>, Error>>),
|
||||
GetMessages(JID, oneshot::Sender<Result<Vec<Message>, Reason>>),
|
||||
/// delete a chat from your chat history, along with all the corresponding messages
|
||||
DeleteChat(JID, oneshot::Sender<Result<(), Error>>),
|
||||
DeleteChat(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// delete a message from your chat history
|
||||
DeleteMessage(Uuid, oneshot::Sender<Result<(), Error>>),
|
||||
DeleteMessage(Uuid, oneshot::Sender<Result<(), Reason>>),
|
||||
/// get a user from your users database
|
||||
GetUser(JID, oneshot::Sender<Result<User, Error>>),
|
||||
GetUser(JID, oneshot::Sender<Result<User, Reason>>),
|
||||
/// add a contact to your roster, with a status of none, no subscriptions.
|
||||
// TODO: for all these, consider returning with oneshot::Sender<Result<(), Error>>
|
||||
AddContact(JID, oneshot::Sender<Result<(), Error>>),
|
||||
AddContact(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// 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, oneshot::Sender<Result<(), Error>>),
|
||||
BuddyRequest(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// send a subscription request, without pre-approval. if not already added to roster server adds to roster.
|
||||
SubscriptionRequest(JID, oneshot::Sender<Result<(), Error>>),
|
||||
SubscriptionRequest(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// accept a friend request by accepting a pending subscription and sending a subscription request back. if not already added to roster adds to roster.
|
||||
AcceptBuddyRequest(JID, oneshot::Sender<Result<(), Error>>),
|
||||
AcceptBuddyRequest(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// accept a pending subscription and doesn't send a subscription request back. if not already added to roster adds to roster.
|
||||
AcceptSubscriptionRequest(JID, oneshot::Sender<Result<(), Error>>),
|
||||
AcceptSubscriptionRequest(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// unsubscribe to a contact, but don't remove their subscription.
|
||||
UnsubscribeFromContact(JID, oneshot::Sender<Result<(), Error>>),
|
||||
UnsubscribeFromContact(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// stop a contact from being subscribed, but stay subscribed to the contact.
|
||||
UnsubscribeContact(JID, oneshot::Sender<Result<(), Error>>),
|
||||
UnsubscribeContact(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// remove subscriptions to and from contact, but keep in roster.
|
||||
UnfriendContact(JID, oneshot::Sender<Result<(), Error>>),
|
||||
UnfriendContact(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// remove a contact from the contact list. will remove subscriptions if not already done then delete contact from roster.
|
||||
DeleteContact(JID, oneshot::Sender<Result<(), Error>>),
|
||||
/// update contact
|
||||
UpdateContact(JID, ContactUpdate, oneshot::Sender<Result<(), Error>>),
|
||||
DeleteContact(JID, oneshot::Sender<Result<(), Reason>>),
|
||||
/// update contact. contact details will be overwritten with the contents of the contactupdate struct.
|
||||
UpdateContact(JID, ContactUpdate, oneshot::Sender<Result<(), Reason>>),
|
||||
/// set online status. if disconnected, will be cached so when client connects, will be sent as the initial presence.
|
||||
SetStatus(Online, oneshot::Sender<Result<(), StatusError>>),
|
||||
/// 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 (most likely through setting an internal setting)
|
||||
/// 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, oneshot::Sender<Result<(), Error>>),
|
||||
SendMessage(JID, Body, oneshot::Sender<Result<(), Reason>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use sqlx::Sqlite;
|
||||
use stanza::client::presence::String1024;
|
||||
|
||||
#[derive(Debug, Default, sqlx::FromRow, Clone)]
|
||||
pub struct Online {
|
||||
|
@ -62,3 +63,30 @@ pub enum Presence {
|
|||
Online(Online),
|
||||
Offline(Offline),
|
||||
}
|
||||
|
||||
impl From<Online> for stanza::client::presence::Presence {
|
||||
fn from(value: Online) -> Self {
|
||||
Self {
|
||||
from: None,
|
||||
id: None,
|
||||
to: None,
|
||||
r#type: None,
|
||||
lang: None,
|
||||
show: value.show.map(|show| match show {
|
||||
Show::Away => stanza::client::presence::Show::Away,
|
||||
Show::Chat => stanza::client::presence::Show::Chat,
|
||||
Show::DoNotDisturb => stanza::client::presence::Show::Dnd,
|
||||
Show::ExtendedAway => stanza::client::presence::Show::Xa,
|
||||
}),
|
||||
// TODO: enforce message length in status message
|
||||
status: value.status.map(|status| stanza::client::presence::Status {
|
||||
lang: None,
|
||||
status: String1024(status),
|
||||
}),
|
||||
priority: value
|
||||
.priority
|
||||
.map(|priority| stanza::client::presence::Priority(priority)),
|
||||
errors: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,9 @@ use std::collections::HashSet;
|
|||
use jid::JID;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
pub enum ContactUpdate {
|
||||
Name(Option<String>),
|
||||
AddToGroup(String),
|
||||
RemoveFromGroup(String),
|
||||
pub struct ContactUpdate {
|
||||
pub name: Option<String>,
|
||||
pub groups: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, sqlx::FromRow, Clone)]
|
||||
|
|
|
@ -10,16 +10,16 @@ use super::XMLNS;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Message {
|
||||
from: Option<JID>,
|
||||
id: Option<String>,
|
||||
to: Option<JID>,
|
||||
pub from: Option<JID>,
|
||||
pub id: Option<String>,
|
||||
pub to: Option<JID>,
|
||||
// can be omitted, if so default to normal
|
||||
r#type: MessageType,
|
||||
lang: Option<String>,
|
||||
pub r#type: MessageType,
|
||||
pub lang: Option<String>,
|
||||
// children
|
||||
subject: Option<Subject>,
|
||||
body: Option<Body>,
|
||||
thread: Option<Thread>,
|
||||
pub subject: Option<Subject>,
|
||||
pub body: Option<Body>,
|
||||
pub thread: Option<Thread>,
|
||||
}
|
||||
|
||||
impl FromElement for Message {
|
||||
|
@ -109,8 +109,8 @@ impl ToString for MessageType {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Body {
|
||||
lang: Option<String>,
|
||||
body: Option<String>,
|
||||
pub lang: Option<String>,
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
impl FromElement for Body {
|
||||
|
|
|
@ -10,18 +10,18 @@ use super::{error::Error, XMLNS};
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Presence {
|
||||
from: Option<JID>,
|
||||
id: Option<String>,
|
||||
to: Option<JID>,
|
||||
r#type: Option<PresenceType>,
|
||||
lang: Option<String>,
|
||||
pub from: Option<JID>,
|
||||
pub id: Option<String>,
|
||||
pub to: Option<JID>,
|
||||
pub r#type: Option<PresenceType>,
|
||||
pub lang: Option<String>,
|
||||
// children
|
||||
show: Option<Show>,
|
||||
status: Option<Status>,
|
||||
priority: Option<Priority>,
|
||||
pub show: Option<Show>,
|
||||
pub status: Option<Status>,
|
||||
pub priority: Option<Priority>,
|
||||
// TODO: ##other
|
||||
// other: Vec<Other>,
|
||||
errors: Vec<Error>,
|
||||
pub errors: Vec<Error>,
|
||||
}
|
||||
|
||||
impl FromElement for Presence {
|
||||
|
@ -165,8 +165,8 @@ impl ToString for Show {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Status {
|
||||
lang: Option<String>,
|
||||
status: String1024,
|
||||
pub lang: Option<String>,
|
||||
pub status: String1024,
|
||||
}
|
||||
|
||||
impl FromElement for Status {
|
||||
|
|
Loading…
Reference in New Issue