homework: thermometer mock (not tested)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
/// Пример подключения нескольких клиентов к розетке. Изменение состояния любым из клиентов отражается на всех.
|
//! Пример подключения нескольких клиентов к розетке. Изменение состояния любым из клиентов отражается на всех.
|
||||||
|
|
||||||
use smart_house::PowerSocket;
|
use smart_house::PowerSocket;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/// Сервер-имитатор умной розетки
|
//! Сервер-имитатор умной розетки
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/// Старый пример работы умного дома на заглушках
|
//! Старый пример работы умного дома на заглушках
|
||||||
|
|
||||||
use smart_house::{Device, House, PowerSocket, PrintStatus, Room, Thermometer, room};
|
use smart_house::{Device, House, PowerSocket, PrintStatus, Room, Thermometer, room};
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,76 @@
|
|||||||
|
//! Имитатор термометра
|
||||||
|
|
||||||
|
use rand::prelude::*;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use rand::prelude::*;
|
use std::time::Duration;
|
||||||
|
|
||||||
fn parse_args() -> Result<SocketAddr, Box<dyn std::error::Error>> {
|
fn parse_args() -> Result<SocketAddr, Box<dyn std::error::Error>> {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
args.next();
|
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 {
|
fn generate_temperature() -> f32 {
|
||||||
rand::rng().random_range(18.0..23.0)
|
rand::rng().random_range(18.0..23.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RealThermometer {
|
struct RealThermometer {
|
||||||
temperature: f32
|
temperature: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const REQUEST: u8 = 0b01010101;
|
||||||
|
|
||||||
|
async fn mutate_thermometer(thermometer: Arc<RwLock<RealThermometer>>) -> 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<RwLock<RealThermometer>>,
|
||||||
|
socket: Arc<tokio::net::UdpSocket>,
|
||||||
|
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<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
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()?;
|
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 });
|
||||||
|
|
||||||
});
|
let socket = Arc::new(tokio::net::UdpSocket::bind(parse_args()?).await?);
|
||||||
Ok(())
|
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 });
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user