rustybook-messenger 0.2.1

Messenger client for Rustybook
Documentation
use serde_json::Value;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TaskLabel {
    SendMessage,
    MarkRead,
    MarkUnread,
    UnsendMessage,
    ReactMessage,
    SearchMessage,
    PinMessage,
    TypingIndicator,
    CreateGroup,
    SendGroupBootstrap,
    ChangeThreadApproval,
    ChangeThreadMessageShare,
    ChangeReadReceipts,
    AddParticipants,
    RemoveParticipant,
    SetThreadAdmin,
    ChangeThreadImage,
    ChangeThreadName,
    ChangeThreadTheme,
    ChangeThreadEmoji,
    ChangeNickname,
    MuteThreadMessages,
    MuteThreadCalls,
    RestrictUser,
    RemovePinnedThreadOnRestrict,
    AcceptFriendRequest,
    ThreadRangeQuery,
    ContactQuery,
    IntegrityCheck,
    SearchContacts,
    PullMailbox,
    ProjectSync,
    Unknown(String),
}

impl TaskLabel {
    pub fn parse(code: &str) -> Self {
        match code {
            "46" => Self::SendMessage,
            "21" => Self::MarkRead,
            "49" => Self::MarkUnread,
            "33" => Self::UnsendMessage,
            "29" => Self::ReactMessage,
            "107" => Self::SearchMessage,
            "751" => Self::PinMessage,
            "3" => Self::TypingIndicator,
            "153" => Self::CreateGroup,
            "130" => Self::SendGroupBootstrap,
            "28" => Self::ChangeThreadApproval,
            "210002" => Self::ChangeThreadMessageShare,
            "60003" => Self::ChangeReadReceipts,
            "23" => Self::AddParticipants,
            "140" => Self::RemoveParticipant,
            "25" => Self::SetThreadAdmin,
            "37" => Self::ChangeThreadImage,
            "32" => Self::ChangeThreadName,
            "43" => Self::ChangeThreadTheme,
            "100003" => Self::ChangeThreadEmoji,
            "44" => Self::ChangeNickname,
            "144" => Self::MuteThreadMessages,
            "229" => Self::MuteThreadCalls,
            "367" => Self::RestrictUser,
            "810" => Self::RemovePinnedThreadOnRestrict,
            "207" => Self::AcceptFriendRequest,
            "145" => Self::ThreadRangeQuery,
            "701" => Self::IntegrityCheck,
            "452" => Self::SearchContacts,
            "17" => Self::PullMailbox,
            "351" => Self::ProjectSync,
            unknown => Self::Unknown(unknown.to_string()),
        }
    }

    pub fn code(&self) -> &str {
        match self {
            Self::SendMessage => "46",
            Self::MarkRead => "21",
            Self::MarkUnread => "49",
            Self::UnsendMessage => "33",
            Self::ReactMessage => "29",
            Self::SearchMessage => "107",
            Self::PinMessage => "751",
            Self::TypingIndicator => "3",
            Self::CreateGroup => "153",
            Self::SendGroupBootstrap => "130",
            Self::ChangeThreadApproval => "28",
            Self::ChangeThreadMessageShare => "210002",
            Self::ChangeReadReceipts => "60003",
            Self::AddParticipants => "23",
            Self::RemoveParticipant => "140",
            Self::SetThreadAdmin => "25",
            Self::ChangeThreadImage => "37",
            Self::ChangeThreadName => "32",
            Self::ChangeThreadTheme => "43",
            Self::ChangeThreadEmoji => "100003",
            Self::ChangeNickname => "44",
            Self::MuteThreadMessages => "144",
            Self::MuteThreadCalls => "229",
            Self::RestrictUser => "367",
            Self::RemovePinnedThreadOnRestrict => "810",
            Self::AcceptFriendRequest => "207",
            Self::ThreadRangeQuery => "145",
            Self::ContactQuery => "207",
            Self::IntegrityCheck => "701",
            Self::SearchContacts => "452",
            Self::PullMailbox => "17",
            Self::ProjectSync => "351",
            Self::Unknown(code) => code,
        }
    }

