Skip to main content

ferrix_app/
subscription.rs

1/* subscription.rs
2 *
3 * Copyright 2025-2026 Michail Krasnov <mskrasnov07@ya.ru>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21use crate::{
22    ferrix::Ferrix,
23    load_state::LoadState,
24    messages::{DataReceiverMessage, KeyboardMessage, Message},
25    pages::Page,
26};
27use iced::{Subscription, event, time};
28use std::time::Duration;
29
30type Script<T> = Subscription<T>;
31type OScript<T> = Option<Script<T>>;
32
33const START_UPERIOD: u64 = 10;
34
35trait PushMaybe<T> {
36    fn push_maybe(&mut self, data: Option<T>);
37}
38
39impl<T> PushMaybe<T> for Vec<T> {
40    fn push_maybe(&mut self, data: Option<T>) {
41        if let Some(data) = data {
42            self.push(data);
43        }
44    }
45}
46
47impl Ferrix {
48    pub fn subscription(&self) -> Script<Message> {
49        let charts_uperiod = self.settings.charts_update_period_nsecs as f32 * 0.1;
50        let mut scripts = vec![
51            event::listen().map(|event| Message::Keyboard(KeyboardMessage::Event(event))),
52            // Charts
53            time::every(Duration::from_secs_f32(charts_uperiod))
54                .map(|_| Message::DataReceiver(DataReceiverMessage::AddCPUCoreLineSeries)),
55            time::every(Duration::from_secs_f32(charts_uperiod))
56                .map(|_| Message::DataReceiver(DataReceiverMessage::AddTotalRAMUsage)),
57        ];
58        let oscripts = [
59            self.cpu_basic_data(),
60            self.cpu_stat_data(),
61            self.ram_data(),
62            self.swap_data(),
63            self.cpu_freq_subscription(),
64            self.cpu_vuln_subscription(),
65            self.storage_subscription(),
66            self.networks_subscription(),
67            self.dmi_subscription(),
68            self.battery_subscription(),
69            self.drm_subscription(),
70            self.osrel_subscription(),
71            self.users_subscription(),
72            self.groups_subscription(),
73            self.sysd_subscription(),
74            self.soft_subscription(),
75            self.env_and_sys_subscription(),
76            self.kernel_subscription(),
77            self.kmods_subscription(),
78        ];
79        for oscr in oscripts {
80            scripts.push_maybe(oscr);
81        }
82        Subscription::batch(scripts)
83    }
84
85    fn u(&self) -> u64 {
86        self.settings.update_period as u64
87    }
88
89    fn cpu_basic_data(&self) -> OScript<Message> {
90        if (self.current_page == Page::Dashboard || self.current_page == Page::Processors)
91            && self.data.proc_data.is_none()
92        {
93            Some(
94                time::every(Duration::from_millis(START_UPERIOD))
95                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetCPUData)),
96            )
97        } else {
98            None
99        }
100    }
101
102    fn cpu_stat_data(&self) -> OScript<Message> {
103        if (self.current_page == Page::Dashboard || self.current_page == Page::SystemMonitor)
104            && self.data.curr_proc_stat.is_none()
105        {
106            Some(
107                time::every(Duration::from_millis(START_UPERIOD))
108                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetProcStat)),
109            )
110        } else {
111            let uperiod = self.settings.charts_update_period_nsecs as f32 * 0.1;
112            Some(
113                time::every(Duration::from_secs_f32(uperiod))
114                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetProcStat)),
115            )
116        }
117    }
118
119    fn ram_data(&self) -> OScript<Message> {
120        if (self.current_page == Page::Dashboard || self.current_page == Page::Memory)
121            && self.data.ram_data.is_none()
122        {
123            Some(
124                time::every(Duration::from_millis(START_UPERIOD))
125                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetRAMData)),
126            )
127        } else {
128            let uperiod = self.settings.charts_update_period_nsecs as f32 * 0.1;
129            Some(
130                time::every(Duration::from_secs_f32(uperiod))
131                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetRAMData)),
132            )
133        }
134    }
135
136    fn swap_data(&self) -> OScript<Message> {
137        if (self.current_page == Page::Dashboard || self.current_page == Page::Memory)
138            && self.data.swap_data.is_none()
139        {
140            Some(
141                time::every(Duration::from_millis(START_UPERIOD))
142                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetSwapData)),
143            )
144        } else {
145            let uperiod = self.settings.charts_update_period_nsecs as f32 * 0.1;
146            Some(
147                time::every(Duration::from_secs_f32(uperiod))
148                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetSwapData)),
149            )
150        }
151    }
152
153    fn cpu_freq_subscription(&self) -> OScript<Message> {
154        if self.current_page == Page::CPUFrequency && self.data.cpu_freq.is_none() {
155            Some(
156                time::every(Duration::from_millis(START_UPERIOD))
157                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetCPUFrequency)),
158            )
159        } else if self.current_page == Page::CPUFrequency {
160            Some(
161                time::every(Duration::from_secs(self.u()))
162                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetCPUFrequency)),
163            )
164        } else {
165            None
166        }
167    }
168
169    fn cpu_vuln_subscription(&self) -> OScript<Message> {
170        if self.current_page == Page::CPUVulnerabilities && self.data.cpu_vulnerabilities.is_none()
171        {
172            Some(
173                time::every(Duration::from_millis(START_UPERIOD))
174                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetCPUVulnerabilities)),
175            )
176        } else {
177            None
178        }
179    }
180
181    fn storage_subscription(&self) -> OScript<Message> {
182        if (self.current_page == Page::Dashboard || self.current_page == Page::FileSystems)
183            && self.data.storages.is_none()
184        {
185            Some(
186                time::every(Duration::from_millis(START_UPERIOD))
187                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetStorageData)),
188            )
189        } else if self.current_page == Page::FileSystems {
190            Some(
191                time::every(Duration::from_secs(10))
192                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetStorageData)),
193            )
194        } else {
195            None
196        }
197    }
198
199    fn networks_subscription(&self) -> OScript<Message> {
200        if self.data.networks.is_none() && self.current_page == Page::Dashboard {
201            Some(
202                time::every(Duration::from_millis(START_UPERIOD))
203                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetNetworksData)),
204            )
205        } else if self.current_page == Page::Network {
206            Some(
207                time::every(Duration::from_secs(self.u()))
208                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetNetworksData)),
209            )
210        } else {
211            None
212        }
213    }
214
215    fn dmi_subscription(&self) -> OScript<Message> {
216        if self.current_page == Page::DMI && !self.data.is_polkit && self.data.dmi_data.is_none() {
217            Some(
218                time::every(Duration::from_millis(START_UPERIOD))
219                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetDMIData)),
220            )
221        } else {
222            None
223        }
224    }
225
226    fn battery_subscription(&self) -> OScript<Message> {
227        if self.current_page == Page::Dashboard || self.current_page == Page::Battery {
228            match self.data.bat_data {
229                LoadState::Loaded(_) => Some(
230                    time::every(Duration::from_secs(self.u()))
231                        .map(|_| Message::DataReceiver(DataReceiverMessage::GetBatInfo)),
232                ),
233                _ => Some(
234                    time::every(Duration::from_millis(START_UPERIOD))
235                        .map(|_| Message::DataReceiver(DataReceiverMessage::GetBatInfo)),
236                ),
237            }
238        } else {
239            None
240        }
241    }
242
243    fn drm_subscription(&self) -> OScript<Message> {
244        if self.current_page == Page::Screen && self.data.drm_data.is_none() {
245            Some(
246                time::every(Duration::from_millis(START_UPERIOD))
247                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetDRMData)),
248            )
249        } else if self.current_page == Page::Screen && self.data.drm_data.is_some() {
250            Some(
251                time::every(Duration::from_secs(self.u()))
252                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetDRMData)),
253            )
254        } else {
255            None
256        }
257    }
258
259    fn osrel_subscription(&self) -> OScript<Message> {
260        if (self.current_page == Page::Dashboard || self.current_page == Page::Distro)
261            && self.data.osrel_data.is_none()
262        {
263            Some(
264                time::every(Duration::from_millis(START_UPERIOD))
265                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetOsReleaseData)),
266            )
267        } else {
268            None
269        }
270    }
271
272    fn users_subscription(&self) -> OScript<Message> {
273        if self.current_page == Page::Users && self.data.users_list.is_none() {
274            Some(
275                time::every(Duration::from_millis(START_UPERIOD))
276                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetUsersData)),
277            )
278        } else {
279            None
280        }
281    }
282
283    fn groups_subscription(&self) -> OScript<Message> {
284        if self.current_page == Page::Groups && self.data.groups_list.is_none() {
285            Some(
286                time::every(Duration::from_millis(START_UPERIOD))
287                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetGroupsData)),
288            )
289        } else {
290            None
291        }
292    }
293
294    fn sysd_subscription(&self) -> OScript<Message> {
295        if self.current_page == Page::SystemManager && self.data.sysd_services_list.is_none() {
296            Some(
297                time::every(Duration::from_millis(START_UPERIOD))
298                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetSystemdServices)),
299            )
300        } else if self.current_page == Page::SystemManager && self.data.sysd_services_list.is_some()
301        {
302            Some(
303                time::every(Duration::from_secs(self.u() * 10))
304                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetSystemdServices)),
305            )
306        } else {
307            None
308        }
309    }
310
311    fn soft_subscription(&self) -> OScript<Message> {
312        if self.current_page == Page::Software && self.data.installed_pkgs_list.is_none() {
313            Some(
314                time::every(Duration::from_millis(START_UPERIOD))
315                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetPackagesList)),
316            )
317        } else {
318            None
319        }
320    }
321
322    fn env_and_sys_subscription(&self) -> OScript<Message> {
323        if self.current_page == Page::Environment
324            || self.current_page == Page::SystemMisc
325            || self.current_page == Page::Dashboard
326        {
327            if self.data.system.is_none() {
328                Some(
329                    time::every(Duration::from_millis(START_UPERIOD))
330                        .map(|_| Message::DataReceiver(DataReceiverMessage::GetSystemData)),
331                )
332            } else {
333                match self.current_page {
334                    Page::SystemMisc | Page::Dashboard => Some(
335                        time::every(Duration::from_secs(self.u()))
336                            .map(|_| Message::DataReceiver(DataReceiverMessage::GetSystemData)),
337                    ),
338                    _ => None,
339                }
340            }
341        } else {
342            None
343        }
344    }
345
346    fn kernel_subscription(&self) -> OScript<Message> {
347        if self.current_page == Page::Kernel && self.data.kernel_data.is_none() {
348            Some(
349                time::every(Duration::from_millis(START_UPERIOD))
350                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetKernelData)),
351            )
352        } else {
353            None
354        }
355    }
356
357    fn kmods_subscription(&self) -> OScript<Message> {
358        if self.current_page == Page::KModules && self.data.kmods_data.is_none() {
359            Some(
360                time::every(Duration::from_millis(START_UPERIOD))
361                    .map(|_| Message::DataReceiver(DataReceiverMessage::GetKModsData)),
362            )
363        } else {
364            None
365        }
366    }
367}