aboutsummaryrefslogtreecommitdiffstats
path: root/filamento/src/presence.rs
diff options
context:
space:
mode:
Diffstat (limited to 'filamento/src/presence.rs')
-rw-r--r--filamento/src/presence.rs151
1 files changed, 151 insertions, 0 deletions
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<Show>,
+ #[sqlx(rename = "message")]
+ pub status: Option<String>,
+ #[sqlx(skip)]
+ pub priority: Option<i8>,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Show {
+ Away,
+ Chat,
+ DoNotDisturb,
+ ExtendedAway,
+}
+
+impl sqlx::Type<Sqlite> for Show {
+ fn type_info() -> <Sqlite as sqlx::Database>::TypeInfo {
+ <&str as sqlx::Type<Sqlite>>::type_info()
+ }
+}
+
+impl sqlx::Decode<'_, Sqlite> for Show {
+ fn decode(
+ value: <Sqlite as sqlx::Database>::ValueRef<'_>,
+ ) -> Result<Self, sqlx::error::BoxDynError> {
+ let value = <&str as sqlx::Decode<Sqlite>>::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 <Sqlite as sqlx::Database>::ArgumentBuffer<'_>,
+ ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
+ let value = match self {
+ Show::Away => "away",
+ Show::Chat => "chat",
+ Show::DoNotDisturb => "do-not-disturb",
+ Show::ExtendedAway => "extended-away",
+ };
+ <&str as sqlx::Encode<Sqlite>>::encode(value, buf)
+ }
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct Offline {
+ pub status: Option<String>,
+}
+
+#[derive(Debug, Clone)]
+pub enum PresenceType {
+ Online(Online),
+ Offline(Offline),
+}
+
+#[derive(Debug, Clone)]
+pub struct Presence {
+ pub timestamp: DateTime<Utc>,
+ pub presence: PresenceType,
+}
+
+impl Online {
+ pub fn into_stanza(
+ self,
+ timestamp: Option<DateTime<Utc>>,
+ ) -> 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<DateTime<Utc>>,
+ ) -> 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<PresenceType> 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<Presence> 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)),
+ }
+ }
+}