hipcheck_common/
types.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use crate::{
4	error::Error,
5	proto::{Query as PluginQuery, QueryState},
6};
7use serde::Deserialize;
8use serde_json::Value;
9use std::fmt::{self, Display, Formatter};
10
11#[derive(Debug)]
12pub struct Query {
13	pub id: usize,
14	pub direction: QueryDirection,
15	pub publisher: String,
16	pub plugin: String,
17	pub query: String,
18	pub key: Vec<serde_json::Value>,
19	pub output: Vec<serde_json::Value>,
20	pub concerns: Vec<String>,
21}
22
23#[derive(Debug, PartialEq, Eq)]
24pub enum QueryDirection {
25	Request,
26	Response,
27}
28
29impl TryFrom<QueryState> for QueryDirection {
30	type Error = Error;
31
32	fn try_from(value: QueryState) -> Result<Self, Self::Error> {
33		match value {
34			QueryState::Unspecified => Err(Error::UnspecifiedQueryState),
35			QueryState::SubmitInProgress => Err(Error::UnexpectedRequestInProgress),
36			QueryState::SubmitComplete => Ok(QueryDirection::Request),
37			QueryState::ReplyInProgress => Err(Error::UnexpectedReplyInProgress),
38			QueryState::ReplyComplete => Ok(QueryDirection::Response),
39		}
40	}
41}
42
43impl From<QueryDirection> for QueryState {
44	fn from(value: QueryDirection) -> Self {
45		match value {
46			QueryDirection::Request => QueryState::SubmitComplete,
47			QueryDirection::Response => QueryState::ReplyComplete,
48		}
49	}
50}
51
52impl TryFrom<PluginQuery> for Query {
53	type Error = Error;
54
55	fn try_from(value: PluginQuery) -> Result<Query, Self::Error> {
56		let direction = QueryDirection::try_from(value.state())?;
57
58		fn get_fields_rfd9(v: &PluginQuery) -> Result<(Vec<Value>, Vec<Value>), Error> {
59			let mut keys = Vec::with_capacity(v.key.len());
60			for x in v.key.iter() {
61				let value =
62					serde_json::from_str(x.as_str()).map_err(Error::InvalidJsonInQueryKey)?;
63				keys.push(value);
64			}
65
66			let mut outputs = Vec::with_capacity(v.output.len());
67			for x in v.output.iter() {
68				let value =
69					serde_json::from_str(x.as_str()).map_err(Error::InvalidJsonInQueryOutput)?;
70				outputs.push(value);
71			}
72
73			Ok((keys, outputs))
74		}
75
76		fn get_fields_compat(v: &PluginQuery) -> Result<(Vec<Value>, Vec<Value>), Error> {
77			let key = v.key.join("");
78			let output = v.output.join("");
79			let json_key = serde_json::from_str(&key).map_err(Error::InvalidJsonInQueryKey)?;
80			let json_out =
81				serde_json::from_str(&output).map_err(Error::InvalidJsonInQueryOutput)?;
82			Ok((vec![json_key], vec![json_out]))
83		}
84
85		let rfd9_res = get_fields_rfd9(&value);
86
87		let (keys, outputs) = if rfd9_res.is_err() && cfg!(feature = "rfd9-compat") {
88			get_fields_compat(&value)?
89		} else {
90			rfd9_res?
91		};
92
93		Ok(Query {
94			id: value.id as usize,
95			direction,
96			publisher: value.publisher_name,
97			plugin: value.plugin_name,
98			query: value.query_name,
99			key: keys,
100			output: outputs,
101			concerns: value.concern,
102		})
103	}
104}
105
106impl TryFrom<Query> for PluginQuery {
107	type Error = Error;
108
109	fn try_from(value: Query) -> Result<PluginQuery, Self::Error> {
110		let state: QueryState = value.direction.into();
111
112		let mut keys = vec![];
113		for key in value.key {
114			let json_formatted_key =
115				serde_json::to_string(&key).map_err(Error::InvalidJsonInQueryKey)?;
116			keys.push(json_formatted_key);
117		}
118
119		let mut outputs = vec![];
120		for output in value.output {
121			let json_formatted_output =
122				serde_json::to_string(&output).map_err(Error::InvalidJsonInQueryOutput)?;
123			outputs.push(json_formatted_output);
124		}
125
126		Ok(PluginQuery {
127			id: value.id as i32,
128			state: state as i32,
129			publisher_name: value.publisher,
130			plugin_name: value.plugin,
131			query_name: value.query,
132			key: keys,
133			output: outputs,
134			concern: value.concerns,
135			split: false,
136		})
137	}
138}
139
140#[derive(Debug, Deserialize, PartialEq, Clone, clap::ValueEnum)]
141#[serde(rename_all = "UPPERCASE")]
142pub enum LogLevel {
143	Off,
144	Error,
145	Warn,
146	Info,
147	Debug,
148	Trace,
149}
150impl LogLevel {
151	pub fn level_from_str(s: &str) -> Result<LogLevel, String> {
152		match s.trim().to_lowercase().as_str() {
153			"off" => Ok(LogLevel::Off),
154			"error" => Ok(LogLevel::Error),
155			"warn" => Ok(LogLevel::Warn),
156			"info" => Ok(LogLevel::Info),
157			"debug" => Ok(LogLevel::Debug),
158			"trace" => Ok(LogLevel::Trace),
159			_ => Err(format!("Invalid log level: {}", s.trim())),
160		}
161	}
162}
163
164impl Display for LogLevel {
165	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
166		match &self {
167			LogLevel::Off => write!(f, "off"),
168			LogLevel::Error => write!(f, "error"),
169			LogLevel::Warn => write!(f, "warn"),
170			LogLevel::Info => write!(f, "info"),
171			LogLevel::Debug => write!(f, "debug"),
172			LogLevel::Trace => write!(f, "trace"),
173		}
174	}
175}