From 2211f324782cdc617b4b5ecd071178e372539fe4 Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Wed, 26 Mar 2025 14:29:40 +0000 Subject: refactor: rename crates and move client logic to separate crate `filament` --- filamento/src/roster.rs | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 filamento/src/roster.rs (limited to 'filamento/src/roster.rs') diff --git a/filamento/src/roster.rs b/filamento/src/roster.rs new file mode 100644 index 0000000..43c32f5 --- /dev/null +++ b/filamento/src/roster.rs @@ -0,0 +1,127 @@ +use std::collections::HashSet; + +use jid::JID; +use sqlx::Sqlite; + +pub struct ContactUpdate { + pub name: Option, + pub groups: HashSet, +} + +#[derive(Debug, sqlx::FromRow, Clone)] +pub struct Contact { + // jid is the id used to reference everything, but not the primary key + pub user_jid: JID, + pub subscription: Subscription, + /// client user defined name + pub name: Option, + // TODO: avatar, nickname + /// nickname picked by contact + // nickname: Option, + #[sqlx(skip)] + pub groups: HashSet, +} + +#[derive(Debug, Clone)] +pub enum Subscription { + None, + PendingOut, + PendingIn, + PendingInPendingOut, + OnlyOut, + OnlyIn, + OutPendingIn, + InPendingOut, + Buddy, + // TODO: perhaps don't need, just emit event to remove contact + // Remove, +} + +impl sqlx::Type for Subscription { + fn type_info() -> ::TypeInfo { + <&str as sqlx::Type>::type_info() + } +} + +impl sqlx::Decode<'_, Sqlite> for Subscription { + fn decode( + value: ::ValueRef<'_>, + ) -> Result { + let value = <&str as sqlx::Decode>::decode(value)?; + match value { + "none" => Ok(Self::None), + "pending-out" => Ok(Self::PendingOut), + "pending-in" => Ok(Self::PendingIn), + "pending-in-pending-out" => Ok(Self::PendingInPendingOut), + "only-out" => Ok(Self::OnlyOut), + "only-in" => Ok(Self::OnlyIn), + "out-pending-in" => Ok(Self::OutPendingIn), + "in-pending-out" => Ok(Self::InPendingOut), + "buddy" => Ok(Self::Buddy), + _ => panic!("unexpected subscription `{value}`"), + } + } +} + +impl sqlx::Encode<'_, Sqlite> for Subscription { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'_>, + ) -> Result { + let value = match self { + Subscription::None => "none", + Subscription::PendingOut => "pending-out", + Subscription::PendingIn => "pending-in", + Subscription::PendingInPendingOut => "pending-in-pending-out", + Subscription::OnlyOut => "only-out", + Subscription::OnlyIn => "only-in", + Subscription::OutPendingIn => "out-pending-in", + Subscription::InPendingOut => "in-pending-out", + Subscription::Buddy => "buddy", + }; + <&str as sqlx::Encode>::encode(value, buf) + } +} + +// none +// > +// >> +// < +// << +// >< +// >>< +// ><< +// >><< + +impl From for Contact { + fn from(value: stanza::roster::Item) -> Self { + let subscription = match value.ask { + true => match value.subscription { + Some(s) => match s { + stanza::roster::Subscription::Both => Subscription::Buddy, + stanza::roster::Subscription::From => Subscription::InPendingOut, + stanza::roster::Subscription::None => Subscription::PendingOut, + stanza::roster::Subscription::Remove => Subscription::PendingOut, + stanza::roster::Subscription::To => Subscription::OnlyOut, + }, + None => Subscription::PendingOut, + }, + false => match value.subscription { + Some(s) => match s { + stanza::roster::Subscription::Both => Subscription::Buddy, + stanza::roster::Subscription::From => Subscription::OnlyIn, + stanza::roster::Subscription::None => Subscription::None, + stanza::roster::Subscription::Remove => Subscription::None, + stanza::roster::Subscription::To => Subscription::OnlyOut, + }, + None => Subscription::None, + }, + }; + Contact { + user_jid: value.jid, + subscription, + name: value.name, + groups: HashSet::from_iter(value.groups.into_iter().filter_map(|group| group.0)), + } + } +} -- cgit