rustmo_server/
virtual_device.rs1use serde_json::Error;
2use std::fmt::Debug;
3use std::sync::{Arc, Mutex};
4
5pub struct VirtualDeviceError(pub String);
6
7impl VirtualDeviceError {
8 pub fn new(message: &'static str) -> Self {
9 VirtualDeviceError(message.to_string())
10 }
11
12 pub fn from(message: String) -> Self {
13 VirtualDeviceError(message)
14 }
15}
16
17impl std::convert::From<std::io::Error> for VirtualDeviceError {
18 fn from(e: std::io::Error) -> Self {
19 VirtualDeviceError::from(e.to_string())
20 }
21}
22
23impl std::convert::From<std::ffi::FromBytesWithNulError> for VirtualDeviceError {
24 fn from(e: std::ffi::FromBytesWithNulError) -> Self {
25 VirtualDeviceError::from(e.to_string())
26 }
27}
28
29impl std::convert::From<reqwest::Error> for VirtualDeviceError {
30 fn from(e: reqwest::Error) -> Self {
31 VirtualDeviceError::from(e.to_string())
32 }
33}
34
35impl std::convert::From<serde_json::error::Error> for VirtualDeviceError {
36 fn from(e: Error) -> Self {
37 VirtualDeviceError::from(e.to_string())
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq)]
42pub enum VirtualDeviceState {
43 On,
45
46 Off,
48}
49
50pub type WrappedVirtualDevice = Arc<Mutex<Box<dyn VirtualDevice>>>;
56
57pub trait VirtualDevice: Sync + Send + 'static {
81 fn turn_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError>;
83
84 fn turn_off(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError>;
86
87 fn check_is_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError>;
89}
90
91pub(crate) mod wrappers {
92 use std::sync::atomic::{AtomicBool, Ordering};
93 use std::thread;
94 use std::time::Duration;
95
96 use rayon::prelude::*;
97
98 use crate::virtual_device::{
99 VirtualDevice, VirtualDeviceError, VirtualDeviceState, WrappedVirtualDevice,
100 };
101
102 pub(crate) struct InstantOnDevice {
107 pub(crate) device: Box<dyn VirtualDevice>,
108 pub(crate) instant: bool,
109 }
110
111 impl VirtualDevice for InstantOnDevice {
112 fn turn_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
113 let result = self.device.turn_on();
114 self.instant = true;
115
116 result
117 }
118
119 fn turn_off(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
120 let result = self.device.turn_off();
121 self.instant = false;
122
123 result
124 }
125
126 fn check_is_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
127 let result = self.device.check_is_on();
128
129 if self.instant {
130 if let VirtualDeviceState::On = result.unwrap_or(VirtualDeviceState::Off) {
131 self.instant = false;
132 }
133 return Ok(VirtualDeviceState::On);
134 }
135
136 result
137 }
138 }
139
140 pub(crate) struct PollingDevice {
145 pub(crate) device: Box<dyn VirtualDevice>,
146 }
147
148 impl VirtualDevice for PollingDevice {
149 fn turn_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
150 self.device.turn_on()?;
151
152 let mut state = self.device.check_is_on().unwrap_or(VirtualDeviceState::Off);
153 match state {
154 VirtualDeviceState::Off => {
155 let mut cnt = 0;
156 while state.eq(&VirtualDeviceState::Off) {
157 println!("POLLING for 'on': cnt={}", cnt);
158
159 thread::sleep(Duration::from_millis(400));
160 state = self.device.check_is_on().unwrap_or(VirtualDeviceState::Off);
161 cnt += 1;
162 if cnt == 10 {
163 break;
164 }
165 }
166 Ok(state)
167 }
168 _ => Ok(state),
169 }
170 }
171
172 fn turn_off(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
173 self.device.turn_off()?;
174
175 let mut state = self.device.check_is_on().unwrap_or(VirtualDeviceState::On);
176 match state {
177 VirtualDeviceState::On => {
178 let mut cnt = 0;
179 while state.eq(&VirtualDeviceState::On) {
180 println!("POLLING for 'off': cnt={}", cnt);
181 thread::sleep(Duration::from_millis(400));
182
183 state = self.device.check_is_on().unwrap_or(VirtualDeviceState::On);
184 cnt += 1;
185 if cnt == 10 {
186 break;
187 }
188 }
189 Ok(state)
190 }
191 _ => Ok(state),
192 }
193 }
194
195 fn check_is_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
196 self.device.check_is_on()
197 }
198 }
199
200 pub(crate) struct CompositeDevice {
207 pub(crate) devices: Vec<WrappedVirtualDevice>,
208 }
209
210 impl VirtualDevice for CompositeDevice {
211 fn turn_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
212 self.devices.par_iter_mut().for_each(|device| {
213 if let Ok(mut device) = device.lock() {
214 if device.check_is_on().unwrap_or(VirtualDeviceState::Off)
215 == VirtualDeviceState::Off
216 {
217 device.turn_on().ok().unwrap();
218 }
219 }
220 });
221
222 self.check_is_on()
223 }
224
225 fn turn_off(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
226 self.devices.par_iter_mut().for_each(|device| {
227 if let Ok(mut device) = device.lock() {
228 if device.check_is_on().unwrap_or(VirtualDeviceState::Off)
229 == VirtualDeviceState::On
230 {
231 device.turn_off().ok().unwrap();
232 }
233 }
234 });
235
236 self.check_is_on()
237 }
238
239 fn check_is_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
240 let on = AtomicBool::new(true);
241 self.devices.par_iter_mut().for_each(|device| {
242 if let Ok(mut device) = device.lock() {
243 match device.check_is_on().unwrap_or(VirtualDeviceState::Off) {
244 VirtualDeviceState::On => {
245 on.compare_and_swap(true, true, Ordering::SeqCst);
246 }
247 VirtualDeviceState::Off => {
248 on.store(false, Ordering::SeqCst);
249 }
250 }
251 }
252 });
253
254 if on.load(Ordering::SeqCst) {
255 Ok(VirtualDeviceState::On)
256 } else {
257 Ok(VirtualDeviceState::Off)
258 }
259 }
260 }
261
262 pub(crate) struct FunctionalDevice<TurnOn, TurnOff, CheckIsOn>
265 where
266 TurnOn: FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
267 TurnOff: FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
268 CheckIsOn:
269 FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
270 {
271 pub(crate) turn_on: TurnOn,
272 pub(crate) turn_off: TurnOff,
273 pub(crate) check_is_on: CheckIsOn,
274 }
275
276 impl<TurnOn, TurnOff, CheckIsOn> VirtualDevice for FunctionalDevice<TurnOn, TurnOff, CheckIsOn>
277 where
278 TurnOn: FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
279 TurnOff: FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
280 CheckIsOn:
281 FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
282 {
283 fn turn_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
284 (self.turn_on)()
285 }
286
287 fn turn_off(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
288 (self.turn_off)()
289 }
290
291 fn check_is_on(&mut self) -> Result<VirtualDeviceState, VirtualDeviceError> {
292 (self.check_is_on)()
293 }
294 }
295}