homework: thermometer client
This commit is contained in:
@@ -133,11 +133,11 @@
|
|||||||
- [x] Позволяет управлять розеткой множеству клиентов одновременно.
|
- [x] Позволяет управлять розеткой множеству клиентов одновременно.
|
||||||
|
|
||||||
Для умного термометра:
|
Для умного термометра:
|
||||||
- [ ] Функционал не изменяется: возвращает температуру.
|
- [x] Функционал не изменяется: возвращает температуру.
|
||||||
- [ ] Получает значения температуры в виде UDP-пакетов в параллельном потоке.
|
- [x] Получает значения температуры в виде UDP-пакетов в параллельном потоке.
|
||||||
- [ ] Параллельный поток запускается при создании объекта термометра и завершается при уничтожении этого объекта.
|
- [x] Параллельный поток запускается при создании объекта термометра и завершается при уничтожении этого объекта.
|
||||||
- [ ] Объект термометра возвращает последнее полученное значение температуры.
|
- [x] Объект термометра возвращает последнее полученное значение температуры.
|
||||||
- [ ] Термометр может имитировать удалённое получение данных о температуре (для тестов).
|
- [x] Термометр может имитировать удалённое получение данных о температуре (для тестов).
|
||||||
|
|
||||||
Для имитатора умного термометра:
|
Для имитатора умного термометра:
|
||||||
- [ ] Реализован с использованием неблокирующего сетевого взаимодействия.
|
- [ ] Реализован с использованием неблокирующего сетевого взаимодействия.
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use smart_house::PowerSocket;
|
use smart_house::Thermometer;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let power_socket = PowerSocket::connect("127.0.0.1:10001");
|
let thermometer = Thermometer::connect("127.0.0.1:10001").unwrap();
|
||||||
println!("{}", power_socket.display());
|
println!("{}", thermometer.display());
|
||||||
std::thread::sleep(Duration::from_secs(30));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
use std::net::UdpSocket;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Thermometer {
|
pub struct Thermometer {
|
||||||
@@ -12,6 +16,11 @@ impl Thermometer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connect(addr: &str) -> std::io::Result<Self> {
|
||||||
|
let handle = ThermometerClient::new(addr)?;
|
||||||
|
Ok(Self { handle: Box::new(handle) })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_temperature(&self) -> f32 {
|
pub fn get_temperature(&self) -> f32 {
|
||||||
self.handle.get_temperature()
|
self.handle.get_temperature()
|
||||||
}
|
}
|
||||||
@@ -42,20 +51,48 @@ impl ThermometerHandle for ThermometerHandleStub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ThermometerClient {
|
struct ThermometerClient {
|
||||||
value: f32,
|
value: Arc<AtomicU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThermometerClient {
|
impl ThermometerClient {
|
||||||
fn new() -> Self {
|
fn read(socket: &UdpSocket) -> std::io::Result<u32> {
|
||||||
Self { value: f32::NAN }
|
let mut buf = [0u8; 4];
|
||||||
|
let result = socket.recv_from(&mut buf);
|
||||||
|
result.map(|_| Ok(u32::from_le_bytes(buf)))?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(addr: &str) -> std::io::Result<Self> {
|
||||||
|
let value = Arc::new(AtomicU32::new(u32::from_le_bytes(f32::NAN.to_le_bytes())));
|
||||||
|
let socket = UdpSocket::bind(addr)?;
|
||||||
|
socket.set_read_timeout(Some(TIMEOUT))?;
|
||||||
|
|
||||||
|
let data = ThermometerClient::read(&socket)?;
|
||||||
|
value.store(data, Ordering::Relaxed);
|
||||||
|
|
||||||
|
let weak_value = Arc::downgrade(&value);
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
while let Some(value) = weak_value.upgrade() {
|
||||||
|
let result = ThermometerClient::read(&socket);
|
||||||
|
match result {
|
||||||
|
Ok(data) => value.store(data, Ordering::Relaxed),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("receiving data failed: {:?}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(Self { value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThermometerHandle for ThermometerClient {
|
impl ThermometerHandle for ThermometerClient {
|
||||||
fn get_temperature(&self) -> f32 {
|
fn get_temperature(&self) -> f32 {
|
||||||
self.value
|
f32::from_le_bytes(self.value.load(Ordering::Relaxed).to_le_bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user