From deb1d7df4a3d81ec131087de2dfe07f458ecd6ea Mon Sep 17 00:00:00 2001 From: Alexander Baranov Date: Thu, 26 Feb 2026 00:34:46 +0300 Subject: [PATCH] homework: thermometer mock (not tested) --- smart-house/src/bin/power_socket_client.rs | 2 +- smart-house/src/bin/power_socket_mock.rs | 3 +- smart-house/src/bin/stubs_example.rs | 2 +- smart-house/src/bin/thermometer_mock.rs | 65 +++++++++++++++++++--- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/smart-house/src/bin/power_socket_client.rs b/smart-house/src/bin/power_socket_client.rs index 6608ca7..a9dc184 100644 --- a/smart-house/src/bin/power_socket_client.rs +++ b/smart-house/src/bin/power_socket_client.rs @@ -1,4 +1,4 @@ -/// Пример подключения нескольких клиентов к розетке. Изменение состояния любым из клиентов отражается на всех. +//! Пример подключения нескольких клиентов к розетке. Изменение состояния любым из клиентов отражается на всех. use smart_house::PowerSocket; use std::time::Duration; diff --git a/smart-house/src/bin/power_socket_mock.rs b/smart-house/src/bin/power_socket_mock.rs index 27e062d..3c897eb 100644 --- a/smart-house/src/bin/power_socket_mock.rs +++ b/smart-house/src/bin/power_socket_mock.rs @@ -1,4 +1,5 @@ -/// Сервер-имитатор умной розетки +//! Сервер-имитатор умной розетки + use std::net::SocketAddr; use std::sync::{Arc, RwLock}; use std::time::Duration; diff --git a/smart-house/src/bin/stubs_example.rs b/smart-house/src/bin/stubs_example.rs index bcaefa3..e168f12 100644 --- a/smart-house/src/bin/stubs_example.rs +++ b/smart-house/src/bin/stubs_example.rs @@ -1,4 +1,4 @@ -/// Старый пример работы умного дома на заглушках +//! Старый пример работы умного дома на заглушках use smart_house::{Device, House, PowerSocket, PrintStatus, Room, Thermometer, room}; diff --git a/smart-house/src/bin/thermometer_mock.rs b/smart-house/src/bin/thermometer_mock.rs index 9e3ca67..0794347 100644 --- a/smart-house/src/bin/thermometer_mock.rs +++ b/smart-house/src/bin/thermometer_mock.rs @@ -1,25 +1,76 @@ +//! Имитатор термометра + +use rand::prelude::*; use std::net::SocketAddr; use std::sync::{Arc, RwLock}; -use rand::prelude::*; +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 specified"))?.parse()?) + Ok(args + .next() + .ok_or(std::io::Error::other("no server address parameter must be specified"))? + .parse()?) } + fn generate_temperature() -> f32 { rand::rng().random_range(18.0..23.0) } struct RealThermometer { - temperature: f32 + 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 real_thermometer = Arc::new(RwLock::new(RealThermometer { + temperature: generate_temperature(), + })); let rt = tokio::runtime::Builder::new_current_thread().enable_all().build()?; - rt.block_on(async { + rt.block_on(async move { + let thermometer = real_thermometer.clone(); + tokio::spawn(async move { mutate_thermometer(thermometer).await }); - }); - Ok(()) + let socket = Arc::new(tokio::net::UdpSocket::bind(parse_args()?).await?); + let mut buf = [0u8; 4]; + 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 }); + } + }) }