Merge branch 'device_managment'
This commit is contained in:
commit
04a21c79f6
9 changed files with 189 additions and 79 deletions
62
Cargo.lock
generated
62
Cargo.lock
generated
|
@ -292,6 +292,16 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"iovec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
@ -307,7 +317,7 @@ version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35"
|
checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -428,7 +438,7 @@ version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2"
|
checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures 0.3.30",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -643,11 +653,11 @@ dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"bytes-utils",
|
"bytes-utils",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"float-cmp",
|
"float-cmp",
|
||||||
"futures",
|
"futures 0.3.30",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"nom",
|
"nom",
|
||||||
|
@ -668,6 +678,12 @@ version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.1.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -761,6 +777,7 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"slab",
|
"slab",
|
||||||
|
"tokio-io",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -890,7 +907,7 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"fnv",
|
"fnv",
|
||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
@ -974,12 +991,13 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bstr",
|
"bstr",
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"fred",
|
"fred",
|
||||||
|
"futures-util",
|
||||||
"heapless",
|
"heapless",
|
||||||
"hex",
|
"hex",
|
||||||
"hifitime",
|
"hifitime",
|
||||||
|
@ -999,6 +1017,15 @@ dependencies = [
|
||||||
"ufmt",
|
"ufmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iovec"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.0"
|
version = "1.70.0"
|
||||||
|
@ -1236,7 +1263,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ffd6ac357a3fd885753ddeb4130ec92474e79d013362532eba4778854466981"
|
checksum = "2ffd6ac357a3fd885753ddeb4130ec92474e79d013362532eba4778854466981"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -1726,7 +1753,7 @@ version = "4.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c31deddf734dc0a39d3112e73490e88b61a05e83e074d211f348404cee4d2c6"
|
checksum = "9c31deddf734dc0a39d3112e73490e88b61a05e83e074d211f348404cee4d2c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"bytes-utils",
|
"bytes-utils",
|
||||||
"cookie-factory",
|
"cookie-factory",
|
||||||
"crc16",
|
"crc16",
|
||||||
|
@ -1804,7 +1831,7 @@ checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"bytecheck",
|
"bytecheck",
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
"ptr_meta",
|
"ptr_meta",
|
||||||
"rend",
|
"rend",
|
||||||
|
@ -1833,7 +1860,7 @@ checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"borsh",
|
"borsh",
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand",
|
"rand",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
|
@ -2225,7 +2252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
|
@ -2237,6 +2264,17 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-io"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 0.4.12",
|
||||||
|
"futures 0.1.31",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
@ -2265,7 +2303,7 @@ version = "0.7.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes 1.6.0",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
|
|
@ -31,3 +31,4 @@ smallstr = { version = "0.3.0", features = ["std", "union"] }
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.40"
|
||||||
tokio = { version = "1.28.2", features = ["full"] }
|
tokio = { version = "1.28.2", features = ["full"] }
|
||||||
ufmt = { version = "0.2.0", features = ["std"] }
|
ufmt = { version = "0.2.0", features = ["std"] }
|
||||||
|
futures-util = { version = "0.3.30", features = ["tokio-io"] }
|
||||||
|
|
|
@ -13,3 +13,5 @@
|
||||||
- Поля
|
- Поля
|
||||||
- `exists`: bool
|
- `exists`: bool
|
||||||
- `unit`: str
|
- `unit`: str
|
||||||
|
|
||||||
|
!!!! Убедитесь что в переменных ключей нет `_` !!!!
|
||||||
|
|
|
@ -6,15 +6,20 @@
|
||||||
// #[serde(rename = "...")]
|
// #[serde(rename = "...")]
|
||||||
// #[serde(alias = "...")]
|
// #[serde(alias = "...")]
|
||||||
|
|
||||||
use crate::utils::{EpochUTC, SupportedUnit};
|
|
||||||
use crate::ingest_protocol::error::Error;
|
use crate::ingest_protocol::error::Error;
|
||||||
use crate::ingest_protocol::parser::parse_mac_address;
|
use crate::ingest_protocol::parser::parse_mac_address;
|
||||||
|
use crate::utils::{EpochUTC, SupportedUnit};
|
||||||
|
use crate::web_server::app_error::AppError;
|
||||||
|
|
||||||
|
use fred::clients::RedisClient;
|
||||||
|
use fred::interfaces::{HashesInterface, KeysInterface};
|
||||||
|
use hifitime::Epoch;
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
|
use ufmt::uwrite;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
/// Данные с одного датчика.
|
/// Данные с одного датчика.
|
||||||
|
@ -74,6 +79,16 @@ pub struct NMDeviceDataPacket {
|
||||||
pub lon: Option<Decimal>,
|
pub lon: Option<Decimal>,
|
||||||
pub alt: Option<Decimal>,
|
pub alt: Option<Decimal>,
|
||||||
|
|
||||||
|
/// Команды для управления устройством.
|
||||||
|
///
|
||||||
|
/// Текст после декодировки.
|
||||||
|
///
|
||||||
|
/// ## Отчёт совместимости
|
||||||
|
/// Функционал изначально narodmon-овский.
|
||||||
|
/// Про то, как кодировать при наличии символов `#;=` или поддержку UTF-8 не сказано.
|
||||||
|
/// Рассчитываю на то, что все значения нужно URL кодировать.
|
||||||
|
pub commands: Option<HashMap<String, String>>,
|
||||||
|
|
||||||
// HTTP GET/POST url-encode specific parameters
|
// HTTP GET/POST url-encode specific parameters
|
||||||
/// TODO: Желательное поведение в будущем:
|
/// TODO: Желательное поведение в будущем:
|
||||||
/// - Если в values есть хотябы один times и этот time не None => Игнорируем этот time
|
/// - Если в values есть хотябы один times и этот time не None => Игнорируем этот time
|
||||||
|
@ -82,7 +97,74 @@ pub struct NMDeviceDataPacket {
|
||||||
pub time: Option<EpochUTC>,
|
pub time: Option<EpochUTC>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NMDeviceDataPacket {
|
||||||
|
pub async fn save_to_db(&self, redis: &RedisClient) -> Result<(), AppError> {
|
||||||
|
let device_mac_enc = hex::encode(self.mac);
|
||||||
|
|
||||||
|
let mut key = String::new();
|
||||||
|
|
||||||
|
let now = Epoch::now().unwrap().into();
|
||||||
|
let mut device_time = self.time.unwrap_or(now);
|
||||||
|
|
||||||
|
// TODO: Добавить гистерезис
|
||||||
|
// Отчёт совместимости: отсутствует
|
||||||
|
if device_time > now {
|
||||||
|
device_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
let device_tai_timestamp = device_time.0.to_duration_since_j1900().to_seconds();
|
||||||
|
|
||||||
|
uwrite!(&mut key, "devices_{}", device_mac_enc).unwrap();
|
||||||
|
|
||||||
|
let device_exists: Option<bool> = redis.hget(key.as_str(), "exists").await?;
|
||||||
|
|
||||||
|
if !device_exists.is_some_and(|v| v == true) {
|
||||||
|
return Err(AppError::DeviceNotFound(hex::encode(&self.mac)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// devices_{device_id}_{tai_timestamp}_{sensor_id}
|
||||||
|
for sensor in &self.values {
|
||||||
|
let mut key = String::new();
|
||||||
|
uwrite!(
|
||||||
|
&mut key,
|
||||||
|
"devices_{}_{}_{}",
|
||||||
|
device_mac_enc,
|
||||||
|
device_tai_timestamp.to_string(),
|
||||||
|
sensor.mac
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
redis
|
||||||
|
.set(key.as_str(), sensor.value.to_string(), None, None, false)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(commands) = &self.commands {
|
||||||
|
for (cmd_key, cmd_value) in commands {
|
||||||
|
let mut key = String::new();
|
||||||
|
uwrite!(&mut key, "devices_{}_cmds_{}", device_mac_enc, cmd_key).unwrap();
|
||||||
|
|
||||||
|
redis
|
||||||
|
.set(key.as_str(), cmd_value, None, None, false)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Deserialize)]
|
||||||
pub struct NMJsonPacket {
|
pub struct NMJsonPacket {
|
||||||
pub devices: Vec<NMDeviceDataPacket>,
|
pub devices: Vec<NMDeviceDataPacket>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NMJsonPacket {
|
||||||
|
pub async fn save_to_db(&self, redis: &RedisClient) -> Result<(), AppError> {
|
||||||
|
for device in &self.devices {
|
||||||
|
device.save_to_db(redis).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
src/ingest_socket_server/mod.rs
Normal file
12
src/ingest_socket_server/mod.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// let body = "OK";
|
||||||
|
//
|
||||||
|
// let mut stream = app_state.redis_client.scan("devices_{}", None, None);
|
||||||
|
//
|
||||||
|
// while let Some(cmd) = stream.next().await {
|
||||||
|
// let mut cmd = cmd?;
|
||||||
|
// let redis_cmd_keys = cmd.take_results().unwrap();
|
||||||
|
//
|
||||||
|
// for redis_cmd_key in redis_cmd_keys {
|
||||||
|
// redis_cmd_key.as_str().unwrap().split("_"); // Продолжи
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -1,12 +1,11 @@
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
mod ingest_protocol;
|
mod ingest_protocol;
|
||||||
mod web_server;
|
mod ingest_socket_server;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod web_server;
|
||||||
use crate::web_server::server_main;
|
use crate::web_server::server_main;
|
||||||
|
|
||||||
struct Params {}
|
struct Params {}
|
||||||
|
|
|
@ -4,18 +4,21 @@ pub mod qs_parser;
|
||||||
|
|
||||||
use crate::ingest_protocol::{NMDeviceDataPacket, NMJsonPacket};
|
use crate::ingest_protocol::{NMDeviceDataPacket, NMJsonPacket};
|
||||||
use crate::web_server::app_error::AppError;
|
use crate::web_server::app_error::AppError;
|
||||||
|
use fred::bytes_utils::Str;
|
||||||
|
|
||||||
|
|
||||||
use ntex::http::{HttpMessage, StatusCode};
|
|
||||||
use ntex::util::Bytes;
|
|
||||||
use ntex::{http, web};
|
|
||||||
use fred::prelude::*;
|
use fred::prelude::*;
|
||||||
use hifitime::Epoch;
|
use hifitime::Epoch;
|
||||||
|
use ntex::http::{HttpMessage, StatusCode};
|
||||||
|
use ntex::util::Bytes;
|
||||||
use ntex::web::types::State;
|
use ntex::web::types::State;
|
||||||
|
use ntex::{http, web};
|
||||||
|
use qs_parser::QSParserError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use ufmt::uwrite;
|
use ufmt::uwrite;
|
||||||
use crate::web_server::NMAppState;
|
|
||||||
use crate::web_server::old_device_sensor_api::qs_parser::QSParserError;
|
use futures_util::stream::StreamExt;
|
||||||
|
|
||||||
|
use super::NMAppState;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -27,7 +30,6 @@ pub enum Error {
|
||||||
QSParserError(#[from] QSParserError),
|
QSParserError(#[from] QSParserError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Обработчик данных датчиков с устройств.
|
/// Обработчик данных датчиков с устройств.
|
||||||
///
|
///
|
||||||
/// Слушает /post и /get.
|
/// Слушает /post и /get.
|
||||||
|
@ -76,41 +78,7 @@ pub async fn device_handler<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(real_body) = real_body {
|
if let Some(real_body) = real_body {
|
||||||
for device in real_body.devices {
|
real_body.save_to_db(&app_state.redis_client).await?;
|
||||||
let mut device_key_str = String::new();
|
|
||||||
|
|
||||||
let now = Epoch::now().unwrap().into();
|
|
||||||
let mut device_time = device.time
|
|
||||||
.unwrap_or(now);
|
|
||||||
|
|
||||||
// TODO: Добавить гистерезис
|
|
||||||
// Отчёт совместимости: отсутствует
|
|
||||||
if device_time > now {
|
|
||||||
device_time = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
let device_tai_timestamp = device_time.0
|
|
||||||
.to_duration_since_j1900()
|
|
||||||
.to_seconds();
|
|
||||||
|
|
||||||
uwrite!(device_key_str, "devices_{}", hex::encode(device.mac));
|
|
||||||
|
|
||||||
let device_exists: bool = app_state.redis_client.hget(device_key_str.as_str(), "exists").await?;
|
|
||||||
|
|
||||||
if !device_exists {
|
|
||||||
return Err(AppError::DeviceNotFound(hex::encode(&device.mac)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// devices_{device_id}_{tai_timestamp}_{sensor_id}
|
|
||||||
for sensor in device.values {
|
|
||||||
let mut device_report_key_str = String::new();
|
|
||||||
uwrite!(&mut device_report_key_str, "devices_{}_{}_{}", hex::encode(device.mac), device_tai_timestamp.to_string(), sensor.mac);
|
|
||||||
|
|
||||||
app_state.redis_client.set(
|
|
||||||
device_key_str.as_str(), sensor.value.to_string(), None, None, false,
|
|
||||||
).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err(AppError::UnknownBody {
|
return Err(AppError::UnknownBody {
|
||||||
json_err: json_error,
|
json_err: json_error,
|
||||||
|
@ -118,6 +86,5 @@ pub async fn device_handler<'a>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(web::HttpResponseBuilder::new(StatusCode::OK)
|
Ok(web::HttpResponseBuilder::new(StatusCode::OK).finish())
|
||||||
.finish())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
|
use crate::ingest_protocol::error::Error;
|
||||||
|
use crate::ingest_protocol::parser::parse_mac_address;
|
||||||
|
use crate::ingest_protocol::{NMDeviceDataPacket, SensorValue};
|
||||||
|
use hifitime::Epoch;
|
||||||
|
use ntex::util::HashMap;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::num::ParseFloatError;
|
use std::num::ParseFloatError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use hifitime::Epoch;
|
|
||||||
use ntex::util::HashMap;
|
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use crate::ingest_protocol::error::Error;
|
|
||||||
use crate::ingest_protocol::{NMDeviceDataPacket, SensorValue};
|
|
||||||
use crate::ingest_protocol::parser::parse_mac_address;
|
|
||||||
|
|
||||||
/// В иделае было бы хорошо сделать всё как у [serde_json::Error], но это слишком большая морока
|
/// В иделае было бы хорошо сделать всё как у [serde_json::Error], но это слишком большая морока
|
||||||
#[derive(Error, Clone, Debug)]
|
#[derive(Error, Clone, Debug)]
|
||||||
|
@ -45,7 +45,9 @@ impl From<serde_qs::Error> for QSParserError {
|
||||||
///
|
///
|
||||||
/// Формат: `<SENSOR_MAC>=<SENSOR_VALUE>`.
|
/// Формат: `<SENSOR_MAC>=<SENSOR_VALUE>`.
|
||||||
/// Других данных на подобии названия и времени нет.
|
/// Других данных на подобии названия и времени нет.
|
||||||
pub fn qs_rest_to_values(parsed: HashMap<String, String>) -> Result<HashSet<SensorValue>, QSParserError> {
|
pub fn qs_rest_to_values(
|
||||||
|
parsed: HashMap<String, String>,
|
||||||
|
) -> Result<HashSet<SensorValue>, QSParserError> {
|
||||||
let mut hashset = HashSet::new();
|
let mut hashset = HashSet::new();
|
||||||
|
|
||||||
for (key, value) in parsed {
|
for (key, value) in parsed {
|
||||||
|
@ -62,24 +64,26 @@ pub fn qs_rest_to_values(parsed: HashMap<String, String>) -> Result<HashSet<Sens
|
||||||
Ok(hashset)
|
Ok(hashset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_decimal_if_exists(parsed: &mut HashMap<String, String>, key: &str) -> Result<Option<Decimal>, QSParserError> {
|
pub fn parse_decimal_if_exists(
|
||||||
|
parsed: &mut HashMap<String, String>,
|
||||||
|
key: &str,
|
||||||
|
) -> Result<Option<Decimal>, QSParserError> {
|
||||||
return if let Some(unwrapped_value) = parsed.remove(key) {
|
return if let Some(unwrapped_value) = parsed.remove(key) {
|
||||||
Ok(Some(
|
Ok(Some(Decimal::from_str(unwrapped_value.as_str())?))
|
||||||
Decimal::from_str(unwrapped_value.as_str())?
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_epoch_if_exists(parsed: &mut HashMap<String, String>, key: &str) -> Result<Option<Epoch>, QSParserError> {
|
pub fn parse_epoch_if_exists(
|
||||||
|
parsed: &mut HashMap<String, String>,
|
||||||
|
key: &str,
|
||||||
|
) -> Result<Option<Epoch>, QSParserError> {
|
||||||
return if let Some(unwrapped_value) = parsed.remove(key) {
|
return if let Some(unwrapped_value) = parsed.remove(key) {
|
||||||
Ok(Some(
|
Ok(Some(Epoch::from_unix_seconds(unwrapped_value.parse()?)))
|
||||||
Epoch::from_unix_seconds(unwrapped_value.parse()?)
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn parse_nm_qs_format(input: &str) -> Result<NMDeviceDataPacket, QSParserError> {
|
pub async fn parse_nm_qs_format(input: &str) -> Result<NMDeviceDataPacket, QSParserError> {
|
||||||
|
@ -99,9 +103,12 @@ pub async fn parse_nm_qs_format(input: &str) -> Result<NMDeviceDataPacket, QSPar
|
||||||
lon: parse_decimal_if_exists(&mut parsed, "lon")?,
|
lon: parse_decimal_if_exists(&mut parsed, "lon")?,
|
||||||
alt: parse_decimal_if_exists(&mut parsed, "alt")?,
|
alt: parse_decimal_if_exists(&mut parsed, "alt")?,
|
||||||
time: parse_epoch_if_exists(&mut parsed, "time")?.map(|v| v.into()),
|
time: parse_epoch_if_exists(&mut parsed, "time")?.map(|v| v.into()),
|
||||||
|
// TODO: Выяснить можно ли передавать команды по QS и можно ли их отличить от
|
||||||
|
// маков и значений сенсоров.
|
||||||
|
commands: None,
|
||||||
|
|
||||||
values: qs_rest_to_values(parsed)?,
|
values: qs_rest_to_values(parsed)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(device_data)
|
Ok(device_data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use fred::prelude::*;
|
||||||
use heapless::String as HeaplessString;
|
use heapless::String as HeaplessString;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use ufmt::uwrite;
|
use ufmt::uwrite;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -13,6 +14,7 @@ lazy_static! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Описание полей в KV DB у `apikey_{}`.
|
/// Описание полей в KV DB у `apikey_{}`.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct ApiKeyDescription {
|
pub struct ApiKeyDescription {
|
||||||
/// ID владельца API ключа.
|
/// ID владельца API ключа.
|
||||||
apikey_owner: i64,
|
apikey_owner: i64,
|
||||||
|
|
Loading…
Add table
Reference in a new issue