    pub fn name(&self) -> &'static str {
        match self {
            Self::SendMessage => "send_message",
            Self::MarkRead => "mark_read",
            Self::MarkUnread => "mark_unread",
            Self::UnsendMessage => "unsend_message",
            Self::ReactMessage => "react_message",
            Self::SearchMessage => "search_message",
            Self::PinMessage => "pin_message",
            Self::TypingIndicator => "typing_indicator",
            Self::CreateGroup => "create_group",
            Self::SendGroupBootstrap => "send_group_bootstrap",
            Self::ChangeThreadApproval => "change_thread_approval",
            Self::ChangeThreadMessageShare => "change_thread_message_share",
            Self::ChangeReadReceipts => "change_read_receipts",
            Self::AddParticipants => "add_participants",
            Self::RemoveParticipant => "remove_participant",
            Self::SetThreadAdmin => "set_thread_admin",
            Self::ChangeThreadImage => "change_thread_image",
            Self::ChangeThreadName => "change_thread_name",
            Self::ChangeThreadTheme => "change_thread_theme",
            Self::ChangeThreadEmoji => "change_thread_emoji",
            Self::ChangeNickname => "change_nickname",
            Self::MuteThreadMessages => "mute_thread_messages",
            Self::MuteThreadCalls => "mute_thread_calls",
            Self::RestrictUser => "restrict_user",
            Self::RemovePinnedThreadOnRestrict => "remove_pinned_thread_on_restrict",
            Self::AcceptFriendRequest => "accept_friend_request",
            Self::ThreadRangeQuery => "thread_range_query",
            Self::ContactQuery => "contact_query",
            Self::IntegrityCheck => "integrity_check",
            Self::SearchContacts => "search_contacts",
            Self::PullMailbox => "pull_mailbox",
            Self::ProjectSync => "project_sync",
            Self::Unknown(_) => "unknown",
        }
    }
}

#[derive(Debug, Clone)]
pub struct Task {
    pub label: TaskLabel,
    pub label_code: String,
    pub payload: Value,
    pub queue_name: String,
    pub task_id: Option<u64>,
    pub failure_count: Option<u64>,
    pub raw: Value,
}

impl Task {
    pub fn new(label: TaskLabel, payload: Value, queue_name: String, task_id: u64) -> Self {
        let label_code = label.code().to_string();
        Self {
            label,
            label_code,
            payload,
            queue_name,
            task_id: Some(task_id),
            failure_count: None,
            raw: Value::Null,
        }
    }

    pub fn parse(raw: &Value) -> Option<Self> {
        let label_code = raw.get("label")?.as_str()?.to_string();
        let payload = decode_task_payload(raw.get("payload"));
        let queue_name = raw
            .get("queue_name")
            .and_then(Value::as_str)
            .map(ToString::to_string)
            .unwrap_or_default();
        let task_id = raw.get("task_id").and_then(|value| {
            value
                .as_u64()
                .or_else(|| value.as_str()?.parse::<u64>().ok())
        });
        let failure_count = raw.get("failure_count").and_then(|value| {
            value
                .as_u64()
                .or_else(|| value.as_str()?.parse::<u64>().ok())
        });

        Some(Self {
            label: TaskLabel::parse(&label_code),
            label_code,
            payload,
            queue_name,
            task_id,
            failure_count,
            raw: raw.clone(),
        })
    }

    pub fn encode_value(&self) -> Value {
        let payload = if self.payload.is_string() {
            self.payload.clone()
        } else {
            Value::String(self.payload.to_string())
        };

        serde_json::json!({
            "failure_count": self.failure_count,
            "label": self.label_code,
            "payload": payload,
            "queue_name": self.queue_name,
            "task_id": self.task_id,
        })
    }
}

fn decode_task_payload(value: Option<&Value>) -> Value {
    match value {
        Some(Value::String(text)) => {
            serde_json::from_str::<Value>(text).unwrap_or_else(|_| Value::String(text.clone()))
        }
        Some(other) => other.clone(),
        None => Value::Null,
    }
}