1use 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}