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/presence.rs | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 filamento/src/presence.rs (limited to 'filamento/src/presence.rs') diff --git a/filamento/src/presence.rs b/filamento/src/presence.rs new file mode 100644 index 0000000..e35761c --- /dev/null +++ b/filamento/src/presence.rs @@ -0,0 +1,151 @@ +use chrono::{DateTime, Utc}; +use sqlx::Sqlite; +use stanza::{client::presence::String1024, xep_0203::Delay}; + +#[derive(Debug, Default, sqlx::FromRow, Clone)] +pub struct Online { + pub show: Option, + #[sqlx(rename = "message")] + pub status: Option, + #[sqlx(skip)] + pub priority: Option, +} + +#[derive(Debug, Clone, Copy)] +pub enum Show { + Away, + Chat, + DoNotDisturb, + ExtendedAway, +} + +impl sqlx::Type for Show { + fn type_info() -> ::TypeInfo { + <&str as sqlx::Type>::type_info() + } +} + +impl sqlx::Decode<'_, Sqlite> for Show { + fn decode( + value: ::ValueRef<'_>, + ) -> Result { + let value = <&str as sqlx::Decode>::decode(value)?; + match value { + "away" => Ok(Self::Away), + "chat" => Ok(Self::Chat), + "do-not-disturb" => Ok(Self::DoNotDisturb), + "extended-away" => Ok(Self::ExtendedAway), + _ => unreachable!(), + } + } +} + +impl sqlx::Encode<'_, Sqlite> for Show { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'_>, + ) -> Result { + let value = match self { + Show::Away => "away", + Show::Chat => "chat", + Show::DoNotDisturb => "do-not-disturb", + Show::ExtendedAway => "extended-away", + }; + <&str as sqlx::Encode>::encode(value, buf) + } +} + +#[derive(Debug, Default, Clone)] +pub struct Offline { + pub status: Option, +} + +#[derive(Debug, Clone)] +pub enum PresenceType { + Online(Online), + Offline(Offline), +} + +#[derive(Debug, Clone)] +pub struct Presence { + pub timestamp: DateTime, + pub presence: PresenceType, +} + +impl Online { + pub fn into_stanza( + self, + timestamp: Option>, + ) -> stanza::client::presence::Presence { + stanza::client::presence::Presence { + from: None, + id: None, + to: None, + r#type: None, + lang: None, + show: self.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: self.status.map(|status| stanza::client::presence::Status { + lang: None, + status: String1024(status), + }), + priority: self + .priority + .map(|priority| stanza::client::presence::Priority(priority)), + errors: Vec::new(), + delay: timestamp.map(|timestamp| Delay { + from: None, + stamp: timestamp, + }), + } + } +} + +impl Offline { + pub fn into_stanza( + self, + timestamp: Option>, + ) -> stanza::client::presence::Presence { + stanza::client::presence::Presence { + from: None, + id: None, + to: None, + r#type: Some(stanza::client::presence::PresenceType::Unavailable), + lang: None, + show: None, + status: self.status.map(|status| stanza::client::presence::Status { + lang: None, + status: String1024(status), + }), + priority: None, + errors: Vec::new(), + delay: timestamp.map(|timestamp| Delay { + from: None, + stamp: timestamp, + }), + } + } +} + +impl From for stanza::client::presence::Presence { + fn from(value: PresenceType) -> Self { + match value { + PresenceType::Online(online) => online.into_stanza(None), + PresenceType::Offline(offline) => offline.into_stanza(None), + } + } +} + +impl From for stanza::client::presence::Presence { + fn from(value: Presence) -> Self { + match value.presence { + PresenceType::Online(online) => online.into_stanza(Some(value.timestamp)), + PresenceType::Offline(offline) => offline.into_stanza(Some(value.timestamp)), + } + } +} -- cgit