homework: add power socket mock
This commit is contained in:
@@ -127,10 +127,10 @@
|
|||||||
- [x] Розетка может использовать как реальный TCP-обмен, так и имитировать реальную работу (для тестов).
|
- [x] Розетка может использовать как реальный TCP-обмен, так и имитировать реальную работу (для тестов).
|
||||||
|
|
||||||
Для имитатора умной розетки:
|
Для имитатора умной розетки:
|
||||||
- [ ] Читает адрес для приёма TCP-соединений из аргументов командной строки.
|
- [x] Читает адрес для приёма TCP-соединений из аргументов командной строки.
|
||||||
- [ ] Реализован с использованием неблокирующего сетевого взаимодействия.
|
- [x] Реализован с использованием неблокирующего сетевого взаимодействия.
|
||||||
- [ ] Хранит состояние розетки.
|
- [x] Хранит состояние розетки.
|
||||||
- [ ] Позволяет управлять розеткой множеству клиентов одновременно.
|
- [x] Позволяет управлять розеткой множеству клиентов одновременно.
|
||||||
|
|
||||||
Для умного термометра:
|
Для умного термометра:
|
||||||
- [ ] Функционал не изменяется: возвращает температуру.
|
- [ ] Функционал не изменяется: возвращает температуру.
|
||||||
|
|||||||
87
smart-house/src/bin/power_socket_mock.rs
Normal file
87
smart-house/src/bin/power_socket_mock.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::net::{SocketAddr, TcpListener, TcpStream};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn parse_args() -> SocketAddr {
|
||||||
|
let mut args = std::env::args();
|
||||||
|
args.next();
|
||||||
|
args.next()
|
||||||
|
.expect("server address should be passed as parameter")
|
||||||
|
.parse()
|
||||||
|
.expect("server address should be valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RealPowerSocket {
|
||||||
|
power_rate: f32,
|
||||||
|
on: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CMD_GET_ON: u8 = 1;
|
||||||
|
const CMD_TURN_ON: u8 = 2;
|
||||||
|
const CMD_TURN_OFF: u8 = 3;
|
||||||
|
const CMD_GET_POWER: u8 = 4;
|
||||||
|
|
||||||
|
fn handle_connection(mut stream: TcpStream, real_power_socket: Arc<RwLock<RealPowerSocket>>) {
|
||||||
|
loop {
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
let result = stream.read_exact(&mut buf);
|
||||||
|
match result {
|
||||||
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
|
std::thread::sleep(Duration::from_millis(250));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(e) if [io::ErrorKind::UnexpectedEof, io::ErrorKind::ConnectionReset].contains(&e.kind()) => {
|
||||||
|
println!("connection is over");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("error on reading socket: {e}"),
|
||||||
|
Ok(_) => {}
|
||||||
|
}
|
||||||
|
match buf {
|
||||||
|
[CMD_GET_ON] => {
|
||||||
|
println!("handling CMD_GET_ON");
|
||||||
|
let power_socket = real_power_socket.read().expect("power socket lock is poisoned");
|
||||||
|
buf = if power_socket.on { [1u8; 1] } else { [0u8; 1] };
|
||||||
|
stream.write_all(&buf).expect("response write error");
|
||||||
|
}
|
||||||
|
[CMD_TURN_ON] => {
|
||||||
|
println!("handling CMD_TURN_ON");
|
||||||
|
let mut power_socket = real_power_socket.write().expect("power socket lock is poisoned");
|
||||||
|
power_socket.on = true;
|
||||||
|
stream.write_all(&buf).expect("response write error");
|
||||||
|
}
|
||||||
|
[CMD_TURN_OFF] => {
|
||||||
|
println!("handling CMD_TURN_OFF");
|
||||||
|
let mut power_socket = real_power_socket.write().expect("power socket lock is poisoned");
|
||||||
|
power_socket.on = false;
|
||||||
|
stream.write_all(&buf).expect("response write error");
|
||||||
|
}
|
||||||
|
[CMD_GET_POWER] => {
|
||||||
|
println!("handling CMD_GET_POWER");
|
||||||
|
let power_socket = real_power_socket.write().expect("power socket lock is poisoned");
|
||||||
|
let data_buf = power_socket.power_rate.to_le_bytes();
|
||||||
|
stream.write_all(&data_buf).expect("response write error");
|
||||||
|
}
|
||||||
|
_ => panic!("unexpected command: {}", buf[0]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let real_power_socket = Arc::new(RwLock::new(RealPowerSocket { power_rate: 12.0, on: false }));
|
||||||
|
let listener = TcpListener::bind(parse_args()).expect("address 127.0.0.1:10001 should be available for listening");
|
||||||
|
for connection in listener.incoming() {
|
||||||
|
println!("new connection");
|
||||||
|
let real_power_socket = real_power_socket.clone();
|
||||||
|
let stream = connection.expect("connection should not fail");
|
||||||
|
stream.set_write_timeout(Some(TIMEOUT)).expect("set_write_timeout failed");
|
||||||
|
stream.set_nonblocking(true).expect("set_nonblocking call failed");
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
handle_connection(stream, real_power_socket);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,8 @@
|
|||||||
fn main() {}
|
use smart_house::PowerSocket;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let power_socket = PowerSocket::connect("127.0.0.1:10001");
|
||||||
|
println!("{}", power_socket.display());
|
||||||
|
std::thread::sleep(Duration::from_secs(30));
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ impl PowerSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PowerSocketHandle: Debug {
|
trait PowerSocketHandle: Debug {
|
||||||
fn is_on(&self) -> bool;
|
fn is_on(&self) -> bool;
|
||||||
|
|
||||||
fn set_on(&mut self, on: bool);
|
fn set_on(&mut self, on: bool);
|
||||||
@@ -49,7 +49,7 @@ pub trait PowerSocketHandle: Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PowerSocketStub {
|
struct PowerSocketStub {
|
||||||
power_rate: f32,
|
power_rate: f32,
|
||||||
on: bool,
|
on: bool,
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ impl PowerSocketHandle for PowerSocketStub {
|
|||||||
const TIMEOUT: Duration = Duration::from_secs(5);
|
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PowerSocketClient {
|
struct PowerSocketClient {
|
||||||
stream: RefCell<TcpStream>,
|
stream: RefCell<TcpStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user