Forgot to add
This commit is contained in:
parent
83d712b930
commit
427a3095f8
15 changed files with 1992 additions and 124 deletions
|
@ -0,0 +1,71 @@
|
|||
use std::borrow::Cow;
|
||||
use phf::phf_map;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
#[repr(u64)]
|
||||
pub enum SupportedUnit {
|
||||
Celsius, // Needs verification > 273.15
|
||||
Percentage, // Needs verification >= 100 && <= 0
|
||||
MillimeterHg, // Needs verification
|
||||
UVIndex, // Needs verification
|
||||
Boolean, // Needs verification
|
||||
Kbps,
|
||||
Volume,
|
||||
KWh,
|
||||
Amps,
|
||||
Volts,
|
||||
Watts,
|
||||
Seconds,
|
||||
}
|
||||
|
||||
impl Serialize for SupportedUnit {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(match self {
|
||||
SupportedUnit::Celsius => "C",
|
||||
SupportedUnit::Percentage => "%",
|
||||
SupportedUnit::MillimeterHg => "mmHg",
|
||||
SupportedUnit::UVIndex => "UV",
|
||||
SupportedUnit::Boolean => "bool",
|
||||
SupportedUnit::Kbps => "Kbps",
|
||||
SupportedUnit::Volume => "m3",
|
||||
SupportedUnit::Amps => "A",
|
||||
SupportedUnit::Volts => "V",
|
||||
SupportedUnit::Watts => "W",
|
||||
SupportedUnit::Seconds => "s",
|
||||
SupportedUnit::KWh => "KWh"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SupportedUnit {
|
||||
fn deserialize<'a, D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let color_str = Cow::<'a, str>::deserialize(deserializer)?;
|
||||
match STR_TO_UNITS.get(color_str.as_ref()) {
|
||||
Some(v) => Ok(v.clone()),
|
||||
None => Err(serde::de::Error::custom("Invalid unit")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static STR_TO_UNITS: phf::Map<&'static str, SupportedUnit> = phf_map! {
|
||||
"C" => SupportedUnit::Celsius,
|
||||
"%" => SupportedUnit::Percentage,
|
||||
"mmHg" => SupportedUnit::MillimeterHg,
|
||||
"UV" => SupportedUnit::UVIndex,
|
||||
"bool" => SupportedUnit::Boolean,
|
||||
"Kbps" => SupportedUnit::Kbps,
|
||||
"m3" => SupportedUnit::Volume,
|
||||
"A" => SupportedUnit::Amps,
|
||||
"V" => SupportedUnit::Volts,
|
||||
"W" => SupportedUnit::Watts,
|
||||
"s" => SupportedUnit::Seconds,
|
||||
"KWh" => SupportedUnit::Seconds,
|
||||
};
|
143
src/main.rs
143
src/main.rs
|
@ -1,3 +1,4 @@
|
|||
#![feature(impl_trait_in_fn_trait_return)]
|
||||
|
||||
/*
|
||||
Три датчика реалтайм:
|
||||
|
@ -33,98 +34,30 @@ C названием и координатами:
|
|||
##
|
||||
*/
|
||||
|
||||
extern crate core;
|
||||
|
||||
mod hashes;
|
||||
mod web_server;
|
||||
mod protocol;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::mem::{size_of, size_of_val};
|
||||
use std::num::NonZeroUsize;
|
||||
use nom::{InputTake, IResult, Needed, Parser};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{take_until, take_while_m_n};
|
||||
use nom::bytes::streaming::{take_till1, take};
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::streaming::take_till;
|
||||
use nom::character::streaming::{anychar, char, hex_digit0, newline};
|
||||
use nom::character::complete::hex_digit1;
|
||||
use std::str::FromStr;
|
||||
use axum::Router;
|
||||
use axum::routing::post;
|
||||
use hifitime::Epoch;
|
||||
|
||||
use nom::combinator::{map, map_opt, map_parser, opt, recognize, rest};
|
||||
use nom::Err as NomErr;
|
||||
use nom::error::{Error, ErrorKind as NomErrorKind};
|
||||
use nom::multi::{count, separated_list1};
|
||||
use nom::sequence::{delimited, preceded, separated_pair};
|
||||
use rust_decimal::Decimal;
|
||||
use thiserror::Error;
|
||||
|
||||
struct NarodMonPacketSerializer {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct NarodMonValues<'a> {
|
||||
mac: Cow<'a, str>,
|
||||
value: Decimal,
|
||||
time: Option<u64>,
|
||||
name: Option<u64>
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
|
||||
enum ValueMac<'a> {
|
||||
Temperature(Cow<'a, str>, Option<u128>)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct NarodMonPacket<'a> {
|
||||
mac: [u8; 6],
|
||||
name: Option<Cow<'a, str>>,
|
||||
values: HashSet<NarodMonValues<'a>>
|
||||
}
|
||||
|
||||
fn parse_mac_address(input: &str) -> IResult<&str, [u8; 6]> {
|
||||
let mut mac = [0u8; 6];
|
||||
|
||||
let mut counter = 0;
|
||||
|
||||
let (leftovers, i) = take(17usize)(input)?;
|
||||
|
||||
let (_, out) = count(|inp| {
|
||||
//dbg!(inp);
|
||||
let (mut i, o) = map_parser(take(2usize), hex_digit1)(inp)?;
|
||||
if counter != 5 {
|
||||
(i, _) = tag("-")(i)?;
|
||||
}
|
||||
counter+=1;
|
||||
Ok((i, o))
|
||||
}, 6)(i)?;
|
||||
|
||||
//dbg!(&out);
|
||||
|
||||
hex::decode_to_slice(out.join(""), &mut mac).unwrap();
|
||||
|
||||
Ok((leftovers, mac))
|
||||
}
|
||||
|
||||
fn parse_packet(input: &str) -> IResult<&str, NarodMonPacket> {
|
||||
let (input, _) = tag("#")(input)?;
|
||||
|
||||
let (input, mac) = parse_mac_address(input)?;
|
||||
|
||||
dbg!(input);
|
||||
|
||||
let (input, opt_name) = opt(delimited(tag("#"), take_till1(|c| c == '\n'), tag("\n")))(input)?;
|
||||
use crate::protocol::{NarodMonPacket, NarodMonValues};
|
||||
use crate::protocol::error::Error;
|
||||
use crate::protocol::error::Error::TimestampParseError;
|
||||
use crate::web_server::old_app_api::old_api_handler;
|
||||
use crate::web_server::server_main;
|
||||
|
||||
|
||||
|
||||
let (input, values) = parse_sensor_values(input)?;
|
||||
|
||||
Ok((input,
|
||||
NarodMonPacket {
|
||||
mac,
|
||||
name: opt_name,
|
||||
values,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_sensor_value(input: Vec<&str>) -> IResult<&str, NarodMonValues> {
|
||||
/*fn parse_sensor_value(input: Vec<&str>) -> MyIError<Vec<&str>, NarodMonValues> {
|
||||
Ok(
|
||||
(input, NarodMonValues {
|
||||
mac: Default::default(),
|
||||
|
@ -133,44 +66,46 @@ fn parse_sensor_value(input: Vec<&str>) -> IResult<&str, NarodMonValues> {
|
|||
name: None,
|
||||
})
|
||||
)
|
||||
}*/
|
||||
|
||||
|
||||
struct Params {
|
||||
|
||||
}
|
||||
|
||||
fn parse_sensor_values(input: &str) -> IResult<&str, HashSet<NarodMonValues>> {
|
||||
let (input, asd) = map_parser(take_until("##"),separated_list1(tag("\n"), rest))(input)?;
|
||||
|
||||
|
||||
for line in asd {
|
||||
let one = NarodMonValues::default();
|
||||
let (line, _) = tag("#")(line)?;
|
||||
let (line, sensor_mac) = take_till1(|c| c == '\n' || c == "#")(line);
|
||||
let (line, _) = preceded(tag("#"), take_till1(|c| c == '\n' || c == "#")(line);
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
//dotenvy::dotenv().unwrap();
|
||||
|
||||
let web_server_hndl = tokio::spawn(server_main());
|
||||
|
||||
|
||||
}
|
||||
|
||||
Ok((input,
|
||||
Default::default()
|
||||
))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
web_server_hndl.await.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::protocol::parser::{parse_mac_address, parse_packet};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_mac() {
|
||||
assert_eq!(parse_mac_address("12-34-AA-12-55-AA"), Ok(("", [18, 52, 170, 18, 85, 170])))
|
||||
//assert_eq!(parse_mac_address("12-34-AA-12-55-AA"), Ok(("", [18, 52, 170, 18, 85, 170])) );
|
||||
|
||||
println!("{:?}", parse_mac_address("12-34-AA-12-55-AA"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_packet() {
|
||||
let inp = "#26-94-1D-75-C2-F8#Метео\n";
|
||||
let inp = r#"#26-94-1D-75-C2-F8#Метео
|
||||
#OWNER#nm17
|
||||
#T1#1.12
|
||||
#T2#10000#1231410321#sensorName
|
||||
#T2#1.2#3400005345
|
||||
##"#;
|
||||
|
||||
println!("{:?}", parse_packet(inp));
|
||||
|
||||
println!("{:#?}", parse_packet(inp));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
mod packet_types;
|
||||
pub mod error;
|
||||
pub mod parser;
|
||||
mod server;
|
||||
|
||||
pub use packet_types::*;
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
use hifitime::Epoch;
|
||||
use nom::{InputTake, Needed, Parser};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{take_until, take_until1, take_while_m_n};
|
||||
use nom::bytes::complete::{take_till1, take, take_while, take_while1};
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::streaming::take_till;
|
||||
use nom::character::streaming::{anychar, char, hex_digit0, newline};
|
||||
use nom::character::complete::hex_digit1;
|
||||
|
||||
use nom::combinator::{map, map_opt, map_parser, opt, recognize, rest};
|
||||
use nom::Err as NomErr;
|
||||
use nom::error::{context, ContextError, ErrorKind as NomErrorKind, ParseError as NomParseError, Error as NomError, VerboseError};
|
||||
use nom::multi::{count, separated_list0, separated_list1};
|
||||
use nom::sequence::{delimited, preceded, separated_pair};
|
||||
use rust_decimal::Decimal;
|
||||
use crate::protocol::error::Error;
|
||||
use crate::protocol::{NarodMonPacket, NarodMonValues};
|
||||
use crate::protocol::error::Error::TimestampParseError;
|
||||
|
||||
type MyIError<I, O> = Result<(I, O), Error<I>>;
|
||||
|
||||
|
||||
pub fn parse_mac_address(input: &str) -> MyIError<&str, [u8; 6]> {
|
||||
let mut mac = [0u8; 6];
|
||||
|
||||
let mut counter = 0;
|
||||
|
||||
let (leftovers, i) = context("17 символов для MAC адреса", take(17usize))(input)?;
|
||||
|
||||
let (_, out) = count(|inp| {
|
||||
//dbg!(inp);
|
||||
let (mut i, o) = context("Октет", map_parser(take(2usize), hex_digit1))(inp)?;
|
||||
if counter != 5 {
|
||||
(i, _) = tag("-")(i)?;
|
||||
}
|
||||
counter += 1;
|
||||
Ok((i, o))
|
||||
}, 6)(i)?;
|
||||
|
||||
//dbg!(&out);
|
||||
|
||||
hex::decode_to_slice(out.join(""), &mut mac).unwrap();
|
||||
|
||||
Ok((leftovers, mac))
|
||||
}
|
||||
|
||||
pub fn parse_packet(input: &str) -> MyIError<&str, NarodMonPacket> {
|
||||
let (input, _) = tag("#")(input)?;
|
||||
|
||||
let (input, mac) = parse_mac_address(input)?;
|
||||
|
||||
let (input, opt_name) = opt(delimited(tag("#"), take_while(|c| c != '\n'), tag("\n")))(input)?;
|
||||
|
||||
let mut packet = NarodMonPacket::default();
|
||||
packet.mac = mac;
|
||||
|
||||
let mut hs = HashSet::new();
|
||||
|
||||
let (input, asd) = context(
|
||||
"Получение значений до тега терминатора",
|
||||
map_parser(
|
||||
take_until1("##"),
|
||||
separated_list0(tag("\n"), take_while1(|c| c != '\n'))
|
||||
)
|
||||
)(input)?;
|
||||
|
||||
|
||||
println!("ASDASD: {:?}", asd);
|
||||
|
||||
for line in asd {
|
||||
let (line, _) = tag("#")(line)?;
|
||||
let (line, sensor_mac) = take_while1(|c| c != '\n' && c != '#')(line)?;
|
||||
|
||||
let (line, _) = tag("#")(line)?;
|
||||
|
||||
match sensor_mac {
|
||||
"OWNER" => {
|
||||
let (line, owner_value) = take_while1(|c| c != '\n')(line)?;
|
||||
|
||||
packet.owner = Some(owner_value.into())
|
||||
|
||||
//hs.insert(NarodMonValues::Owner(owner_value.into()));
|
||||
//let (line, _) = tag("\n")(line)?;
|
||||
}
|
||||
_ => {
|
||||
let (line, sensor_value) = take_while1(|c| c != '\n' && c != '#')(line)?;
|
||||
let (line, sensor_time) = opt(preceded(tag("#"), take_while1(|c| c != '\n' && c != '#')))(line)?;
|
||||
let (line, sensor_name) = opt(preceded(tag("#"), take_while1(|c| c != '\n')))(line)?;
|
||||
|
||||
|
||||
let sensor_time = match sensor_time {
|
||||
Some(v) => Some(Epoch::from_unix_seconds(v.parse().map_err(|e| TimestampParseError(e))?)),
|
||||
None => None
|
||||
};
|
||||
|
||||
hs.insert(NarodMonValues {
|
||||
mac: sensor_mac.into(),
|
||||
value: Decimal::from_str(sensor_value).unwrap(),
|
||||
time: sensor_time, // TODO
|
||||
unit: None,
|
||||
name: sensor_name.map(|v| Cow::from(v)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (input, _) = tag("##")(input)?;
|
||||
|
||||
packet.name = opt_name.map(|v| Cow::from(v));
|
||||
packet.values = hs;
|
||||
|
||||
Ok((input, packet))
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
async fn main() {
|
||||
|
||||
}
|
|
@ -25,6 +25,11 @@ pub enum AppError {
|
|||
#[error("Fuck")]
|
||||
RequestTooLarge,
|
||||
|
||||
#[error("Api")]
|
||||
ApiKeyInvalid {
|
||||
reason: &'static str
|
||||
},
|
||||
|
||||
#[error("Fuck")]
|
||||
UnitValidationFailed {
|
||||
max: Option<Decimal>,
|
||||
|
@ -51,6 +56,9 @@ impl IntoResponse for AppError {
|
|||
},
|
||||
AppError::ServerRedisError(_) => {
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, "Internal server error")
|
||||
},
|
||||
AppError::ApiKeyInvalid { .. } => {
|
||||
(StatusCode::BAD_REQUEST, "API Key invalid")
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -76,6 +84,9 @@ impl IntoResponse for AppError {
|
|||
AppError::RequestTooLarge => {
|
||||
headers.insert("X-Max-Request-Size", HeaderValue::try_from("10 KiB = 10240 bytes").unwrap());
|
||||
},
|
||||
AppError::ApiKeyInvalid { reason } => {
|
||||
headers.insert("X-Error-Description", HeaderValue::try_from(reason).unwrap());
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,13 +6,47 @@ use axum::{
|
|||
};
|
||||
use axum::error_handling::{HandleError, HandleErrorLayer};
|
||||
use axum::http::StatusCode;
|
||||
use crate::server::old_app_api::old_api_handler;
|
||||
use axum::routing::post;
|
||||
use fred::bytes_utils::Str;
|
||||
use fred::prelude::*;
|
||||
use crate::web_server::old_app_api::old_api_handler;
|
||||
|
||||
pub mod old_app_api;
|
||||
mod utils;
|
||||
pub(crate) mod app_error;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct NMAppState {
|
||||
redis_client: RedisClient
|
||||
pub struct NMAppState {
|
||||
pub redis_client: RedisClient
|
||||
}
|
||||
|
||||
async fn main()
|
||||
use heapless::String as HeaplessString;
|
||||
|
||||
pub async fn server_main() {
|
||||
let config = RedisConfig::default();
|
||||
let perf = PerformanceConfig::default();
|
||||
let policy = ReconnectPolicy::default();
|
||||
let client = RedisClient::new(config, Some(perf), Some(policy));
|
||||
|
||||
// connect to the server, returning a handle to the task that drives the connection
|
||||
let _ = client.connect();
|
||||
let _ = client.wait_for_connect().await.unwrap();
|
||||
|
||||
let asd: Str = client.ping().await.unwrap();
|
||||
|
||||
println!("Ping result: {}", asd);
|
||||
|
||||
let state = NMAppState {
|
||||
redis_client: client
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/api", post(old_api_handler))
|
||||
.with_state(state);
|
||||
|
||||
|
||||
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -1,29 +1,35 @@
|
|||
use std::borrow::Cow;
|
||||
use axum::body::{Body, Bytes, HttpBody};
|
||||
use axum::extract::State;
|
||||
use axum::http::Request;
|
||||
use axum::Json;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use nom::AsBytes;
|
||||
use serde_json::Value;
|
||||
use crate::server::old_app_api::app_error::AppError;
|
||||
use crate::server::old_app_api::handlers::app_init;
|
||||
use crate::server::old_app_api::types::{AppInitRequest, MandatoryParams};
|
||||
use crate::web_server::app_error::AppError;
|
||||
use crate::web_server::NMAppState;
|
||||
use crate::web_server::old_app_api::handlers::app_init;
|
||||
use crate::web_server::old_app_api::types::{AppInitRequest, MandatoryParams};
|
||||
use crate::web_server::utils::redis::is_api_key_valid;
|
||||
|
||||
|
||||
pub async fn old_api_handler(
|
||||
app_state: State<NMAppState>,
|
||||
body_bytes: Bytes,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
if body_bytes.len() > 10 * 1024 { // 10 KiB
|
||||
return Err(AppError::RequestTooLarge)
|
||||
}
|
||||
|
||||
let mandatory_params: MandatoryParams<'_> = serde_json::from_slice(body_bytes.as_bytes())?;
|
||||
let mandatory_params: MandatoryParams<'_> = serde_json::from_slice(body_bytes.as_bytes())?; // TODO: Simd-JSON
|
||||
|
||||
is_api_key_valid(&app_state.redis_client, mandatory_params.api_key.as_ref()).await?;
|
||||
|
||||
return match mandatory_params.cmd.as_ref() {
|
||||
"appInit" => {
|
||||
let body: AppInitRequest = serde_json::from_slice(body_bytes.as_bytes())?;
|
||||
|
||||
Ok(app_init(body).await)
|
||||
Ok(app_init(body, app_state).await)
|
||||
}
|
||||
_ => {
|
||||
Err(AppError::UnknownMethod(mandatory_params.cmd.to_string()))
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
use axum::body::Body;
|
||||
use axum::extract::State;
|
||||
use axum::http::Request;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use axum::Json;
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
use serde_json::Value as JsonValue;
|
||||
use crate::server::old_app_api::types::AppInitRequest;
|
||||
use crate::web_server::old_app_api::types::AppInitRequest;
|
||||
use heapless::String as HeaplessString;
|
||||
use ufmt::uwrite;
|
||||
use crate::web_server::NMAppState;
|
||||
use crate::web_server::app_error::AppError;
|
||||
|
||||
use fred::interfaces::KeysInterface;
|
||||
|
||||
pub async fn app_init(body: AppInitRequest<'_>, State(appState): State<>) -> impl IntoResponse {
|
||||
pub async fn app_init(body: AppInitRequest<'_>, State(appState): State<NMAppState>) -> Result<impl IntoResponse, AppError> {
|
||||
let _: () = appState.redis_client.set("test", 123, None, None, true).await?;
|
||||
|
||||
|
||||
"Hello, World!"
|
||||
Ok((StatusCode::OK, "Hello, World!").into_response())
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
mod types;
|
||||
mod handlers;
|
||||
mod config_app;
|
||||
mod app_error;
|
||||
|
||||
pub use config_app::old_api_handler;
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ pub struct AppInitRequest<'a> {
|
|||
#[serde(borrow)]
|
||||
pub model: Cow<'a, str>,
|
||||
|
||||
#[serde(borrow)]
|
||||
pub width: Cow<'a, str>,
|
||||
pub width: u64
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod redis;
|
|
@ -0,0 +1,31 @@
|
|||
use fred::prelude::*;
|
||||
use heapless::String as HeaplessString;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use ufmt::uwrite;
|
||||
use crate::web_server::app_error::AppError;
|
||||
|
||||
lazy_static! {
|
||||
static ref ALLOWED_API_KEY_CHARACTERS: Regex = Regex::new("[a-zA-Z0-9]{13}").unwrap();
|
||||
}
|
||||
|
||||
pub struct ApiKeyDescription {
|
||||
apikey_owner: i64
|
||||
}
|
||||
|
||||
pub async fn is_api_key_valid(client: &RedisClient, api_key: &str) -> Result<ApiKeyDescription, AppError> {
|
||||
if !ALLOWED_API_KEY_CHARACTERS.is_match(api_key) {
|
||||
return Err(AppError::ApiKeyInvalid { reason: "Invalid characters present in the API key." })
|
||||
}
|
||||
|
||||
let mut key_buffer = HeaplessString::<{7 + 13}>::new();
|
||||
uwrite!(key_buffer, "apikey_{}", api_key);
|
||||
|
||||
let valid: Option<i64> = client.hget(key_buffer.as_str(), "owner").await?;
|
||||
|
||||
valid.map(|uid| {
|
||||
ApiKeyDescription {
|
||||
apikey_owner: uid
|
||||
}
|
||||
}).ok_or(AppError::ApiKeyInvalid { reason: "Unknown API key" })
|
||||
}
|
Loading…
Add table
Reference in a new issue