use super::*;
pub(super) struct LoggedInState {
pub(super) owner_pubkey: PublicKey,
pub(super) owner_keys: Option<Keys>,
pub(super) device_keys: Keys,
pub(super) client: Client,
pub(super) relay_urls: Vec<RelayUrl>,
pub(super) authorization_state: LocalAuthorizationState,
}
pub(super) struct PendingLinkedDeviceState {
pub(super) device_keys: Keys,
pub(super) pairing_client: Client,
pub(super) pairing_invite: Invite,
pub(super) pairing_url: String,
pub(super) authorized_app_keys_event: Option<Event>,
pub(super) pending_response: Option<PendingLinkInviteResponse>,
pub(super) refresh_in_flight: bool,
}
pub(super) struct PendingLinkInviteResponse {
pub(super) owner_pubkey: PublicKey,
pub(super) peer_device_id: String,
pub(super) session_state: SessionState,
}
#[derive(Clone)]
pub(super) struct ThreadRecord {
pub(super) chat_id: String,
pub(super) unread_count: u64,
pub(super) updated_at_secs: u64,
pub(super) messages: Vec<ChatMessageSnapshot>,
pub(super) draft: String,
}
impl ThreadRecord {
pub(super) fn unread_message_ids(&self) -> HashSet<String> {
self.messages
.iter()
.rev()
.filter(|message| {
!message.is_outgoing && !matches!(message.delivery, DeliveryState::Seen)
})
.take(usize::try_from(self.unread_count).unwrap_or(usize::MAX))
.map(|message| message.id.clone())
.collect()
}
pub(super) fn insert_message_sorted(&mut self, message: ChatMessageSnapshot) {
let position = self
.messages
.partition_point(|existing| message_order_key(existing) <= message_order_key(&message));
self.messages.insert(position, message);
}
}
fn message_order_key(message: &ChatMessageSnapshot) -> u64 {
message.created_at_secs
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct ChatReadState {
pub(super) updated_at_ms: u64,
pub(super) device_id: String,
pub(super) seen_through_secs: u64,
pub(super) seen_at_boundary: std::collections::BTreeSet<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub(super) seen_messages: BTreeMap<String, MessageReadState>,
}
pub(super) const MAX_RECENT_READ_IDS: usize = 128;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct MessageReadState {
pub(super) created_at_secs: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) expires_at_secs: Option<u64>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub(super) struct KnownAppKeys {
pub(super) owner_pubkey_hex: String,
pub(super) created_at_secs: u64,
pub(super) devices: Vec<KnownAppKeyDevice>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub(super) struct KnownAppKeyDevice {
pub(super) identity_pubkey_hex: String,
pub(super) created_at_secs: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) device_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) client_label: Option<String>,
#[serde(default)]
pub(super) label_updated_at_secs: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum DirectChatCapabilityCheckState {
Checking,
Unavailable,
CheckFailed,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct DirectChatCapabilityCheck {
pub(super) token: u64,
pub(super) owner_pubkey_hex: String,
pub(super) state: DirectChatCapabilityCheckState,
}
#[derive(Clone, Debug, Default)]
pub(super) struct DirectChatCapabilityRuntime {
pub(super) generation: u64,
pub(super) next_token: u64,
pub(super) current: Option<DirectChatCapabilityCheck>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub(super) struct UserDiscoveryCache {
#[serde(default)]
pub(super) follow_event_json: Option<String>,
pub(super) owner_pubkey_hex: Option<String>,
pub(super) follow_event_id: Option<String>,
pub(super) follow_created_at_secs: u64,
pub(super) users: BTreeMap<String, DiscoveredUserRecord>,
pub(super) social_rank_ready: bool,
pub(super) social_friend_support: BTreeMap<String, u16>,
#[serde(default)]
pub(super) social_graph: Option<Vec<u8>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub(super) struct DiscoveredUserRecord {
pub(super) owner_pubkey_hex: String,
pub(super) follow_position: u32,
pub(super) petname: Option<String>,
}
#[derive(Clone, Debug, Default)]
pub(super) struct UserDiscoveryRuntime {
pub(super) token: u64,
pub(super) in_flight: bool,
pub(super) refresh_pending: bool,
pub(super) last_started_at: Option<Instant>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct ProfileSearchCandidate {
pub(super) owner_pubkey_hex: String,
pub(super) name: String,
pub(super) aliases: Vec<String>,
pub(super) nip05: Option<String>,
pub(super) picture: Option<String>,
pub(super) created_at_secs: u64,
}
#[derive(Debug, Default)]
pub(super) struct ProfileSearchRuntime {
pub(super) token: u64,
pub(super) query: String,
pub(super) debounce_pending: bool,
pub(super) in_flight: bool,
pub(super) recent_attempts: VecDeque<(String, Instant)>,
pub(super) fetch_task: Option<tokio::task::AbortHandle>,
}
#[derive(Debug)]
pub(crate) struct ProfileSearchFetchResult {
pub(super) candidates: Vec<ProfileSearchCandidate>,
pub(super) app_keys_events: Vec<Event>,
pub(super) detail: String,
}
#[derive(Debug)]
pub(crate) struct UserDiscoveryFetchResult {
pub(super) cache: UserDiscoveryCache,
pub(super) metadata_events: Vec<Event>,
pub(super) detail: String,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(super) struct CurrentDeviceLabels {
pub(super) device_label: Option<String>,
pub(super) client_label: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub(super) struct OwnerProfileRecord {
#[serde(default)]
pub(super) source_event_id: Option<String>,
#[serde(default)]
pub(super) contact_memory: crate::contact_memory::ContactMemory,
#[serde(default)]
pub(super) nickname: Option<String>,
#[serde(default)]
pub(super) contact_note: Option<String>,
#[serde(default)]
pub(super) contact_updated_at_ms: u64,
#[serde(default)]
pub(super) name: Option<String>,
#[serde(default)]
pub(super) display_name: Option<String>,
#[serde(default)]
pub(super) picture: Option<String>,
#[serde(default)]
pub(super) about: Option<String>,
#[serde(default = "default_extra_metadata_json")]
pub(super) extra_metadata_json: String,
#[serde(default)]
pub(super) extra_tags: Vec<Vec<String>>,
#[serde(default)]
pub(super) updated_at_secs: u64,
}
fn default_extra_metadata_json() -> String {
"{}".to_string()
}
impl Default for OwnerProfileRecord {
fn default() -> Self {
Self {
source_event_id: None,
contact_memory: Default::default(),
nickname: None,
contact_note: None,
contact_updated_at_ms: 0,
name: None,
display_name: None,
picture: None,
about: None,
extra_metadata_json: default_extra_metadata_json(),
extra_tags: Vec::new(),
updated_at_secs: 0,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct TypingIndicatorRecord {
pub(super) chat_id: String,
pub(super) author_owner_hex: String,
pub(super) expires_at_secs: u64,
pub(super) last_event_secs: u64,
}
#[derive(Clone, Debug)]
pub(super) struct RecentHandshakePeer {
pub(super) owner_hex: String,
pub(super) device_hex: String,
pub(super) observed_at_secs: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum LocalAuthorizationState {
Authorized,
AwaitingApproval,
Revoked,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct ProtocolSubscriptionPlan {
pub(crate) runtime_subscriptions: Vec<String>,
pub(crate) roster_authors: Vec<String>,
pub(crate) invite_authors: Vec<String>,
pub(crate) message_authors: Vec<String>,
pub(crate) message_recipients: Vec<String>,
pub(crate) group_roster_group_ids: Vec<String>,
pub(crate) group_roster_authors: Vec<String>,
pub(crate) group_sender_key_authors: Vec<String>,
pub(crate) invite_response_recipient: Option<String>,
}
#[derive(Clone, Debug, Default)]
pub(super) struct ProtocolSubscriptionRuntime {
pub(super) discovery_clients:
std::collections::HashMap<PublicKey, Arc<protocol::private_reads::PrivateDiscoveryClient>>,
pub(super) desired_plan: Option<ProtocolSubscriptionPlan>,
pub(super) applying_plan: Option<ProtocolSubscriptionPlan>,
pub(super) applied_plan: Option<ProtocolSubscriptionPlan>,
pub(super) refresh_token: u64,
pub(super) reconcile_token: u64,
pub(super) refresh_in_flight: bool,
pub(super) refresh_dirty: bool,
pub(super) force_reconnect_dirty: bool,
pub(super) liveness_due_at: Option<Instant>,
pub(super) ready_retry_due_at: Option<Instant>,
pub(super) tracked_peer_catch_up_due_at: Option<Instant>,
pub(super) tracked_peer_catch_up_token: u64,
pub(super) protocol_fetch_in_flight: bool,
pub(super) protocol_author_backfill_in_flight: u64,
pub(super) protocol_fetch_last_started_at: Option<Instant>,
}
#[derive(Debug, Default)]
pub(super) struct RelayTransportRuntime {
pub(super) connect_in_flight: bool,
pub(super) connect_dirty: bool,
pub(super) force_reconnect_dirty: bool,
pub(super) connect_token: u64,
pub(super) connect_started_at: Option<Instant>,
pub(super) publish_drain_in_flight: bool,
pub(super) publish_drain_dirty: bool,
pub(super) publish_drain_token: u64,
pub(super) publish_drain_started_at: Option<Instant>,
pub(super) publish_drain_failed_count: usize,
pub(super) publish_drain_task: Option<RelayPublishDrainTask>,
pub(super) nearby_replay_started_at: Option<Instant>,
pub(super) retry_backoff_attempt: u32,
pub(super) next_retry_due_at: Option<Instant>,
pub(super) next_retry_reason: Option<String>,
pub(super) last_connect_reason: Option<String>,
pub(super) last_drain_reason: Option<String>,
}
#[derive(Debug)]
pub(super) struct RelayPublishDrainTask {
pub(super) abort: tokio::task::AbortHandle,
pub(super) cancelled: Arc<std::sync::atomic::AtomicBool>,
}
impl Drop for RelayPublishDrainTask {
fn drop(&mut self) {
self.cancelled
.store(true, std::sync::atomic::Ordering::Release);
self.abort.abort();
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub(super) struct PendingRelayPublish {
pub(super) owner_pubkey_hex: String,
pub(super) event_id: String,
pub(super) label: String,
pub(super) event_json: String,
pub(super) inner_event_id: Option<String>,
pub(super) chat_id: Option<String>,
pub(super) created_at_secs: u64,
pub(super) attempt_count: u64,
pub(super) last_error: Option<String>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub(super) struct DebugEventCounters {
pub(super) app_keys_events: u64,
pub(super) invite_events: u64,
pub(super) invite_response_events: u64,
pub(super) message_events: u64,
pub(super) group_events: u64,
pub(super) other_events: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct DebugLogEntry {
pub(super) timestamp_secs: u64,
pub(super) category: String,
pub(super) detail: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimeDebugSnapshot {
pub(super) generated_at_secs: u64,
pub(super) local_owner_pubkey_hex: Option<String>,
pub(super) local_device_pubkey_hex: Option<String>,
pub(super) authorization_state: Option<String>,
pub(super) active_chat_id: Option<String>,
pub(super) relay_transport: RuntimeRelayTransportDebug,
pub(super) current_protocol_plan: Option<RuntimeProtocolPlanDebug>,
pub(super) protocol_subscription: RuntimeProtocolSubscriptionDebug,
#[serde(default)]
pub(super) anonymous_discovery: protocol::anonymous_reads::diagnostics::Snapshot,
pub(super) protocol_engine: Option<ProtocolEngineDebugSnapshot>,
pub(super) pending_relay_publishes: Vec<RuntimePendingRelayPublishDebug>,
pub(super) tracked_owner_hexes: Vec<String>,
pub(super) known_users: Vec<RuntimeKnownUserDebug>,
pub(super) recent_handshake_peers: Vec<RuntimeRecentHandshakeDebug>,
pub(super) event_counts: DebugEventCounters,
pub(super) recent_log: Vec<DebugLogEntry>,
pub(super) toast: Option<String>,
pub(super) current_chat_list: Vec<String>,
}
#[derive(Clone, Debug, Serialize)]
pub(super) struct SupportBuildMetadata {
pub(super) app_version: String,
pub(super) build_channel: String,
pub(super) git_sha: String,
pub(super) build_timestamp_utc: String,
pub(super) relay_set_id: String,
pub(super) trusted_test_build: bool,
}
#[derive(Clone, Debug, Serialize)]
pub(super) struct SupportBundle {
pub(super) generated_at_secs: u64,
pub(super) build: SupportBuildMetadata,
pub(super) relay_urls: Vec<String>,
pub(super) local_owner_pubkey_hex: Option<String>,
pub(super) authorization_state: Option<String>,
pub(super) active_chat_id: Option<String>,
pub(super) current_screen: String,
pub(super) relay_transport: RuntimeRelayTransportDebug,
pub(super) protocol_subscription: RuntimeProtocolSubscriptionDebug,
pub(super) anonymous_discovery: protocol::anonymous_reads::diagnostics::Snapshot,
pub(super) chat_count: usize,
pub(super) direct_chat_count: usize,
pub(super) group_chat_count: usize,
pub(super) unread_chat_count: usize,
pub(super) protocol: Option<RuntimeProtocolPlanDebug>,
pub(super) protocol_engine: Option<ProtocolEngineDebugSnapshot>,
pub(super) pending_relay_publishes: Vec<RuntimePendingRelayPublishDebug>,
pub(super) tracked_owner_hexes: Vec<String>,
pub(super) known_users: Vec<RuntimeKnownUserDebug>,
pub(super) recent_handshake_peers: Vec<RuntimeRecentHandshakeDebug>,
pub(super) event_counts: DebugEventCounters,
pub(super) recent_log: Vec<DebugLogEntry>,
pub(super) current_chat_list: Vec<String>,
pub(super) latest_toast: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimeRelayTransportDebug {
pub(super) phase: String,
pub(super) connect_in_flight: bool,
pub(super) connect_dirty: bool,
pub(super) force_reconnect_dirty: bool,
pub(super) connect_age_ms: Option<u64>,
pub(super) publish_drain_in_flight: bool,
pub(super) publish_drain_dirty: bool,
pub(super) publish_drain_age_ms: Option<u64>,
pub(super) connected_relay_count: u64,
pub(super) pending_relay_publish_count: u64,
pub(super) retry_backoff_attempt: u32,
pub(super) next_retry_due_in_ms: Option<u64>,
pub(super) next_retry_reason: Option<String>,
pub(super) last_connect_reason: Option<String>,
pub(super) last_drain_reason: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimeProtocolPlanDebug {
pub(super) runtime_subscriptions: Vec<String>,
#[serde(default)]
pub(super) roster_authors: Vec<String>,
#[serde(default)]
pub(super) invite_authors: Vec<String>,
#[serde(default)]
pub(super) message_authors: Vec<String>,
#[serde(default)]
pub(super) message_recipients: Vec<String>,
#[serde(default)]
pub(super) group_roster_group_ids: Vec<String>,
#[serde(default)]
pub(super) group_roster_authors: Vec<String>,
#[serde(default)]
pub(super) group_sender_key_authors: Vec<String>,
#[serde(default)]
pub(super) invite_response_recipient: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimeProtocolSubscriptionDebug {
pub(super) desired_plan: Option<RuntimeProtocolPlanDebug>,
pub(super) applying_plan: Option<RuntimeProtocolPlanDebug>,
pub(super) applied_plan: Option<RuntimeProtocolPlanDebug>,
pub(super) refresh_in_flight: bool,
pub(super) refresh_dirty: bool,
pub(super) force_reconnect_dirty: bool,
#[serde(default)]
pub(super) protocol_fetch_in_flight: bool,
#[serde(default)]
pub(super) author_backfill_in_flight: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimePendingRelayPublishDebug {
pub(super) event_id: String,
pub(super) label: String,
pub(super) inner_event_id: Option<String>,
pub(super) chat_id: Option<String>,
pub(super) attempt_count: u64,
pub(super) last_error: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimeKnownUserDebug {
pub(super) owner_pubkey_hex: String,
pub(super) has_roster: bool,
pub(super) roster_device_count: usize,
pub(super) device_count: usize,
pub(super) authorized_device_count: usize,
pub(super) active_session_device_count: usize,
pub(super) inactive_session_count: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct RuntimeRecentHandshakeDebug {
pub(super) owner_hex: String,
pub(super) device_hex: String,
pub(super) observed_at_secs: u64,
}
#[derive(Debug, Serialize, Deserialize)]
pub(super) struct PersistedState {
pub(super) version: u32,
#[serde(alias = "active_peer_hex")]
pub(super) active_chat_id: Option<String>,
pub(super) next_message_id: u64,
#[serde(default)]
pub(super) owner_profiles: BTreeMap<String, OwnerProfileRecord>,
#[serde(default)]
pub(super) preferences: PersistedPreferences,
#[serde(default)]
pub(super) chat_message_ttl_seconds: BTreeMap<String, u64>,
#[serde(default)]
pub(super) app_keys: Vec<KnownAppKeys>,
#[serde(default)]
pub(super) groups: Vec<GroupSnapshot>,
#[serde(default)]
pub(super) group_pictures: BTreeMap<String, String>,
pub(super) threads: Vec<PersistedThread>,
#[serde(default)]
pub(super) seen_event_ids: Vec<String>,
#[serde(default)]
pub(super) authorization_state: Option<PersistedAuthorizationState>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(super) struct PersistedPreferences {
#[serde(default = "default_true")]
pub(super) voice_calls_enabled: bool,
#[serde(default = "default_true")]
pub(super) video_calls_enabled: bool,
#[serde(default)]
pub(super) call_quality: String,
#[serde(default)]
pub(super) call_max_bitrate_bps: u32,
#[serde(default = "default_true")]
pub(super) send_typing_indicators: bool,
#[serde(default = "default_true")]
pub(super) send_read_receipts: bool,
#[serde(default = "default_true")]
pub(super) allow_message_deletion_by_others: bool,
#[serde(default)]
pub(super) hide_blocked_group_messages: bool,
#[serde(default = "default_true")]
pub(super) desktop_notifications_enabled: bool,
#[serde(default = "default_true")]
pub(super) invite_acceptance_notifications_enabled: bool,
#[serde(default = "default_true")]
pub(super) startup_at_login_enabled: bool,
#[serde(default = "default_true")]
pub(super) nearby_enabled: bool,
#[serde(default)]
pub(super) nearby_bluetooth_enabled: bool,
#[serde(default)]
pub(super) nearby_lan_enabled: bool,
#[serde(default = "default_true")]
pub(super) nearby_show_in_chat_list: bool,
#[serde(default = "default_true")]
pub(super) nearby_mailbag_enabled: bool,
#[serde(default = "default_nostr_relay_urls")]
pub(super) nostr_relay_urls: Vec<String>,
#[serde(default = "default_true")]
pub(super) image_proxy_enabled: bool,
#[serde(default)]
pub(super) image_proxy_fallback_enabled: bool,
#[serde(default = "default_image_proxy_url")]
pub(super) image_proxy_url: String,
#[serde(default = "default_image_proxy_key_hex")]
pub(super) image_proxy_key_hex: String,
#[serde(default = "default_image_proxy_salt_hex")]
pub(super) image_proxy_salt_hex: String,
#[serde(default)]
pub(super) mobile_push_server_url: String,
#[serde(default)]
pub(super) muted_chat_ids: Vec<String>,
#[serde(default)]
pub(super) timed_chat_mutes: Vec<ChatMuteDeadline>,
#[serde(default)]
pub(super) silent_mention_chat_ids: Vec<String>,
#[serde(default)]
pub(super) pinned_chat_ids: Vec<String>,
#[serde(default)]
pub(super) blocked_owner_pubkeys: Vec<String>,
#[serde(default)]
pub(super) accepted_owner_pubkeys: Vec<String>,
#[serde(default)]
pub(super) debug_logging_enabled: bool,
#[serde(default = "default_true")]
pub(super) accept_unknown_direct_messages: bool,
}
impl Default for PersistedPreferences {
fn default() -> Self {
let defaults = PreferencesSnapshot::default();
Self {
voice_calls_enabled: defaults.voice_calls_enabled,
video_calls_enabled: defaults.video_calls_enabled,
call_quality: defaults.call_quality,
call_max_bitrate_bps: defaults.call_max_bitrate_bps,
send_typing_indicators: defaults.send_typing_indicators,
send_read_receipts: defaults.send_read_receipts,
allow_message_deletion_by_others: defaults.allow_message_deletion_by_others,
hide_blocked_group_messages: defaults.hide_blocked_group_messages,
desktop_notifications_enabled: defaults.desktop_notifications_enabled,
invite_acceptance_notifications_enabled: defaults
.invite_acceptance_notifications_enabled,
startup_at_login_enabled: defaults.startup_at_login_enabled,
nearby_enabled: defaults.nearby_enabled,
nearby_bluetooth_enabled: defaults.nearby_bluetooth_enabled,
nearby_lan_enabled: defaults.nearby_lan_enabled,
nearby_show_in_chat_list: defaults.nearby_show_in_chat_list,
nearby_mailbag_enabled: defaults.nearby_mailbag_enabled,
nostr_relay_urls: defaults.nostr_relay_urls,
image_proxy_enabled: defaults.image_proxy_enabled,
image_proxy_fallback_enabled: defaults.image_proxy_fallback_enabled,
image_proxy_url: defaults.image_proxy_url,
image_proxy_key_hex: defaults.image_proxy_key_hex,
image_proxy_salt_hex: defaults.image_proxy_salt_hex,
mobile_push_server_url: defaults.mobile_push_server_url,
muted_chat_ids: defaults.muted_chat_ids,
timed_chat_mutes: defaults.timed_chat_mutes,
silent_mention_chat_ids: defaults.silent_mention_chat_ids,
pinned_chat_ids: defaults.pinned_chat_ids,
blocked_owner_pubkeys: defaults.blocked_owner_pubkeys,
accepted_owner_pubkeys: defaults.accepted_owner_pubkeys,
debug_logging_enabled: defaults.debug_logging_enabled,
accept_unknown_direct_messages: defaults.accept_unknown_direct_messages,
}
}
}
fn default_true() -> bool {
true
}
fn default_nostr_relay_urls() -> Vec<String> {
configured_relays()
}
fn default_image_proxy_url() -> String {
crate::image_proxy::DEFAULT_IMAGE_PROXY_URL.to_string()
}
fn default_image_proxy_key_hex() -> String {
crate::image_proxy::DEFAULT_IMAGE_PROXY_KEY_HEX.to_string()
}
fn default_image_proxy_salt_hex() -> String {
crate::image_proxy::DEFAULT_IMAGE_PROXY_SALT_HEX.to_string()
}
#[derive(Debug, Serialize, Deserialize)]
pub(super) struct PersistedThread {
#[serde(alias = "peer_hex")]
pub(super) chat_id: String,
pub(super) unread_count: u64,
#[serde(default)]
pub(super) updated_at_secs: u64,
pub(super) messages: Vec<PersistedMessage>,
#[serde(default)]
pub(super) draft: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(super) struct PersistedMessage {
#[serde(default)]
pub(super) edit_history: Vec<crate::state::MessageEditSnapshot>,
#[serde(default)]
pub(super) deleted_for_everyone: bool,
#[serde(default)]
pub(super) system_notice_owner_pubkey_hex: Option<String>,
pub(super) id: String,
#[serde(alias = "peer_input")]
pub(super) chat_id: String,
#[serde(default = "default_message_kind")]
pub(super) kind: ChatMessageKind,
pub(super) author: String,
#[serde(default)]
pub(super) author_owner_pubkey_hex: Option<String>,
pub(super) body: String,
#[serde(default)]
pub(super) attachments: Vec<MessageAttachmentSnapshot>,
#[serde(default)]
pub(super) reactions: Vec<MessageReactionSnapshot>,
#[serde(default)]
pub(super) reactors: Vec<MessageReactor>,
pub(super) is_outgoing: bool,
pub(super) created_at_secs: u64,
#[serde(default)]
pub(super) expires_at_secs: Option<u64>,
pub(super) delivery: PersistedDeliveryState,
#[serde(default)]
pub(super) source_event_id: Option<String>,
#[serde(default)]
pub(super) recipient_deliveries: Vec<MessageRecipientDeliverySnapshot>,
#[serde(default)]
pub(super) delivery_trace: MessageDeliveryTraceSnapshot,
#[serde(default)]
pub(super) call: Option<crate::state::CallHistorySnapshot>,
}
fn default_message_kind() -> ChatMessageKind {
ChatMessageKind::User
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) enum PersistedDeliveryState {
Queued,
Pending,
Sent,
Received,
Seen,
Failed,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) enum PersistedAuthorizationState {
Authorized,
AwaitingApproval,
Revoked,
}
impl From<PersistedDeliveryState> for DeliveryState {
fn from(value: PersistedDeliveryState) -> Self {
match value {
PersistedDeliveryState::Queued => DeliveryState::Queued,
PersistedDeliveryState::Pending => DeliveryState::Pending,
PersistedDeliveryState::Sent => DeliveryState::Sent,
PersistedDeliveryState::Received => DeliveryState::Received,
PersistedDeliveryState::Seen => DeliveryState::Seen,
PersistedDeliveryState::Failed => DeliveryState::Failed,
}
}
}
impl From<&DeliveryState> for PersistedDeliveryState {
fn from(value: &DeliveryState) -> Self {
match value {
DeliveryState::Queued => Self::Queued,
DeliveryState::Pending => Self::Pending,
DeliveryState::Sent => Self::Sent,
DeliveryState::Received => Self::Received,
DeliveryState::Seen => Self::Seen,
DeliveryState::Failed => Self::Failed,
}
}
}
impl From<LocalAuthorizationState> for PersistedAuthorizationState {
fn from(value: LocalAuthorizationState) -> Self {
match value {
LocalAuthorizationState::Authorized => Self::Authorized,
LocalAuthorizationState::AwaitingApproval => Self::AwaitingApproval,
LocalAuthorizationState::Revoked => Self::Revoked,
}
}
}
impl From<PersistedAuthorizationState> for LocalAuthorizationState {
fn from(value: PersistedAuthorizationState) -> Self {
match value {
PersistedAuthorizationState::Authorized => Self::Authorized,
PersistedAuthorizationState::AwaitingApproval => Self::AwaitingApproval,
PersistedAuthorizationState::Revoked => Self::Revoked,
}
}
}