diff --git a/smart-house/src/bin/thermometer_mock.rs b/smart-house/src/bin/thermometer_mock.rs index 0794347..30999ac 100644 --- a/smart-house/src/bin/thermometer_mock.rs +++ b/smart-house/src/bin/thermometer_mock.rs @@ -1,76 +1,54 @@ //! Имитатор термометра use rand::prelude::*; +use std::io::Read; use std::net::SocketAddr; -use std::sync::{Arc, RwLock}; +use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; -fn parse_args() -> Result> { - let mut args = std::env::args(); - args.next(); - Ok(args - .next() - .ok_or(std::io::Error::other("no server address parameter must be specified"))? - .parse()?) +struct Params { + addr: SocketAddr, + interval: Duration, +} + +const CONFIG_FILE: &str = "thermometer_mock.cfg"; + +fn read_parameters_from_file() -> Result { + let mut file = std::fs::File::open(CONFIG_FILE)?; + let mut content = String::new(); + file.read_to_string(&mut content)?; + let lines = content.split("\n").collect::>(); + let addr = lines + .first() + .map(|v| SocketAddr::from_str(v)) + .ok_or(std::io::Error::other("no address found in config file"))? + .map_err(std::io::Error::other)?; + let interval = lines + .get(1) + .map(|v| v.parse::()) + .ok_or(std::io::Error::other("no interval found in config file"))? + .map(Duration::from_millis) + .map_err(std::io::Error::other)?; + Ok(Params { addr, interval }) } fn generate_temperature() -> f32 { rand::rng().random_range(18.0..23.0) } -struct RealThermometer { - temperature: f32, -} - -const REQUEST: u8 = 0b01010101; - -async fn mutate_thermometer(thermometer: Arc>) -> Result<(), std::io::Error> { - let mut interval = tokio::time::interval(Duration::from_secs(1)); - loop { - interval.tick().await; - let new_temperature = generate_temperature(); - thermometer.try_write().map_err(|_| std::io::Error::other("write lock failed"))?.temperature = new_temperature; - println!("new temperature: {:02.1}", new_temperature) - } -} - -async fn handle_request( - request: u8, - thermometer: Arc>, - socket: Arc, - addr: SocketAddr, -) -> Result<(), std::io::Error> { - if request == REQUEST { - let data = thermometer - .try_read() - .map_err(|_| std::io::Error::other("write lock failed"))? - .temperature - .to_le_bytes(); - socket.send_to(&data, &addr).await?; - println!("temperature was sent to {}", addr); - } else { - println!("invalid request: {:?}", request); - } - Ok(()) -} - fn main() -> Result<(), Box> { - let real_thermometer = Arc::new(RwLock::new(RealThermometer { - temperature: generate_temperature(), - })); + let params = read_parameters_from_file()?; let rt = tokio::runtime::Builder::new_current_thread().enable_all().build()?; rt.block_on(async move { - let thermometer = real_thermometer.clone(); - tokio::spawn(async move { mutate_thermometer(thermometer).await }); - - let socket = Arc::new(tokio::net::UdpSocket::bind(parse_args()?).await?); - let mut buf = [0u8; 4]; + let socket = Arc::new(tokio::net::UdpSocket::bind(params.addr).await?); + let mut interval = tokio::time::interval(params.interval); loop { - let (_, addr) = socket.recv_from(&mut buf).await?; - let request = buf[0]; - let thermometer = real_thermometer.clone(); - let socket = socket.clone(); - tokio::spawn(async move { handle_request(request, thermometer, socket, addr).await }); + interval.tick().await; + let new_temperature = generate_temperature(); + println!("new temperature: {:02.1}", new_temperature); + let data = new_temperature.to_le_bytes(); + socket.send_to(&data, ¶ms.addr).await?; } }) } diff --git a/smart-house/thermometer_mock.cfg b/smart-house/thermometer_mock.cfg new file mode 100644 index 0000000..62f58b9 --- /dev/null +++ b/smart-house/thermometer_mock.cfg @@ -0,0 +1,2 @@ +127.0.0.1:10002 +500