From 8bebf0d5269877fa2dda8a95f8e4a2e13c6c8582 Mon Sep 17 00:00:00 2001 From: Alexander Baranov Date: Wed, 20 May 2026 01:05:50 +0300 Subject: [PATCH] =?UTF-8?q?smart-house-web:=20=D0=B2=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- smart-house-web/backend/src/house.rs | 30 ++++++---- smart-house-web/backend/src/server.rs | 22 +++++-- smart-house-web/backend/src/server/debug.rs | 12 +++- smart-house-web/backend/src/server/device.rs | 44 ++++++++++++++ smart-house-web/backend/src/server/house.rs | 21 +++++++ smart-house-web/backend/src/server/room.rs | 49 +++++++++++++++ smart-house-web/backend/src/server/rooms.rs | 25 -------- smart-house-web/backend/test.http | 63 +++++++++++++++++++- 8 files changed, 219 insertions(+), 47 deletions(-) create mode 100644 smart-house-web/backend/src/server/device.rs create mode 100644 smart-house-web/backend/src/server/house.rs create mode 100644 smart-house-web/backend/src/server/room.rs delete mode 100644 smart-house-web/backend/src/server/rooms.rs diff --git a/smart-house-web/backend/src/house.rs b/smart-house-web/backend/src/house.rs index 2ba164f..eb906de 100644 --- a/smart-house-web/backend/src/house.rs +++ b/smart-house-web/backend/src/house.rs @@ -61,8 +61,8 @@ pub enum Device { impl Device { pub fn report(&self) -> String { match self { - Device::PowerSocket(v) => format!("{}", v.report()), - Device::Thermometer(v) => format!("{}", v.report()), + Device::PowerSocket(v) => v.report().to_string(), + Device::Thermometer(v) => v.report().to_string(), } } } @@ -88,6 +88,14 @@ impl Room { pub fn new(devices: HashMap) -> Self { Self { devices } } + + pub fn get_devices(&self) -> &HashMap { + &self.devices + } + + pub fn get_devices_mut(&mut self) -> &mut HashMap { + &mut self.devices + } } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -100,19 +108,19 @@ impl House { Self { rooms } } - pub fn rooms(&self) -> Vec { - let mut output = Vec::with_capacity(self.rooms.len()); - for (room, _) in self.rooms.iter() { - output.push(room.into()); - } - return output; + pub fn get_rooms(&self) -> &HashMap { + &self.rooms } - pub fn add_room(&mut self, name: String) { - self.rooms.insert(name, Room::default()); + pub fn get_rooms_mut(&mut self) -> &mut HashMap { + &mut self.rooms } - pub fn drop_room(&mut self, name: &str) { + pub fn add_room(&mut self, name: String, room: Room) { + self.rooms.insert(name, room); + } + + pub fn del_room(&mut self, name: &str) { self.rooms.remove(name); } } diff --git a/smart-house-web/backend/src/server.rs b/smart-house-web/backend/src/server.rs index ea2fa8c..213071f 100644 --- a/smart-house-web/backend/src/server.rs +++ b/smart-house-web/backend/src/server.rs @@ -1,4 +1,4 @@ -use axum::routing::{delete, get, put}; +use axum::routing::{delete, get, post, put}; use std::{ process::exit, sync::{ @@ -44,11 +44,19 @@ async fn server_main() { let app = axum::Router::new() // Тестовый эндпоинт для экспериментов .route("/debug", get(debug::debug)) + // API дома + .route("/rooms", get(house::get_rooms)) + .route("/rooms", post(house::post_rooms)) // API комнат - .route("/rooms", get(rooms::get_rooms)) - .route("/room", put(rooms::add_room)) - .route("/room/{name}", delete(rooms::remove_room)) - // TODO + .route("/room/{name}", get(room::get_room)) + .route("/room/{name}", put(room::put_room)) + .route("/room/{name}", delete(room::delete_room)) + .route("/room/{name}/devices", get(room::get_devices)) + // API устройств + .route("/room/{name}/device/{name}", get(device::get_device)) + .route("/room/{name}/device/{name}", put(device::put_device)) + .route("/room/{name}/device/{name}", delete(device::delete_device)) + // Состояние и роут по-умолчанию .with_state(state) .fallback(fallback); let addr = "127.0.0.1:8080"; @@ -98,4 +106,6 @@ async fn shutdown_signal() { } mod debug; -mod rooms; +mod device; +mod house; +mod room; diff --git a/smart-house-web/backend/src/server/debug.rs b/smart-house-web/backend/src/server/debug.rs index 1dc9dbe..a770f42 100644 --- a/smart-house-web/backend/src/server/debug.rs +++ b/smart-house-web/backend/src/server/debug.rs @@ -1,5 +1,13 @@ +use std::collections::HashMap; + use axum::{Json, extract::State}; -pub async fn debug(State(_server_state): State) -> Json<(String, String)> { - ("ONE".into(), "TWO".into()).into() +use crate::{Device, PowerSocket, Room, Thermometer}; + +pub async fn debug(State(_server_state): State) -> Json { + let map = HashMap::::from([ + ("thermo".into(), Thermometer::new(20.0).into()), + ("psock".into(), PowerSocket::new(10.0, false).into()), + ]); + Room::new(map).into() } diff --git a/smart-house-web/backend/src/server/device.rs b/smart-house-web/backend/src/server/device.rs new file mode 100644 index 0000000..1cdd4ea --- /dev/null +++ b/smart-house-web/backend/src/server/device.rs @@ -0,0 +1,44 @@ +use axum::{ + Json, + extract::{Path, State}, + http::StatusCode, +}; + +use crate::{Device, Room}; + +pub async fn get_device( + State(server_state): State, + Path((room, device)): Path<(String, String)>, +) -> Result, StatusCode> { + let house = server_state.read().await; + let Some(room) = house.get_rooms().get(&room) else { + return Err(StatusCode::NOT_FOUND); + }; + let Some(device) = room.get_devices().get(&device) else { + return Err(StatusCode::NOT_FOUND); + }; + Ok(device.clone().into()) +} + +pub async fn put_device( + State(server_state): State, + Path((room, name)): Path<(String, String)>, + Json(device): Json, +) -> StatusCode { + let mut house = server_state.write().await; + let room = house.get_rooms_mut().entry(room).or_insert(Room::default()); + room.get_devices_mut().insert(name, device); + StatusCode::CREATED +} + +pub async fn delete_device( + State(server_state): State, + Path((room, device)): Path<(String, String)>, +) -> StatusCode { + let mut house = server_state.write().await; + let Some(room) = house.get_rooms_mut().get_mut(&room) else { + return StatusCode::ACCEPTED; + }; + room.get_devices_mut().remove(&device); + StatusCode::ACCEPTED +} diff --git a/smart-house-web/backend/src/server/house.rs b/smart-house-web/backend/src/server/house.rs new file mode 100644 index 0000000..9013fbd --- /dev/null +++ b/smart-house-web/backend/src/server/house.rs @@ -0,0 +1,21 @@ +use std::collections::HashMap; + +use axum::{Json, extract::State, http::StatusCode}; + +use crate::Room; + +pub async fn get_rooms( + State(server_state): State, +) -> Json> { + server_state.read().await.get_rooms().clone().into() +} + +pub async fn post_rooms( + State(server_state): State, + Json(map): Json>, +) -> StatusCode { + for (name, room) in map.into_iter() { + server_state.write().await.add_room(name, room); + } + StatusCode::CREATED +} diff --git a/smart-house-web/backend/src/server/room.rs b/smart-house-web/backend/src/server/room.rs new file mode 100644 index 0000000..4643a46 --- /dev/null +++ b/smart-house-web/backend/src/server/room.rs @@ -0,0 +1,49 @@ +use std::collections::HashMap; + +use axum::{ + Json, + extract::{Path, State}, + http::StatusCode, +}; + +use crate::{Device, Room}; + +pub async fn get_room( + State(server_state): State, + Path(name): Path, +) -> Result, StatusCode> { + let house = server_state.read().await; + let Some(room) = house.get_rooms().get(&name) else { + return Err(StatusCode::NOT_FOUND); + }; + Ok(room.clone().into()) +} + +pub async fn put_room( + State(server_state): State, + Path(name): Path, + Json(room): Json, +) -> StatusCode { + let mut house = server_state.write().await; + house.add_room(name, room); + StatusCode::CREATED +} + +pub async fn delete_room( + State(server_state): State, + Path(name): Path, +) -> StatusCode { + server_state.write().await.del_room(&name); + StatusCode::ACCEPTED +} + +pub async fn get_devices( + State(server_state): State, + Path(name): Path, +) -> Result>, StatusCode> { + let house = server_state.read().await; + let Some(room) = house.get_rooms().get(&name) else { + return Err(StatusCode::NOT_FOUND); + }; + Ok(room.get_devices().clone().into()) +} diff --git a/smart-house-web/backend/src/server/rooms.rs b/smart-house-web/backend/src/server/rooms.rs deleted file mode 100644 index 26ae96e..0000000 --- a/smart-house-web/backend/src/server/rooms.rs +++ /dev/null @@ -1,25 +0,0 @@ -use axum::{ - Json, - extract::{Path, State}, - http::StatusCode, -}; - -pub async fn get_rooms(State(server_state): State) -> Json> { - server_state.read().await.rooms().into() -} - -pub async fn add_room( - State(server_state): State, - Json(name): Json, -) -> StatusCode { - server_state.write().await.add_room(name); - StatusCode::CREATED -} - -pub async fn remove_room( - State(server_state): State, - Path(name): Path, -) -> StatusCode { - server_state.write().await.drop_room(&name); - StatusCode::ACCEPTED -} diff --git a/smart-house-web/backend/test.http b/smart-house-web/backend/test.http index ba4d403..198a165 100644 --- a/smart-house-web/backend/test.http +++ b/smart-house-web/backend/test.http @@ -4,11 +4,68 @@ GET http://localhost:8080/debug ### list rooms GET http://localhost:8080/rooms -### add room -PUT http://localhost:8080/room +### post all rooms +POST http://localhost:8080/rooms Content-Type: application/json -"ROOM" +{ + "ROOM0": { + "devices": {} + }, + "ROOM1": { + "devices": { + "therm": { + "type": "Thermometer", + "temperature": 22 + }, + "psock": { + "type": "PowerSocket", + "power_rate": 11, + "on": false + } + } + } +} ### drop room DELETE http://localhost:8080/room/ROOM + +### add room +PUT http://localhost:8080/room/ROOM +Content-Type: application/json + +{ + "devices": { + "therm": { + "type": "Thermometer", + "temperature": 20 + }, + "psock": { + "type": "PowerSocket", + "power_rate": 10, + "on": true + } + } +} + +### get room +GET http://localhost:8080/room/ROOM1 + +### get room devices +GET http://localhost:8080/room/ROOM1/devices + +### get room device +GET http://localhost:8080/room/ROOM/device/TEST + +### get room device +PUT http://localhost:8080/room/ROOM/device/TEST +Content-Type: application/json + +{ + "type": "PowerSocket", + "power_rate": 5, + "on": true +} + +### get room device +DELETE http://localhost:8080/room/ROOM/device/TEST