Skip to main content

iris_chat_core/
updates.rs

1use crate::actions::AppAction;
2use crate::state::{AppState, MutualGroupsSnapshot, PeerProfileDebugSnapshot};
3use crate::DesktopNearbySnapshot;
4use flume::Sender;
5use nostr_sdk::prelude::{Event, RelayStatus};
6
7#[derive(uniffi::Enum, Clone, Debug)]
8#[allow(clippy::large_enum_variant)]
9pub enum AppUpdate {
10    FullState(AppState),
11    PersistAccountBundle {
12        rev: u64,
13        owner_nsec: Option<String>,
14        owner_pubkey_hex: String,
15        device_nsec: String,
16    },
17    PersistPendingDeviceLink {
18        device_nsec: String,
19        approval_bootstrap_json: String,
20    },
21    ClearPendingDeviceLink,
22    NearbyPublishedEvent {
23        event_id: String,
24        kind: u32,
25        created_at_secs: u64,
26        event_json: String,
27    },
28    NearbyPeersChanged {
29        snapshot: DesktopNearbySnapshot,
30        bluetooth_peer_ids: Vec<String>,
31        lan_peer_ids: Vec<String>,
32    },
33}
34
35pub(crate) fn enqueue_update_for_delivery(
36    update: AppUpdate,
37    latest_full_state: &mut Option<AppUpdate>,
38    before_full_state: &mut Vec<AppUpdate>,
39    after_full_state: &mut Vec<AppUpdate>,
40) {
41    match update {
42        full @ AppUpdate::FullState(_) => *latest_full_state = Some(full),
43        nearby
44        @ (AppUpdate::NearbyPublishedEvent { .. } | AppUpdate::NearbyPeersChanged { .. }) => {
45            after_full_state.push(nearby)
46        }
47        other => before_full_state.push(other),
48    }
49}
50
51#[derive(Clone, Debug, PartialEq, Eq)]
52pub(crate) struct FipsNearbyLinkSnapshot {
53    pub(crate) device_pubkey_hex: String,
54    pub(crate) transport_type: String,
55}
56
57#[derive(Debug)]
58pub(crate) enum CoreMsg {
59    Action(AppAction),
60    Internal(Box<InternalEvent>),
61    ExportSupportBundle(Sender<String>),
62    PeerProfileDebug {
63        owner_input: String,
64        reply_tx: Sender<Option<PeerProfileDebugSnapshot>>,
65    },
66    MutualGroups {
67        owner_input: String,
68        reply_tx: Sender<MutualGroupsSnapshot>,
69    },
70    AttachHostBle {
71        attachment: crate::core::HostBleAttachment,
72        reply_tx: Sender<Result<(), String>>,
73    },
74    DetachHostBle(Sender<()>),
75    PrepareForSuspend(Sender<()>),
76    /// Snapshot of core-internal perf counters (debug-snapshot
77    /// rebuild count etc.) — read by `FfiApp::core_perf_counters()`
78    /// so the release-gate budget tests can assert on internal hot
79    /// loops, not just FFI surface traffic.
80    CorePerfCounters(Sender<CorePerfCountersSnapshot>),
81    Shutdown(Option<Sender<()>>),
82    #[cfg(test)]
83    PanicForTest,
84}
85
86#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
87pub(crate) struct CorePerfCountersSnapshot {
88    /// `build_runtime_debug_snapshot` calls since core start.
89    pub debug_snapshot_builds: u64,
90}
91
92#[derive(Debug)]
93pub(crate) enum InternalEvent {
94    RelayEvent(Event),
95    FipsNearbyPacket {
96        source_pubkey_hex: String,
97        source_port: u16,
98        data: Vec<u8>,
99    },
100    FipsNearbyPeersChanged(Vec<FipsNearbyLinkSnapshot>),
101    FetchTrackedPeerCatchUp {
102        token: u64,
103    },
104    ProtocolSubscriptionLivenessCheck {
105        token: u64,
106    },
107    PollPendingDeviceInvites {
108        token: u64,
109    },
110    PollPendingDeviceLink {
111        token: u64,
112    },
113    PendingDeviceLinkRefreshFinished {
114        token: u64,
115        events: Vec<Event>,
116    },
117    PruneExpiredMessages {
118        token: u64,
119    },
120    FetchCatchUpEvents(Vec<Event>),
121    ProfileMetadataFetchFinished {
122        owner_pubkey_hex: String,
123        events: Vec<Event>,
124        error: Option<String>,
125    },
126    DirectChatCapabilityFetchFinished {
127        generation: u64,
128        token: u64,
129        owner_pubkey_hex: String,
130        result: Result<Vec<Event>, String>,
131    },
132    UserDiscoveryFetchFinished {
133        token: u64,
134        result: crate::core::UserDiscoveryFetchResult,
135    },
136    ProfileSearchRequested {
137        query: String,
138    },
139    ProfileSearchDebounceElapsed {
140        token: u64,
141        query: String,
142    },
143    ProfileSearchFetchFinished {
144        token: u64,
145        query: String,
146        result: Result<crate::core::ProfileSearchFetchResult, String>,
147    },
148    RelayStatusChanged {
149        relay_url: String,
150        status: RelayStatus,
151        generation: u64,
152    },
153    ProtocolSubscriptionReconcileCompleted {
154        generation: u64,
155        token: u64,
156        reason: String,
157        plan: Option<crate::core::ProtocolSubscriptionPlan>,
158        success: bool,
159        error: Option<String>,
160        relay_statuses: Vec<(String, RelayStatus)>,
161        connected_before: u64,
162        connected_after: u64,
163        filter_count: u64,
164    },
165    RelayTransportConnectionFinished {
166        token: u64,
167        reason: String,
168        relay_statuses: Vec<(String, RelayStatus)>,
169        connected_count: u64,
170    },
171    #[cfg(not(target_os = "ios"))]
172    DebugSnapshotWriteFinished {
173        generation: u64,
174    },
175    DebugLog {
176        category: String,
177        detail: String,
178    },
179    TypingIndicatorExpired {
180        chat_id: String,
181        author: String,
182    },
183    FlushPendingDeliveredReceipts {
184        token: u64,
185    },
186    RelayPublishDrainFinished {
187        token: u64,
188        results: Vec<RelayPublishDrainResult>,
189    },
190    RelayPublishDrainProgress {
191        token: u64,
192        result: RelayPublishDrainResult,
193    },
194    SessionStartupFollowUp,
195    RetryPendingRelayPublishes {
196        reason: String,
197    },
198    AttachmentUploadFinished {
199        chat_id: String,
200        result: Result<String, String>,
201    },
202    AttachmentUploadProgress {
203        bytes_uploaded: u64,
204        total_bytes: u64,
205    },
206    ProfilePictureUploadFinished {
207        result: Result<String, String>,
208    },
209    GroupPictureUploadFinished {
210        group_id: String,
211        result: Result<String, String>,
212    },
213    SyncComplete,
214    ProtocolAuthorBackfillComplete {
215        reason: String,
216    },
217    // Heavy tail of `open_chat` — DB page load, identity republish,
218    // persist, protocol refresh. Runs on the same event loop as a
219    // queued follow-up so subsequent UI actions (back, switch chat)
220    // can interleave between the screen flip and the load.
221    OpenChatFinalize {
222        chat_id: String,
223    },
224    DeviceSyncPacket {
225        source_pubkey_hex: String,
226        source_port: u16,
227        data: Vec<u8>,
228    },
229}
230
231#[derive(Debug)]
232pub(crate) struct RelayPublishDrainResult {
233    pub(crate) event_id: String,
234    pub(crate) success: bool,
235    pub(crate) relay_urls: Vec<String>,
236    pub(crate) detail: String,
237}