Skip to main content

de_mls/app/
display.rs

1use std::fmt;
2
3use crate::protos::de_mls::messages::v1::{
4    ConversationUpdateRequest, ViolationEvidence, ViolationType, app_message,
5    conversation_update_request,
6};
7
8// ─────────────────────────── Member Role ───────────────────────────
9
10/// A member's steward-list role for a given epoch.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum MemberRole {
13    /// Epoch steward for this epoch.
14    EpochSteward,
15    /// Backup steward for this epoch.
16    BackupSteward,
17    /// On the steward list but not in the epoch or backup slot.
18    Steward,
19    /// Not on the steward list.
20    Member,
21}
22
23impl fmt::Display for MemberRole {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            MemberRole::EpochSteward => write!(f, "epoch_steward"),
27            MemberRole::BackupSteward => write!(f, "backup_steward"),
28            MemberRole::Steward => write!(f, "steward"),
29            MemberRole::Member => write!(f, "member"),
30        }
31    }
32}
33
34// ─────────────────────────── Message Type Labels ───────────────────────────
35
36/// String constants shared with the UI so string-keyed dispatch stays typo-safe.
37pub mod message_types {
38    pub const CONVERSATION_MESSAGE: &str = "ConversationMessage";
39    pub const BAN_REQUEST: &str = "BanRequest";
40    pub const PROPOSAL: &str = "Proposal";
41    pub const VOTE: &str = "Vote";
42    pub const VOTE_PAYLOAD: &str = "VotePayload";
43    pub const USER_VOTE: &str = "UserVote";
44    pub const PROPOSAL_ADDED: &str = "ProposalAdded";
45    pub const COMMIT_CANDIDATE: &str = "CommitCandidate";
46    pub const CONVERSATION_SYNC: &str = "ConversationSync";
47    pub const UNKNOWN: &str = "Unknown";
48}
49
50/// Maps a protobuf message to a stable label string for the UI.
51pub trait MessageType {
52    fn message_type(&self) -> &'static str;
53}
54
55impl MessageType for app_message::Payload {
56    fn message_type(&self) -> &'static str {
57        match self {
58            app_message::Payload::ConversationMessage(_) => message_types::CONVERSATION_MESSAGE,
59            app_message::Payload::BanRequest(_) => message_types::BAN_REQUEST,
60            app_message::Payload::Proposal(_) => message_types::PROPOSAL,
61            app_message::Payload::Vote(_) => message_types::VOTE,
62            app_message::Payload::VotePayload(_) => message_types::VOTE_PAYLOAD,
63            app_message::Payload::UserVote(_) => message_types::USER_VOTE,
64            app_message::Payload::ProposalAdded(_) => message_types::PROPOSAL_ADDED,
65            app_message::Payload::CommitCandidate(_) => message_types::COMMIT_CANDIDATE,
66            app_message::Payload::ConversationSync(_) => message_types::CONVERSATION_SYNC,
67        }
68    }
69}
70
71impl MessageType for ConversationUpdateRequest {
72    fn message_type(&self) -> &'static str {
73        match &self.payload {
74            Some(conversation_update_request::Payload::InviteMember(_)) => "Add Member",
75            Some(conversation_update_request::Payload::RemoveMember(_)) => "Remove Member",
76            Some(conversation_update_request::Payload::EmergencyCriteria(ec)) => ec
77                .evidence
78                .as_ref()
79                .map(|e| match ViolationType::try_from(e.violation_type) {
80                    Ok(ViolationType::BrokenCommit) => "Emergency: Broken Commit",
81                    Ok(ViolationType::BrokenMlsProposal) => "Emergency: Broken MLS Proposal",
82                    Ok(ViolationType::CensorshipInactivity) => "Emergency: Censorship/Inactivity",
83                    Ok(ViolationType::ScoreBelowThreshold) => "Emergency: Score Below Threshold",
84                    _ => "Emergency: Unknown Violation",
85                })
86                .unwrap_or("Emergency: Unknown Violation"),
87            Some(conversation_update_request::Payload::StewardElection(_)) => "Steward Election",
88            _ => "Unknown",
89        }
90    }
91}
92
93// ─────────────────────────── Violation Labels ───────────────────────────
94
95impl ViolationEvidence {
96    /// Human-readable label for the violation type.
97    pub fn violation_type_label(&self) -> &'static str {
98        match ViolationType::try_from(self.violation_type) {
99            Ok(ViolationType::BrokenCommit) => "Broken Commit",
100            Ok(ViolationType::BrokenMlsProposal) => "Broken MLS Proposal",
101            Ok(ViolationType::CensorshipInactivity) => "Censorship/Inactivity",
102            Ok(ViolationType::ScoreBelowThreshold) => "Score Below Threshold",
103            _ => "Unknown Violation",
104        }
105    }
106}