1use std::sync::Arc;
2
3use crate::{
4 Result,
5 storage::stats_db::{NetworkEventRecord, StatsDatabase, SyncSessionRecord},
6};
7
8#[derive(Clone, Copy, Debug)]
10#[non_exhaustive]
11pub enum NetworkEventType {
12 PeerJoined,
13 PeerLeft,
14 SyncStarted,
15 SyncFinished,
16 RelayConnected,
17 RelayDisconnected,
18 RelayFailed,
19 TopicSubscribed,
20 TopicUnsubscribed,
21 MemberAdded,
22 MemberRemoved,
23 FolderAdded,
24 FolderRemoved,
25 TicketCreated,
26 TicketAccepted,
27 Kicked,
28}
29
30impl NetworkEventType {
31 #[must_use]
32 pub const fn as_str(&self) -> &'static str {
33 match self {
34 Self::PeerJoined => "peer_joined",
35 Self::PeerLeft => "peer_left",
36 Self::SyncStarted => "sync_started",
37 Self::SyncFinished => "sync_finished",
38 Self::RelayConnected => "relay_connected",
39 Self::RelayDisconnected => "relay_disconnected",
40 Self::RelayFailed => "relay_failed",
41 Self::TopicSubscribed => "topic_subscribed",
42 Self::TopicUnsubscribed => "topic_unsubscribed",
43 Self::MemberAdded => "member_added",
44 Self::MemberRemoved => "member_removed",
45 Self::FolderAdded => "folder_added",
46 Self::FolderRemoved => "folder_removed",
47 Self::TicketCreated => "ticket_created",
48 Self::TicketAccepted => "ticket_accepted",
49 Self::Kicked => "kicked",
50 }
51 }
52}
53
54#[derive(Clone, Debug)]
58pub struct NetworkLogger {
59 database: Arc<StatsDatabase>,
60}
61
62impl NetworkLogger {
63 #[must_use]
65 pub fn new(database: StatsDatabase) -> Self {
66 Self {
67 database: Arc::new(database),
68 }
69 }
70
71 #[must_use]
73 pub const fn from_arc(database: Arc<StatsDatabase>) -> Self {
74 Self { database }
75 }
76
77 pub fn record_event(
83 &self,
84 network_id: &str,
85 event: NetworkEventType,
86 peer: Option<&str>,
87 details: Option<&str>,
88 ) -> Result<()> {
89 self.database
90 .record_network_event(network_id, event.as_str(), peer, details, None)
91 }
92
93 pub fn record_event_with_metadata(
99 &self,
100 network_id: &str,
101 event: NetworkEventType,
102 peer: Option<&str>,
103 details: Option<&str>,
104 metadata_json: Option<&str>,
105 ) -> Result<()> {
106 self.database
107 .record_network_event(network_id, event.as_str(), peer, details, metadata_json)
108 }
109
110 pub fn record_sync_start(&self, network_id: &str, folder_namespace: &str) -> Result<i64> {
116 self.database.record_sync_session_start(network_id, folder_namespace)
117 }
118
119 pub fn record_sync_finish(&self, session_id: i64, files: u64, bytes: u64, errors: u64, status: &str) -> Result<()> {
125 self.database
126 .record_sync_session_finish(session_id, files, bytes, errors, status)
127 }
128
129 pub fn record_bandwidth_download(
135 &self,
136 bytes: u64,
137 files: u64,
138 folder_namespace: Option<&str>,
139 peer: Option<&str>,
140 network_id: Option<&str>,
141 ) -> Result<()> {
142 if bytes == 0 {
143 return Ok(());
144 }
145 self.database
146 .record_download(bytes, files, folder_namespace, peer, network_id)
147 }
148
149 pub fn record_bandwidth_upload(
155 &self,
156 bytes: u64,
157 files: u64,
158 folder_namespace: Option<&str>,
159 peer: Option<&str>,
160 network_id: Option<&str>,
161 ) -> Result<()> {
162 if bytes == 0 {
163 return Ok(());
164 }
165 self.database
166 .record_upload(bytes, files, folder_namespace, peer, network_id)
167 }
168
169 pub fn record_relay_check(
175 &self,
176 relay_url: &str,
177 connected: bool,
178 latency_ms: Option<i64>,
179 error_message: Option<&str>,
180 ) -> Result<()> {
181 self.database
182 .record_relay_check(relay_url, connected, latency_ms, error_message)
183 }
184
185 pub fn recent_events(&self, network_id: &str, limit: usize) -> Result<Vec<NetworkEventRecord>> {
191 self.database.recent_network_events(network_id, limit)
192 }
193
194 pub fn recent_sessions(&self, network_id: &str, limit: usize) -> Result<Vec<SyncSessionRecord>> {
200 self.database.recent_sync_sessions(network_id, limit)
201 }
202
203 pub fn relay_uptime(&self, relay_url: &str, window_secs: i64) -> Result<f64> {
209 self.database.relay_uptime(relay_url, window_secs)
210 }
211}