Skip to main content

huddle_core/app/
events.rs

1use libp2p::PeerId;
2
3#[derive(Debug, Clone)]
4pub struct DiscoveredRoom {
5    pub room_id: String,
6    pub name: String,
7    pub encrypted: bool,
8    pub member_count: u32,
9    pub creator_fingerprint: String,
10    pub last_seen: i64,
11    /// True for rooms loaded from local storage that we haven't rejoined
12    /// yet this session (encrypted rooms whose passphrase key isn't in
13    /// memory). The lobby renders these with a "saved" hint; pressing
14    /// Enter goes through the join flow with passphrase prompt.
15    pub restorable: bool,
16}
17
18#[derive(Debug, Clone)]
19pub enum AppEvent {
20    /// A room was discovered (announced on the global topic).
21    RoomDiscovered(DiscoveredRoom),
22    /// A previously-discovered room hasn't been re-announced — TTL expired.
23    RoomLost { room_id: String },
24    /// We successfully joined a room (subscribed to its topic).
25    RoomJoined { room_id: String },
26    /// We left a room.
27    RoomLeft { room_id: String },
28    /// A new member appeared in a room we're in.
29    MemberJoined {
30        room_id: String,
31        fingerprint: String,
32    },
33    /// A member left a room we're in.
34    MemberLeft {
35        room_id: String,
36        fingerprint: String,
37    },
38    /// A message arrived in a room.
39    MessageReceived {
40        room_id: String,
41        sender_fingerprint: String,
42        body: String,
43        sent_at: i64,
44    },
45    /// Our own message was sent successfully.
46    MessageSent {
47        room_id: String,
48        body: String,
49        message_id: i64,
50    },
51    /// Listening on a network address.
52    ListeningOn { address: String },
53    /// A peer was discovered on the LAN.
54    PeerDiscovered { peer_id: PeerId },
55    /// A peer's mDNS presence expired — they left the LAN or stopped
56    /// announcing. The lobby refreshes its online/offline indicators.
57    PeerExpired { peer_id: PeerId },
58    /// We've fired a dial command — useful for the UI to show "dialing...".
59    Dialing { address: String },
60    /// A user-initiated dial completed successfully.
61    DialSucceeded { address: String, peer_id: PeerId },
62    /// A user-initiated dial failed.
63    DialFailed { address: String, error: String },
64    /// Non-fatal error.
65    Error { description: String },
66    /// Someone (us or a peer) offered a file in a room.
67    FileOffered {
68        room_id: String,
69        file_id: String,
70        name: String,
71        size_bytes: u64,
72        sender_fingerprint: String,
73    },
74    /// A chunk of an incoming transfer arrived. `total_bytes` is the
75    /// announced size from the offer.
76    FileProgress {
77        file_id: String,
78        bytes_received: u64,
79        total_bytes: u64,
80    },
81    /// All chunks of a transfer received and SHA-256 verified.
82    FileReady { file_id: String },
83    /// User saved a ready file to Downloads.
84    FileSaved { file_id: String, path: String },
85    /// A transfer failed (hash mismatch, decrypt error, IO error).
86    FileFailed { file_id: String, reason: String },
87    /// A peer initiated a key rotation in a room we're in. The UI
88    /// surfaces a modal asking the user to enter the new passphrase.
89    RotationRequested {
90        room_id: String,
91        rotator_fingerprint: String,
92        new_salt: Vec<u8>,
93    },
94    /// Someone in a room started typing. The UI re-reads typing peers
95    /// from `AppHandle::typers_in_room` on each render; the event is
96    /// just a nudge.
97    TypingChanged { room_id: String },
98    /// A received message included our fingerprint (full or short
99    /// form). The TUI uses this to ring the terminal bell, even in
100    /// muted rooms.
101    MentionReceived { room_id: String, body: String },
102    /// Phase A: an unknown peer has dialed us and Identify has
103    /// completed. The TUI shows an accept/reject/trust modal with the
104    /// peer's short fingerprint. Routed through `replace_modal_if_idle`
105    /// so it doesn't clobber whatever the user is typing.
106    InboundDial {
107        peer_id: PeerId,
108        /// 24-char fingerprint, freshly derived from the peer's Ed25519
109        /// pubkey via Identify — proves they hold the matching key.
110        fingerprint: String,
111        /// String form of the listener-side multiaddr (the address as
112        /// seen from our side of the connection). Mostly informational
113        /// for the user; we persist it on accept so the lobby online
114        /// dot tracks the peer.
115        address: String,
116    },
117    /// Phase G: SAS code is ready on both sides — both ephemeral
118    /// X25519 pubkeys exchanged + ECDH derived. The TUI shows the
119    /// `code` (emoji + decimal) and the Match/Cancel buttons.
120    SasCodeReady {
121        room_id: String,
122        partner_fingerprint: String,
123        tx_id: String,
124        emoji_string: String,
125        emoji_labels: String,
126        decimal: String,
127    },
128    /// Phase G: SAS completed — both sides confirmed the match. The
129    /// partner's fingerprint is now verified (per-room + global).
130    SasVerified {
131        room_id: String,
132        partner_fingerprint: String,
133    },
134}