use std::sync::Arc;
use axum::{Json, extract::State, http::StatusCode};
use serde::{Serialize, de::DeserializeOwned};
use crate::{
smart_device_dto::{
Type,
activation::ActivateRequestDto,
config::{ConfigRequestDto, ConfigResponseDto, TypeOption},
read::ReadResponseDto,
status::DeviceStatusResponseDto,
write::WriteRequestDto,
},
smart_device_interface::config::{Config, Mode, ScriptingApi},
};
use super::{
config::{read_config_file_with_path, update_config_file_with_path},
device_builder::DeviceBuilder,
};
pub(crate) async fn write_device_handler<T>(
State(device_service): State<DeviceBuilder<T>>,
Json(payload): Json<WriteRequestDto>,
) -> StatusCode
where
T: Clone + Default + DeserializeOwned,
{
let config = device_service
.config
.read()
.map(|c| c.clone())
.unwrap_or_else(|_| Arc::new(Config::<T>::default()));
match device_service.write_handler {
Some(handler) => handler(payload.data, config).await,
None => StatusCode::INTERNAL_SERVER_ERROR,
}
}
pub(crate) async fn read_device_handler<T>(
State(device_service): State<DeviceBuilder<T>>,
) -> Json<ReadResponseDto>
where
T: Clone + Default + DeserializeOwned,
{
let config = device_service
.config
.read()
.map(|c| c.clone())
.unwrap_or_else(|_| Arc::new(Config::<T>::default()));
match device_service.read_handler {
None => Json(ReadResponseDto { data: Type::None }),
Some(handler) => {
let data = handler(config).await;
Json(ReadResponseDto { data })
}
}
}
pub(crate) async fn get_config_handler<T>(
State(device_service): State<DeviceBuilder<T>>,
) -> Json<Option<ConfigResponseDto<T>>>
where
T: DeserializeOwned + Clone + Default,
{
match read_config_file_with_path(&device_service.config_path) {
Ok(config) => {
if let Ok(mut guard) = device_service.config.write() {
*guard = Arc::new(config.clone());
}
let mut input_type: Option<TypeOption> = None;
let mut output_type: Option<TypeOption> = None;
let mode: crate::smart_device_dto::config::Mode;
match device_service.mode {
Mode::Input(t) => {
input_type = Some(t);
mode = crate::smart_device_dto::config::Mode::Input;
}
Mode::Output(t) => {
output_type = Some(t);
mode = crate::smart_device_dto::config::Mode::Output;
}
Mode::InputOutput(t_i, t_o) => {
input_type = Some(t_i);
output_type = Some(t_o);
mode = crate::smart_device_dto::config::Mode::InputOutput;
}
_ => {
mode = crate::smart_device_dto::config::Mode::Unknown;
}
};
let config_dto = ConfigResponseDto {
mode,
input_type,
output_type,
scripting_api: config.scripting_api.map(|s| {
crate::smart_device_dto::config::ScriptingApi {
url: s.url,
token: s.token,
}
}),
additional_config: config.additional_config,
};
Json(Some(config_dto))
}
Err(_) => Json(None),
}
}
pub(crate) async fn status_device_handler<T>(
State(device_service): State<DeviceBuilder<T>>,
) -> Json<DeviceStatusResponseDto>
where
T: Clone + Default + DeserializeOwned,
{
let config = device_service
.config
.read()
.map(|c| c.clone())
.unwrap_or_else(|_| Arc::new(Config::<T>::default()));
Json((device_service.status_handler)(config).await)
}
pub(crate) async fn config_update_handler<T>(
State(device_service): State<DeviceBuilder<T>>,
Json(config): Json<ConfigRequestDto<T>>,
) -> StatusCode
where
T: Serialize + Clone + Default,
{
let config = (device_service.config_interceptor_handler)(config, {
device_service
.config
.read()
.map(|c| c.clone())
.unwrap_or_else(|_| Arc::new(Config::<T>::default()))
})
.await;
if update_config_file_with_path(&config, &device_service.config_path).is_ok() {
if let Ok(mut guard) = device_service.config.write() {
*guard = Arc::new(config);
}
StatusCode::OK
} else {
StatusCode::INTERNAL_SERVER_ERROR
}
}
pub(crate) async fn activate_device<T>(
State(device_service): State<DeviceBuilder<T>>,
Json(config): Json<ActivateRequestDto>,
) -> StatusCode
where
T: Clone + Default + Serialize + DeserializeOwned,
{
let mut base_config: Config<T> = device_service
.config
.read()
.ok()
.map(|c| (*c).as_ref().clone())
.unwrap_or_else(|| {
read_config_file_with_path(&device_service.config_path).unwrap_or_default()
});
base_config.scripting_api = Some(ScriptingApi {
url: config.url,
token: config.token,
});
if update_config_file_with_path(&base_config, &device_service.config_path).is_ok() {
if let Ok(mut guard) = device_service.config.write() {
*guard = Arc::new(base_config);
}
StatusCode::OK
} else {
StatusCode::INTERNAL_SERVER_ERROR
}
}