aboutsummaryrefslogtreecommitdiffstats
path: root/filamento/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'filamento/src/lib.rs')
-rw-r--r--filamento/src/lib.rs459
1 files changed, 384 insertions, 75 deletions
diff --git a/filamento/src/lib.rs b/filamento/src/lib.rs
index c44edca..d3033b7 100644
--- a/filamento/src/lib.rs
+++ b/filamento/src/lib.rs
@@ -11,11 +11,12 @@ use chrono::Utc;
use db::Db;
use disco::{Info, Items};
use error::{
- ConnectionJobError, DatabaseError, DiscoError, Error, IqError, MessageRecvError, NickError,
- PresenceError, PublishError, RosterError, StatusError, SubscribeError,
+ AvatarPublishError, ConnectionJobError, DatabaseError, DiscoError, Error, IqError,
+ MessageRecvError, NickError, PEPError, PresenceError, RosterError, StatusError, SubscribeError,
};
+use files::FileStore;
use futures::FutureExt;
-use jid::JID;
+use jid::{BareJID, JID};
use lampada::{
Connected, CoreClient, CoreClientCommand, Logic, SupervisorSender, WriteMessage,
error::{ActorError, CommandError, ConnectionError, ReadError, WriteError},
@@ -31,24 +32,30 @@ use tokio::{
sync::{Mutex, mpsc, oneshot},
time::timeout,
};
+#[cfg(target_arch = "wasm32")]
+use tokio_with_wasm::alias as tokio;
use tracing::{debug, info};
use user::User;
use uuid::Uuid;
+pub mod avatar;
pub mod caps;
pub mod chat;
pub mod db;
pub mod disco;
pub mod error;
+pub mod files;
mod logic;
pub mod pep;
pub mod presence;
pub mod roster;
pub mod user;
-pub enum Command {
+pub enum Command<Fs: FileStore> {
/// get the roster. if offline, retreive cached version from database. should be stored in application memory
GetRoster(oneshot::Sender<Result<Vec<Contact>, RosterError>>),
+ /// get the roster. if offline, retreive cached version from database. should be stored in application memory. includes user associated with each contact
+ GetRosterWithUsers(oneshot::Sender<Result<Vec<(Contact, User)>, 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>, DatabaseError>>),
@@ -56,37 +63,60 @@ pub enum Command {
GetChatsOrdered(oneshot::Sender<Result<Vec<Chat>, DatabaseError>>),
// TODO: paging and filtering
GetChatsOrderedWithLatestMessages(oneshot::Sender<Result<Vec<(Chat, Message)>, DatabaseError>>),
+ // TODO: paging and filtering, nullabillity for latest message
+ GetChatsOrderedWithLatestMessagesAndUsers(
+ oneshot::Sender<Result<Vec<((Chat, User), (Message, User))>, DatabaseError>>,
+ ),
/// get a specific chat by jid
- GetChat(JID, oneshot::Sender<Result<Chat, DatabaseError>>),
+ GetChat(BareJID, oneshot::Sender<Result<Chat, DatabaseError>>),
+ /// get a specific chat and user by jid
+ GetChatAndUser(
+ BareJID,
+ oneshot::Sender<Result<(Chat, User), DatabaseError>>,
+ ),
+ /// get message history for chat (does appropriate mam things)
+ GetMessage(Uuid, oneshot::Sender<Result<Message, DatabaseError>>),
+ // TODO: paging and filtering
+ GetMessages(
+ BareJID,
+ oneshot::Sender<Result<Vec<Message>, DatabaseError>>,
+ ),
/// get message history for chat (does appropriate mam things)
// TODO: paging and filtering
- GetMessages(JID, oneshot::Sender<Result<Vec<Message>, DatabaseError>>),
+ GetMessagesWithUsers(
+ BareJID,
+ oneshot::Sender<Result<Vec<(Message, User)>, DatabaseError>>,
+ ),
/// delete a chat from your chat history, along with all the corresponding messages
- DeleteChat(JID, oneshot::Sender<Result<(), DatabaseError>>),
+ DeleteChat(BareJID, oneshot::Sender<Result<(), DatabaseError>>),
/// delete a message from your chat history
DeleteMessage(Uuid, oneshot::Sender<Result<(), DatabaseError>>),
/// get a user from your users database
- GetUser(JID, oneshot::Sender<Result<User, DatabaseError>>),
+ GetUser(BareJID, oneshot::Sender<Result<User, DatabaseError>>),
/// add a contact to your roster, with a status of none, no subscriptions.
- AddContact(JID, oneshot::Sender<Result<(), RosterError>>),
+ AddContact(BareJID, oneshot::Sender<Result<(), RosterError>>),
/// 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<(), SubscribeError>>),
+ BuddyRequest(BareJID, oneshot::Sender<Result<(), SubscribeError>>),
/// send a subscription request, without pre-approval. if not already added to roster server adds to roster.
- SubscriptionRequest(JID, oneshot::Sender<Result<(), SubscribeError>>),
+ SubscriptionRequest(BareJID, oneshot::Sender<Result<(), SubscribeError>>),
/// 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<(), SubscribeError>>),
+ AcceptBuddyRequest(BareJID, oneshot::Sender<Result<(), SubscribeError>>),
/// 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<(), SubscribeError>>),
+ AcceptSubscriptionRequest(BareJID, oneshot::Sender<Result<(), SubscribeError>>),
/// unsubscribe to a contact, but don't remove their subscription.
- UnsubscribeFromContact(JID, oneshot::Sender<Result<(), WriteError>>),
+ UnsubscribeFromContact(BareJID, oneshot::Sender<Result<(), WriteError>>),
/// stop a contact from being subscribed, but stay subscribed to the contact.
- UnsubscribeContact(JID, oneshot::Sender<Result<(), WriteError>>),
+ UnsubscribeContact(BareJID, oneshot::Sender<Result<(), WriteError>>),
/// remove subscriptions to and from contact, but keep in roster.
- UnfriendContact(JID, oneshot::Sender<Result<(), WriteError>>),
+ UnfriendContact(BareJID, oneshot::Sender<Result<(), WriteError>>),
/// remove a contact from the contact list. will remove subscriptions if not already done then delete contact from roster.
- DeleteContact(JID, oneshot::Sender<Result<(), RosterError>>),
+ DeleteContact(BareJID, oneshot::Sender<Result<(), RosterError>>),
/// update contact. contact details will be overwritten with the contents of the contactupdate struct.
- UpdateContact(JID, ContactUpdate, oneshot::Sender<Result<(), RosterError>>),
+ UpdateContact(
+ BareJID,
+ ContactUpdate,
+ oneshot::Sender<Result<(), RosterError>>,
+ ),
/// 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 presence stanza
@@ -100,7 +130,7 @@ pub enum Command {
// 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),
+ SendMessage(BareJID, Body),
// TODO: resend failed messages
// ResendMessage(Uuid),
/// disco info query
@@ -115,28 +145,43 @@ pub enum Command {
Option<String>,
oneshot::Sender<Result<disco::Items, DiscoError>>,
),
- /// publish item to a pep node, specified or default according to item.
- Publish {
+ /// publish item to a pep node specified.
+ PublishPEPItem {
item: pep::Item,
node: String,
- sender: oneshot::Sender<Result<(), PublishError>>,
+ sender: oneshot::Sender<Result<(), PEPError>>,
+ },
+ DeletePEPNode {
+ node: String,
+ sender: oneshot::Sender<Result<(), PEPError>>,
+ },
+ GetPEPItem {
+ jid: Option<BareJID>,
+ node: String,
+ id: String,
+ sender: oneshot::Sender<Result<pep::Item, PEPError>>,
},
- /// change user nickname
- ChangeNick(String, oneshot::Sender<Result<(), NickError>>),
+ /// change client user nickname
+ ChangeNick(Option<String>, oneshot::Sender<Result<(), NickError>>),
+ // // TODO
+ // GetNick(...),
+ // GetAvatar(...)
// /// get capability node
// GetCaps(String, oneshot::Sender<Result<Info, CapsError>>),
+ /// change client user avatar
+ ChangeAvatar(
+ Option<Vec<u8>>,
+ oneshot::Sender<Result<(), AvatarPublishError<Fs>>>,
+ ),
}
#[derive(Debug, Clone)]
pub enum UpdateMessage {
- Online(Online, Vec<Contact>),
+ Online(Online, Vec<(Contact, User)>),
Offline(Offline),
- /// received roster from jabber server (replace full app roster state with this)
- /// is this needed?
- FullRoster(Vec<Contact>),
/// (only update app roster state, don't replace)
- RosterUpdate(Contact),
- RosterDelete(JID),
+ RosterUpdate(Contact, User),
+ RosterDelete(BareJID),
/// presences should be stored with users in the ui, not contacts, as presences can be received from anyone
Presence {
from: JID,
@@ -145,28 +190,44 @@ pub enum UpdateMessage {
// TODO: receipts
// MessageDispatched(Uuid),
Message {
- to: JID,
+ // TODO: rename to chat?
+ to: BareJID,
+ from: User,
message: Message,
},
MessageDelivery {
id: Uuid,
+ chat: BareJID,
delivery: Delivery,
},
- SubscriptionRequest(jid::JID),
+ SubscriptionRequest(BareJID),
NickChanged {
- jid: JID,
- nick: String,
+ jid: BareJID,
+ nick: Option<String>,
+ },
+ AvatarChanged {
+ jid: BareJID,
+ id: Option<String>,
},
}
/// an xmpp client that is suited for a chat client use case
#[derive(Debug)]
-pub struct Client {
- sender: mpsc::Sender<CoreClientCommand<Command>>,
+pub struct Client<Fs: FileStore> {
+ sender: mpsc::Sender<CoreClientCommand<Command<Fs>>>,
timeout: Duration,
}
-impl Clone for Client {
+impl<Fs: FileStore> Client<Fs> {
+ pub fn with_timeout(&self, timeout: Duration) -> Self {
+ Self {
+ sender: self.sender.clone(),
+ timeout,
+ }
+ }
+}
+
+impl<Fs: FileStore> Clone for Client<Fs> {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
@@ -175,32 +236,27 @@ impl Clone for Client {
}
}
-impl Deref for Client {
- type Target = mpsc::Sender<CoreClientCommand<Command>>;
+impl<Fs: FileStore> Deref for Client<Fs> {
+ type Target = mpsc::Sender<CoreClientCommand<Command<Fs>>>;
fn deref(&self) -> &Self::Target {
&self.sender
}
}
-impl DerefMut for Client {
+impl<Fs: FileStore> DerefMut for Client<Fs> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.sender
}
}
-impl Client {
- pub async fn connect(&self) -> Result<(), ActorError> {
- self.send(CoreClientCommand::Connect).await?;
- Ok(())
- }
-
- pub async fn disconnect(&self, offline: Offline) -> Result<(), ActorError> {
- self.send(CoreClientCommand::Disconnect).await?;
- Ok(())
- }
-
- pub fn new(jid: JID, password: String, db: Db) -> (Self, mpsc::Receiver<UpdateMessage>) {
+impl<Fs: FileStore + Clone + Send + Sync + 'static> Client<Fs> {
+ pub fn new(
+ jid: JID,
+ password: String,
+ db: Db,
+ file_store: Fs,
+ ) -> (Self, mpsc::Receiver<UpdateMessage>) {
let (command_sender, command_receiver) = mpsc::channel(20);
let (update_send, update_recv) = mpsc::channel(20);
@@ -211,17 +267,38 @@ impl Client {
let client = Self {
sender: command_sender,
// TODO: configure timeout
- timeout: Duration::from_secs(10),
+ timeout: Duration::from_secs(20),
};
- let logic = ClientLogic::new(client.clone(), jid.as_bare(), db, update_send);
+ let logic = ClientLogic::new(client.clone(), jid.to_bare(), db, update_send, file_store);
- let actor: CoreClient<ClientLogic> =
+ let actor: CoreClient<ClientLogic<Fs>> =
CoreClient::new(jid, password, command_receiver, None, sup_recv, logic);
+
tokio::spawn(async move { actor.run().await });
(client, update_recv)
}
+}
+
+impl<Fs: FileStore> Client<Fs> {
+ /// returns the resource
+ pub async fn connect(&self) -> Result<String, CommandError<ConnectionError>> {
+ let (send, recv) = oneshot::channel::<Result<String, ConnectionError>>();
+ self.send(CoreClientCommand::Connect(send))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let result = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(result)
+ }
+
+ pub async fn disconnect(&self, offline: Offline) -> Result<(), ActorError> {
+ self.send(CoreClientCommand::Disconnect).await?;
+ Ok(())
+ }
pub async fn get_roster(&self) -> Result<Vec<Contact>, CommandError<RosterError>> {
let (send, recv) = oneshot::channel();
@@ -235,6 +312,22 @@ impl Client {
Ok(roster)
}
+ pub async fn get_roster_with_users(
+ &self,
+ ) -> Result<Vec<(Contact, User)>, CommandError<RosterError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::GetRosterWithUsers(
+ send,
+ )))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let roster = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(roster)
+ }
+
pub async fn get_chats(&self) -> Result<Vec<Chat>, CommandError<DatabaseError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::GetChats(send)))
@@ -275,7 +368,23 @@ impl Client {
Ok(chats)
}
- pub async fn get_chat(&self, jid: JID) -> Result<Chat, CommandError<DatabaseError>> {
+ pub async fn get_chats_ordered_with_latest_messages_and_users(
+ &self,
+ ) -> Result<Vec<((Chat, User), (Message, User))>, CommandError<DatabaseError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(
+ Command::GetChatsOrderedWithLatestMessagesAndUsers(send),
+ ))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let chats = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(chats)
+ }
+
+ pub async fn get_chat(&self, jid: BareJID) -> Result<Chat, CommandError<DatabaseError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::GetChat(jid, send)))
.await
@@ -287,9 +396,38 @@ impl Client {
Ok(chat)
}
+ pub async fn get_chat_and_user(
+ &self,
+ jid: BareJID,
+ ) -> Result<(Chat, User), CommandError<DatabaseError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::GetChatAndUser(
+ jid, send,
+ )))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let result = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(result)
+ }
+
+ pub async fn get_message(&self, id: Uuid) -> Result<Message, CommandError<DatabaseError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::GetMessage(id, send)))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let message = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(message)
+ }
+
pub async fn get_messages(
&self,
- jid: JID,
+ jid: BareJID,
) -> Result<Vec<Message>, CommandError<DatabaseError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::GetMessages(jid, send)))
@@ -302,7 +440,24 @@ impl Client {
Ok(messages)
}
- pub async fn delete_chat(&self, jid: JID) -> Result<(), CommandError<DatabaseError>> {
+ pub async fn get_messages_with_users(
+ &self,
+ jid: BareJID,
+ ) -> Result<Vec<(Message, User)>, CommandError<DatabaseError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::GetMessagesWithUsers(
+ jid, send,
+ )))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let messages = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(messages)
+ }
+
+ pub async fn delete_chat(&self, jid: BareJID) -> Result<(), CommandError<DatabaseError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::DeleteChat(jid, send)))
.await
@@ -326,7 +481,7 @@ impl Client {
Ok(result)
}
- pub async fn get_user(&self, jid: JID) -> Result<User, CommandError<DatabaseError>> {
+ pub async fn get_user(&self, jid: BareJID) -> Result<User, CommandError<DatabaseError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::GetUser(jid, send)))
.await
@@ -338,7 +493,7 @@ impl Client {
Ok(result)
}
- pub async fn add_contact(&self, jid: JID) -> Result<(), CommandError<RosterError>> {
+ pub async fn add_contact(&self, jid: BareJID) -> Result<(), CommandError<RosterError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::AddContact(jid, send)))
.await
@@ -350,7 +505,7 @@ impl Client {
Ok(result)
}
- pub async fn buddy_request(&self, jid: JID) -> Result<(), CommandError<SubscribeError>> {
+ pub async fn buddy_request(&self, jid: BareJID) -> Result<(), CommandError<SubscribeError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::BuddyRequest(jid, send)))
.await
@@ -362,7 +517,10 @@ impl Client {
Ok(result)
}
- pub async fn subscription_request(&self, jid: JID) -> Result<(), CommandError<SubscribeError>> {
+ pub async fn subscription_request(
+ &self,
+ jid: BareJID,
+ ) -> Result<(), CommandError<SubscribeError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::SubscriptionRequest(
jid, send,
@@ -376,7 +534,10 @@ impl Client {
Ok(result)
}
- pub async fn accept_buddy_request(&self, jid: JID) -> Result<(), CommandError<SubscribeError>> {
+ pub async fn accept_buddy_request(
+ &self,
+ jid: BareJID,
+ ) -> Result<(), CommandError<SubscribeError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::AcceptBuddyRequest(
jid, send,
@@ -392,7 +553,7 @@ impl Client {
pub async fn accept_subscription_request(
&self,
- jid: JID,
+ jid: BareJID,
) -> Result<(), CommandError<SubscribeError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(
@@ -407,7 +568,10 @@ impl Client {
Ok(result)
}
- pub async fn unsubscribe_from_contact(&self, jid: JID) -> Result<(), CommandError<WriteError>> {
+ pub async fn unsubscribe_from_contact(
+ &self,
+ jid: BareJID,
+ ) -> Result<(), CommandError<WriteError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::UnsubscribeFromContact(
jid, send,
@@ -421,7 +585,7 @@ impl Client {
Ok(result)
}
- pub async fn unsubscribe_contact(&self, jid: JID) -> Result<(), CommandError<WriteError>> {
+ pub async fn unsubscribe_contact(&self, jid: BareJID) -> Result<(), CommandError<WriteError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::UnsubscribeContact(
jid, send,
@@ -435,7 +599,7 @@ impl Client {
Ok(result)
}
- pub async fn unfriend_contact(&self, jid: JID) -> Result<(), CommandError<WriteError>> {
+ pub async fn unfriend_contact(&self, jid: BareJID) -> Result<(), CommandError<WriteError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::UnfriendContact(
jid, send,
@@ -449,7 +613,7 @@ impl Client {
Ok(result)
}
- pub async fn delete_contact(&self, jid: JID) -> Result<(), CommandError<RosterError>> {
+ pub async fn delete_contact(&self, jid: BareJID) -> Result<(), CommandError<RosterError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::DeleteContact(
jid, send,
@@ -465,7 +629,7 @@ impl Client {
pub async fn update_contact(
&self,
- jid: JID,
+ jid: BareJID,
update: ContactUpdate,
) -> Result<(), CommandError<RosterError>> {
let (send, recv) = oneshot::channel();
@@ -493,7 +657,7 @@ impl Client {
Ok(result)
}
- pub async fn send_message(&self, jid: JID, body: Body) -> Result<(), ActorError> {
+ pub async fn send_message(&self, jid: BareJID, body: Body) -> Result<(), ActorError> {
self.send(CoreClientCommand::Command(Command::SendMessage(jid, body)))
.await?;
Ok(())
@@ -539,9 +703,9 @@ impl Client {
&self,
item: pep::Item,
node: String,
- ) -> Result<(), CommandError<PublishError>> {
+ ) -> Result<(), CommandError<PEPError>> {
let (send, recv) = oneshot::channel();
- self.send(CoreClientCommand::Command(Command::Publish {
+ self.send(CoreClientCommand::Command(Command::PublishPEPItem {
item,
node,
sender: send,
@@ -555,7 +719,45 @@ impl Client {
Ok(result)
}
- pub async fn change_nick(&self, nick: String) -> Result<(), CommandError<NickError>> {
+ pub async fn delete_pep_node(&self, node: String) -> Result<(), CommandError<PEPError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::DeletePEPNode {
+ node,
+ sender: send,
+ }))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let result = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(result)
+ }
+
+ pub async fn get_pep_item(
+ &self,
+ // i think this is correct?, should not be able to send pep requests to a full jid.
+ jid: Option<BareJID>,
+ node: String,
+ id: String,
+ ) -> Result<pep::Item, CommandError<PEPError>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::GetPEPItem {
+ jid,
+ node,
+ id,
+ sender: send,
+ }))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let result = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(result)
+ }
+
+ pub async fn change_nick(&self, nick: Option<String>) -> Result<(), CommandError<NickError>> {
let (send, recv) = oneshot::channel();
self.send(CoreClientCommand::Command(Command::ChangeNick(nick, send)))
.await
@@ -566,10 +768,117 @@ impl Client {
.map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
Ok(result)
}
+
+ pub async fn change_avatar(
+ &self,
+ avatar: Option<Vec<u8>>,
+ ) -> Result<(), CommandError<AvatarPublishError<Fs>>> {
+ let (send, recv) = oneshot::channel();
+ self.send(CoreClientCommand::Command(Command::ChangeAvatar(
+ avatar, send,
+ )))
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?;
+ let result = timeout(self.timeout, recv)
+ .await
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?
+ .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??;
+ Ok(result)
+ }
}
-impl From<Command> for CoreClientCommand<Command> {
- fn from(value: Command) -> Self {
+impl<Fs: FileStore> From<Command<Fs>> for CoreClientCommand<Command<Fs>> {
+ fn from(value: Command<Fs>) -> Self {
CoreClientCommand::Command(value)
}
}
+
+#[cfg(test)]
+mod tests {
+ use wasm_bindgen_test::*;
+
+ use super::*;
+
+ wasm_bindgen_test_configure!(run_in_browser);
+
+ use crate::chat;
+ use crate::files::FilesMem;
+ use std::path::Path;
+ use tokio_with_wasm::alias as tokio;
+
+ #[wasm_bindgen_test]
+ async fn login() -> () {
+ tracing_wasm::set_as_global_default();
+ let db = Db::create_connect_and_migrate(Path::new("./filamento.db"))
+ .await
+ .unwrap();
+ let (client, mut recv) = Client::new(
+ "test@blos.sm/testing2".try_into().unwrap(),
+ "slayed".to_string(),
+ db,
+ FilesMem::new(),
+ );
+
+ tokio::spawn(async move {
+ while let Some(msg) = recv.recv().await {
+ info!("{:#?}", msg)
+ }
+ });
+
+ client.connect().await.unwrap();
+ // tokio::time::sleep(Duration::from_secs(5)).await;
+ info!("changing nick");
+ client
+ .change_nick(Some("britney".to_string()))
+ .await
+ .unwrap();
+ let mut data = include_bytes!("../files/britney_starbies.jpg");
+ client.change_avatar(Some(data.to_vec())).await.unwrap();
+ info!("sending message");
+ client
+ .send_message(
+ BareJID::from_str("cel@blos.sm").unwrap(),
+ chat::Body {
+ body: "hallo!!!".to_string(),
+ },
+ )
+ .await
+ .unwrap();
+ info!("sent message");
+ client
+ .send_message(
+ BareJID::from_str("cel@blos.sm").unwrap(),
+ chat::Body {
+ body: "hallo 2".to_string(),
+ },
+ )
+ .await
+ .unwrap();
+ // tokio::time::sleep(Duration::from_secs(15)).await;
+ // info!("sending disco query");
+ // let info = client.disco_info(None, None).await.unwrap();
+ // info!("got disco result: {:#?}", info);
+ // let items = client.disco_items(None, None).await.unwrap();
+ // info!("got disco result: {:#?}", items);
+ // let info = client
+ // .disco_info(Some("blos.sm".parse().unwrap()), None)
+ // .await
+ // .unwrap();
+ // info!("got disco result: {:#?}", info);
+ // let items = client
+ // .disco_items(Some("blos.sm".parse().unwrap()), None)
+ // .await
+ // .unwrap();
+ // info!("got disco result: {:#?}", items);
+ // let info = client
+ // .disco_info(Some("pubsub.blos.sm".parse().unwrap()), None)
+ // .await
+ // .unwrap();
+ // info!("got disco result: {:#?}", info);
+ // let items = client
+ // .disco_items(Some("pubsub.blos.sm".parse().unwrap()), None)
+ // .await
+ // .unwrap();
+ // info!("got disco result: {:#?}", items); let mut jid: JID = "test@blos.sm".try_into().unwrap();
+ }
+}