homework: power socket tokio client
This commit is contained in:
151
smart-house/Cargo.lock
generated
151
smart-house/Cargo.lock
generated
@@ -2,6 +2,157 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.178"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smart-house"
|
name = "smart-house"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.49.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.61.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.53.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ name = "smart-house"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
tokio = { version = "1.49.0", features = ["rt", "net", "io-util", "time", "sync"] }
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use std::io;
|
use std::net::SocketAddr;
|
||||||
use std::io::{Read, Write};
|
use std::sync::Arc;
|
||||||
use std::net::{SocketAddr, TcpListener, TcpStream};
|
|
||||||
use std::sync::{Arc, RwLock};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
fn parse_args() -> SocketAddr {
|
fn parse_args() -> SocketAddr {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
@@ -13,6 +12,7 @@ fn parse_args() -> SocketAddr {
|
|||||||
.expect("server address should be valid")
|
.expect("server address should be valid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct RealPowerSocket {
|
struct RealPowerSocket {
|
||||||
power_rate: f32,
|
power_rate: f32,
|
||||||
on: bool,
|
on: bool,
|
||||||
@@ -23,46 +23,40 @@ const CMD_TURN_ON: u8 = 2;
|
|||||||
const CMD_TURN_OFF: u8 = 3;
|
const CMD_TURN_OFF: u8 = 3;
|
||||||
const CMD_GET_POWER: u8 = 4;
|
const CMD_GET_POWER: u8 = 4;
|
||||||
|
|
||||||
fn handle_connection(mut stream: TcpStream, real_power_socket: Arc<RwLock<RealPowerSocket>>) {
|
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
|
async fn handle_connection(mut socket: tokio::net::TcpStream, real_power_socket: Arc<tokio::sync::RwLock<RealPowerSocket>>) -> Result<(), std::io::Error> {
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0u8; 1];
|
let read = tokio::time::timeout(TIMEOUT, socket.read(&mut buf)).await??;
|
||||||
let result = stream.read_exact(&mut buf);
|
if read == 0 {
|
||||||
match result {
|
println!("connection closed");
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
return Ok(());
|
||||||
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 {
|
match buf {
|
||||||
[CMD_GET_ON] => {
|
[CMD_GET_ON] => {
|
||||||
println!("handling CMD_GET_ON");
|
println!("handling CMD_GET_ON");
|
||||||
let power_socket = real_power_socket.read().expect("power socket lock is poisoned");
|
let power_socket = real_power_socket.try_read().map_err(|e| std::io::Error::other(e))?;
|
||||||
buf = if power_socket.on { [1u8; 1] } else { [0u8; 1] };
|
buf = if power_socket.on { [1u8; 1] } else { [0u8; 1] };
|
||||||
stream.write_all(&buf).expect("response write error");
|
let _ = tokio::time::timeout(TIMEOUT, socket.write(&buf)).await?;
|
||||||
}
|
}
|
||||||
[CMD_TURN_ON] => {
|
[CMD_TURN_ON] => {
|
||||||
println!("handling CMD_TURN_ON");
|
println!("handling CMD_TURN_ON");
|
||||||
let mut power_socket = real_power_socket.write().expect("power socket lock is poisoned");
|
let mut power_socket = real_power_socket.try_write().map_err(|e| std::io::Error::other(e))?;
|
||||||
power_socket.on = true;
|
power_socket.on = true;
|
||||||
stream.write_all(&buf).expect("response write error");
|
let _ = tokio::time::timeout(TIMEOUT, socket.write(&buf)).await?;
|
||||||
}
|
}
|
||||||
[CMD_TURN_OFF] => {
|
[CMD_TURN_OFF] => {
|
||||||
println!("handling CMD_TURN_OFF");
|
println!("handling CMD_TURN_OFF");
|
||||||
let mut power_socket = real_power_socket.write().expect("power socket lock is poisoned");
|
let mut power_socket = real_power_socket.try_write().map_err(|e| std::io::Error::other(e))?;
|
||||||
power_socket.on = false;
|
power_socket.on = false;
|
||||||
stream.write_all(&buf).expect("response write error");
|
let _ = tokio::time::timeout(TIMEOUT, socket.write(&buf)).await?;
|
||||||
}
|
}
|
||||||
[CMD_GET_POWER] => {
|
[CMD_GET_POWER] => {
|
||||||
println!("handling CMD_GET_POWER");
|
println!("handling CMD_GET_POWER");
|
||||||
let power_socket = real_power_socket.write().expect("power socket lock is poisoned");
|
let power_socket = real_power_socket.try_read().map_err(|e| std::io::Error::other(e))?;
|
||||||
let data_buf = power_socket.power_rate.to_le_bytes();
|
let data_buf = power_socket.power_rate.to_le_bytes();
|
||||||
stream.write_all(&data_buf).expect("response write error");
|
let _ = tokio::time::timeout(TIMEOUT, socket.write(&data_buf)).await?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("unknown command {} - ignore it", buf[0]);
|
println!("unknown command {} - ignore it", buf[0]);
|
||||||
@@ -71,19 +65,17 @@ fn handle_connection(mut stream: TcpStream, real_power_socket: Arc<RwLock<RealPo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TIMEOUT: Duration = Duration::from_secs(5);
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let real_power_socket = Arc::new(tokio::sync::RwLock::new(RealPowerSocket { power_rate: 12.0, on: false }));
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build()?;
|
||||||
|
rt.block_on(async {
|
||||||
|
let listener = tokio::net::TcpListener::bind(parse_args()).await?;
|
||||||
|
|
||||||
fn main() {
|
loop {
|
||||||
let real_power_socket = Arc::new(RwLock::new(RealPowerSocket { power_rate: 12.0, on: false }));
|
let (socket, _) = listener.accept().await?;
|
||||||
let listener = TcpListener::bind(parse_args()).expect("address 127.0.0.1:10001 should be available for listening");
|
println!("new connection");
|
||||||
for connection in listener.incoming() {
|
let real_power_socket = real_power_socket.clone();
|
||||||
println!("new connection");
|
tokio::spawn(async move { handle_connection(socket, real_power_socket).await });
|
||||||
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,6 +1,10 @@
|
|||||||
use smart_house::Thermometer;
|
use smart_house::PowerSocket;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let thermometer = Thermometer::connect("127.0.0.1:10001").unwrap();
|
let mut power_socket = PowerSocket::connect("127.0.0.1:10001");
|
||||||
println!("{}", thermometer.display());
|
println!("{}", power_socket.display());
|
||||||
|
std::thread::sleep(Duration::from_secs(2));
|
||||||
|
power_socket.set_on(!power_socket.is_on());
|
||||||
|
println!("{}", power_socket.display());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user