aquarium_control/utilities/
acknowledge_signal_handler.rs

1/* Copyright 2025 Uwe Martin
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8*/
9use crate::food::feed_channels::FeedChannels;
10use crate::mineral::balling_channels::BallingChannels;
11use crate::permission::schedule_check_channels::ScheduleCheckChannels;
12use crate::recorder::data_logger_channels::DataLoggerChannels;
13use crate::relays::relay_manager_channels::RelayManagerChannels;
14use crate::sensors::atlas_scientific_channels::AtlasScientificChannels;
15use crate::sensors::sensor_manager_channels::SensorManagerChannels;
16use crate::sensors::tank_level_switch_channels::TankLevelSwitchChannels;
17use crate::simulator::tcp_communication_channels::TcpCommunicationChannels;
18use crate::thermal::heating_channels::HeatingChannels;
19use crate::thermal::ventilation_channels::VentilationChannels;
20use crate::watchmen::monitors_channels::MonitorsChannels;
21use crate::watchmen::watchdog_channels::WatchDogChannels;
22use crate::water::refill_channels::RefillChannels;
23use log::error;
24
25#[cfg(target_os = "linux")]
26use crate::dispatch::messaging_channels::MessagingChannels;
27use crate::launch::channels::AquaChannelError;
28
29/// A trait for objects that can send a shutdown acknowledgment to the `SignalHandler`.
30///
31/// This trait abstracts the boilerplate logic required for a thread to confirm that it has
32/// received a `Quit` command and is ready to terminate. By implementing this trait on a
33/// module's channel struct, the module can simply call `acknowledge_signal_handler()`
34/// to handle the confirmation and logging automatically.
35pub trait AcknowledgeSignalHandlerTrait {
36    /// Sends the raw acknowledgment message (`true`) to the `SignalHandler`.
37    ///
38    /// This method must be implemented by any struct that uses the trait. It is responsible
39    /// for the actual send-operation to the channel.
40    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError>;
41
42    /// Returns the source location (module path) for logging purposes.
43    ///
44    /// This method provides context for error logs, allowing developers to quickly
45    /// identify which thread failed to send its acknowledgment.
46    fn location(&self) -> String;
47
48    /// Acknowledges the `SignalHandler` by sending a confirmation message.
49    ///
50    /// This is the primary method that threads should call during shutdown.
51    /// It wraps the call to `send_true_to_signal_handler` with error handling,
52    /// automatically logging a detailed error message if the sending to the channel fails.
53    fn acknowledge_signal_handler(&mut self) {
54        if let Err(e) = self.send_true_to_signal_handler() {
55            error!(
56                target: &self.location(),
57                "sending quit confirmation back to signal handler failed ({e:?})"
58            );
59        }
60    }
61}
62
63impl AcknowledgeSignalHandlerTrait for AtlasScientificChannels {
64    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
65        self.send_to_signal_handler(true)
66    }
67
68    fn location(&self) -> String {
69        "atlas scientific".to_string()
70    }
71}
72
73impl AcknowledgeSignalHandlerTrait for FeedChannels {
74    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
75        self.send_to_signal_handler(true)
76    }
77
78    fn location(&self) -> String {
79        "feed".to_string()
80    }
81}
82
83impl AcknowledgeSignalHandlerTrait for BallingChannels {
84    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
85        self.send_to_signal_handler(true)
86    }
87
88    fn location(&self) -> String {
89        "balling".to_string()
90    }
91}
92
93impl AcknowledgeSignalHandlerTrait for ScheduleCheckChannels {
94    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
95        self.send_to_signal_handler(true)
96    }
97
98    fn location(&self) -> String {
99        "schedule_check".to_string()
100    }
101}
102
103impl AcknowledgeSignalHandlerTrait for DataLoggerChannels {
104    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
105        self.send_to_signal_handler(true)
106    }
107
108    fn location(&self) -> String {
109        "data_logger".to_string()
110    }
111}
112
113impl AcknowledgeSignalHandlerTrait for RelayManagerChannels {
114    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
115        self.send_to_signal_handler(true)
116    }
117
118    fn location(&self) -> String {
119        "relay_manager".to_string()
120    }
121}
122
123impl AcknowledgeSignalHandlerTrait for SensorManagerChannels {
124    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
125        self.send_to_signal_handler(true)
126    }
127
128    fn location(&self) -> String {
129        "sensor_manager".to_string()
130    }
131}
132
133impl AcknowledgeSignalHandlerTrait for TankLevelSwitchChannels {
134    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
135        self.send_to_signal_handler(true)
136    }
137
138    fn location(&self) -> String {
139        "tank_level_switch".to_string()
140    }
141}
142
143impl AcknowledgeSignalHandlerTrait for TcpCommunicationChannels {
144    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
145        self.send_to_signal_handler(true)
146    }
147
148    fn location(&self) -> String {
149        "tcp_communication".to_string()
150    }
151}
152
153impl AcknowledgeSignalHandlerTrait for HeatingChannels {
154    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
155        self.send_to_signal_handler(true)
156    }
157
158    fn location(&self) -> String {
159        "heating".to_string()
160    }
161}
162
163impl AcknowledgeSignalHandlerTrait for VentilationChannels {
164    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
165        self.send_to_signal_handler(true)
166    }
167
168    fn location(&self) -> String {
169        "ventilation".to_string()
170    }
171}
172
173impl AcknowledgeSignalHandlerTrait for MonitorsChannels {
174    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
175        self.send_to_signal_handler(true)
176    }
177
178    fn location(&self) -> String {
179        "monitors".to_string()
180    }
181}
182
183impl AcknowledgeSignalHandlerTrait for WatchDogChannels {
184    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
185        self.send_to_signal_handler(true)
186    }
187
188    fn location(&self) -> String {
189        "watchdog".to_string()
190    }
191}
192
193impl AcknowledgeSignalHandlerTrait for RefillChannels {
194    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
195        self.send_to_signal_handler(true)
196    }
197
198    fn location(&self) -> String {
199        "refill".to_string()
200    }
201}
202
203#[cfg(target_os = "linux")]
204impl AcknowledgeSignalHandlerTrait for MessagingChannels {
205    fn send_true_to_signal_handler(&mut self) -> Result<(), AquaChannelError> {
206        self.send_to_signal_handler(true)
207    }
208
209    fn location(&self) -> String {
210        "messaging".to_string()
211    }
212}