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 CallMedia {
11 call_id: String,
12 kind: u8,
13 sequence: u32,
14 timestamp_us: u64,
15 key_frame: bool,
16 data: Vec<u8>,
17 },
18 FullState(AppState),
19 PersistAccountBundle {
20 rev: u64,
21 owner_nsec: Option<String>,
22 owner_pubkey_hex: String,
23 device_nsec: String,
24 },
25 PersistPendingDeviceLink {
26 device_nsec: String,
27 approval_bootstrap_json: String,
28 },
29 ClearPendingDeviceLink,
30 SignerLoginSignEvent {
31 request_id: String,
32 owner_pubkey_hex: String,
33 unsigned_event_json: String,
34 },
35 NearbyPublishedEvent {
36 event_id: String,
37 kind: u32,
38 created_at_secs: u64,
39 event_json: String,
40 },
41 NearbyPeersChanged {
42 snapshot: DesktopNearbySnapshot,
43 bluetooth_peer_ids: Vec<String>,
44 lan_peer_ids: Vec<String>,
45 },
46}
47
48pub(crate) fn enqueue_update_for_delivery(
49 update: AppUpdate,
50 latest_full_state: &mut Option<AppUpdate>,
51 before_full_state: &mut Vec<AppUpdate>,
52 after_full_state: &mut Vec<AppUpdate>,
53) {
54 match update {
55 full @ AppUpdate::FullState(_) => *latest_full_state = Some(full),
56 nearby @ (AppUpdate::CallMedia { .. }
57 | AppUpdate::NearbyPublishedEvent { .. }
58 | AppUpdate::NearbyPeersChanged { .. }) => after_full_state.push(nearby),
59 other => before_full_state.push(other),
60 }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq)]
64pub(crate) struct FipsNearbyLinkSnapshot {
65 pub(crate) device_pubkey_hex: String,
66 pub(crate) transport_type: String,
67 pub(crate) transport_addr: Option<String>,
68}
69
70#[derive(Debug)]
71pub(crate) enum CoreMsg {
72 Action(AppAction),
73 AcceptDirectFiles {
74 chat_id: String,
75 transfer_id: String,
76 destination: std::sync::Arc<dyn crate::DirectFileDestination>,
77 },
78 Internal(Box<InternalEvent>),
79 ExportSupportBundle(Sender<String>),
80 PeerProfileDebug {
81 owner_input: String,
82 reply_tx: Sender<Option<PeerProfileDebugSnapshot>>,
83 },
84 MutualGroups {
85 owner_input: String,
86 reply_tx: Sender<MutualGroupsSnapshot>,
87 },
88 AttachHostBle {
89 attachment: crate::core::HostBleAttachment,
90 reply_tx: Sender<Result<(), String>>,
91 },
92 DetachHostBle {
93 ownership: crate::core::HostBleOwnership,
94 reply_tx: Sender<()>,
95 },
96 HostBleActivity {
97 ownership: crate::core::HostBleOwnership,
98 generation: u64,
99 active: bool,
100 reply_tx: Sender<bool>,
101 },
102 PrepareForSuspend(Sender<()>),
103 CorePerfCounters(Sender<CorePerfCountersSnapshot>),
108 Shutdown(Option<Sender<()>>),
109 #[cfg(test)]
110 PanicForTest,
111}
112
113#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
114pub(crate) struct CorePerfCountersSnapshot {
115 pub debug_snapshot_builds: u64,
117}
118
119#[derive(Debug)]
120pub(crate) enum InternalEvent {
121 PrivateInviteUploaded {
122 request_id: String,
123 owner: String,
124 device: String,
125 result: Result<String, String>,
126 },
127 PrivateInviteResolved {
128 request_id: String,
129 owner: String,
130 result: Result<crate::invite_record::InviteRecord, String>,
131 },
132 DeviceLinkSignerRepair {
133 token: String,
134 heads: Vec<Event>,
135 reply: tokio::sync::oneshot::Sender<Result<Event, String>>,
136 },
137 DeviceLinkSignerRequest {
138 token: String,
139 unsigned_event_json: String,
140 previous: Option<Event>,
141 reply: tokio::sync::oneshot::Sender<
142 Result<(Event, crate::core::device_link_signer::DeviceLinkInfo), String>,
143 >,
144 },
145 DeviceLinkSignerFinished {
146 token: String,
147 success: bool,
148 error: Option<String>,
149 },
150 PrivateContactSyncTick {
151 generation: u64,
152 },
153 FollowUpdateReady {
154 request_id: String,
155 result: Result<Vec<Event>, String>,
156 },
157 RemoteSignerProgress {
158 token: String,
159 phase: crate::RemoteSignerPhase,
160 auth_url: Option<String>,
161 },
162 RemoteSignerConnected {
163 token: String,
164 owner_pubkey_hex: String,
165 },
166 RemoteSignerSigned {
167 token: String,
168 request_id: String,
169 signed_event_json: String,
170 link_info: Option<crate::core::device_link_signer::DeviceLinkInfo>,
171 },
172 RemoteSignerFailed {
173 token: String,
174 message: String,
175 },
176 DirectFilesPrepared {
177 generation: u64,
178 device: String,
179 result: Result<crate::core::direct_files::Record, String>,
180 },
181 DirectFile {
182 generation: u64,
183 event: crate::core::direct_file_tcp::DirectFileEvent,
184 },
185 CallPacket {
186 source_pubkey_hex: String,
187 source_port: u16,
188 data: Vec<u8>,
189 },
190 CallMediaBatch {
191 packets: Vec<(String, u16, Vec<u8>)>,
192 received_at: std::time::Instant,
193 _permit: tokio::sync::OwnedSemaphorePermit,
195 },
196 CallRecoveryTick {
197 call_id: String,
198 },
199 CallTick {
200 call_id: String,
201 },
202 SignerLoginFetched {
203 request_id: String,
204 result: Result<Option<Event>, String>,
205 },
206 SignerLoginPublished {
207 request_id: String,
208 result: Result<Event, String>,
209 },
210 SignerLoginTimedOut {
211 request_id: String,
212 },
213 RelayEvent(Event),
214 MeshEvent(Event),
215 FipsNearbyPacket {
216 source_pubkey_hex: String,
217 source_port: u16,
218 data: Vec<u8>,
219 },
220 FipsNearbyPeersChanged {
221 generation: u64,
222 peers: Vec<FipsNearbyLinkSnapshot>,
223 },
224 FipsPeerDiscoveryNeeded {
225 generation: u64,
226 author: nostr::PublicKey,
227 requires_pending_work: bool,
228 },
229 FetchTrackedPeerCatchUp {
230 token: u64,
231 },
232 ProtocolSubscriptionLivenessCheck {
233 token: u64,
234 },
235 RetryReadyProtocolWork {
236 due_at: tokio::time::Instant,
237 },
238 PollPendingDeviceInvites {
239 token: u64,
240 },
241 PollPendingDeviceLink {
242 token: u64,
243 },
244 PendingDeviceLinkRefreshFinished {
245 token: u64,
246 events: Vec<Event>,
247 },
248 ExpireChatMutes {
249 token: u64,
250 },
251 PruneExpiredMessages {
252 token: u64,
253 },
254 FetchCatchUpEvents(Vec<Event>),
255 ProfileMetadataFetchFinished {
256 owner_pubkey_hex: String,
257 events: Vec<Event>,
258 error: Option<String>,
259 },
260 DirectChatCapabilityFetchFinished {
261 generation: u64,
262 token: u64,
263 owner_pubkey_hex: String,
264 result: Result<Vec<Event>, String>,
265 },
266 UserDiscoveryFetchFinished {
267 token: u64,
268 result: crate::core::UserDiscoveryFetchResult,
269 },
270 ProfileSearchRequested {
271 query: String,
272 },
273 ProfileSearchDebounceElapsed {
274 token: u64,
275 query: String,
276 },
277 ProfileSearchFetchFinished {
278 token: u64,
279 query: String,
280 result: Result<crate::core::ProfileSearchFetchResult, String>,
281 },
282 ProfileSearchCapabilitiesReady {
283 token: u64,
284 query: String,
285 events: Vec<Event>,
286 },
287 RelayStatusChanged {
288 relay_url: String,
289 status: RelayStatus,
290 generation: u64,
291 },
292 ProtocolSubscriptionReconcileCompleted {
293 generation: u64,
294 token: u64,
295 reason: String,
296 plan: Option<crate::core::ProtocolSubscriptionPlan>,
297 success: bool,
298 error: Option<String>,
299 relay_statuses: Vec<(String, RelayStatus)>,
300 connected_before: u64,
301 connected_after: u64,
302 filter_count: u64,
303 },
304 RelayTransportConnectionFinished {
305 token: u64,
306 reason: String,
307 relay_statuses: Vec<(String, RelayStatus)>,
308 connected_count: u64,
309 },
310 #[cfg(not(target_os = "ios"))]
311 DebugSnapshotWriteFinished {
312 generation: u64,
313 },
314 DebugLog {
315 category: String,
316 detail: String,
317 },
318 TypingIndicatorExpired {
319 chat_id: String,
320 author: String,
321 },
322 FlushPendingDeliveredReceipts {
323 token: u64,
324 },
325 RelayPublishDrainFinished {
326 token: u64,
327 results: Vec<RelayPublishDrainResult>,
328 },
329 RelayPublishDrainProgress {
330 token: u64,
331 result: RelayPublishDrainResult,
332 },
333 SessionStartupFollowUp,
334 RetryPendingRelayPublishes {
335 reason: String,
336 },
337 AttachmentReceiptsUpdated,
338 AttachmentUploadFinished {
339 store_id: u64,
340 chat_id: String,
341 result: Result<String, String>,
342 },
343 AttachmentUploadProgress {
344 store_id: u64,
345 bytes_uploaded: u64,
346 total_bytes: u64,
347 },
348 ProfilePictureUploadFinished {
349 result: Result<String, String>,
350 },
351 GroupPictureUploadFinished {
352 group_id: String,
353 result: Result<String, String>,
354 },
355 SyncComplete,
356 OwnerRegistrationLookupFinished {
357 generation: u64,
358 owner: nostr::PublicKey,
359 device: nostr::PublicKey,
360 completed: usize,
361 queried: usize,
362 events: Vec<Event>,
363 },
364 ProtocolAuthorBackfillComplete {
365 reason: String,
366 },
367 OpenChatFinalize {
372 chat_id: String,
373 },
374 DeviceSyncPacket {
375 source_pubkey_hex: String,
376 source_port: u16,
377 data: Vec<u8>,
378 },
379}
380
381#[derive(Debug)]
382pub(crate) struct RelayPublishDrainResult {
383 pub(crate) event_id: String,
384 pub(crate) success: bool,
385 pub(crate) relay_urls: Vec<String>,
386 pub(crate) detail: String,
387}