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}