assemblyline_models/datastore/
error.rs1use chrono::{DateTime, Utc};
2use rand::seq::IteratorRandom;
3use serde::{Serialize, Deserialize};
4use serde_with::{SerializeDisplay, DeserializeFromStr};
5use struct_metadata::Described;
6use strum::IntoEnumIterator;
7
8use crate::messages::task::{generate_conf_key, Task};
9use crate::{random_word, random_words, ElasticMeta, Readable};
10use crate::types::{ServiceName, Sha256, Text};
11
12
13#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, Described, Clone, Copy)]
14#[metadata_type(ElasticMeta)]
15pub enum Status {
16 #[strum(serialize = "FAIL_NONRECOVERABLE")]
17 FailNonrecoverable,
18 #[strum(serialize = "FAIL_RECOVERABLE")]
19 FailRecoverable,
20}
21
22#[cfg(feature = "rand")]
23impl rand::distr::Distribution<Status> for rand::distr::StandardUniform {
24 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Status {
25 if rng.random() {
26 Status::FailNonrecoverable
27 } else {
28 Status::FailRecoverable
29 }
30 }
31}
32
33impl Status {
34 pub fn is_recoverable(&self) -> bool {
35 matches!(self, Status::FailRecoverable)
36 }
37 pub fn is_nonrecoverable(&self) -> bool {
38 matches!(self, Status::FailNonrecoverable)
39 }
40}
41
42
43#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, strum::EnumIter, Described, Clone, Copy)]
44#[metadata_type(ElasticMeta)]
45pub enum ErrorTypes {
46 #[strum(serialize = "UNKNOWN")]
47 Unknown = 0,
48 #[strum(serialize = "EXCEPTION")]
49 Exception = 1,
50 #[strum(serialize = "MAX DEPTH REACHED")]
51 MaxDepthReached = 10,
52 #[strum(serialize = "MAX FILES REACHED")]
53 MaxFilesReached = 11,
54 #[strum(serialize = "MAX RETRY REACHED")]
55 MaxRetryReached = 12,
56 #[strum(serialize = "SERVICE BUSY")]
57 ServiceBusy = 20,
58 #[strum(serialize = "SERVICE DOWN")]
59 ServiceDown = 21,
60 #[strum(serialize = "TASK PRE-EMPTED")]
61 TaskPreempted = 30
62}
63
64#[cfg(feature = "rand")]
65impl rand::distr::Distribution<ErrorTypes> for rand::distr::StandardUniform {
66 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ErrorTypes {
67 match ErrorTypes::iter().choose(rng) {
68 Some(value) => value,
69 None => ErrorTypes::Unknown,
70 }
71 }
72}
73
74#[derive(Serialize, Deserialize, Described)]
76#[metadata_type(ElasticMeta)]
77#[metadata(index=true, store=true)]
78pub struct Response {
79 #[metadata(copyto="__text__")]
81 pub message: Text,
82 pub service_debug_info: Option<String>,
84 #[metadata(copyto="__text__")]
86 pub service_name: ServiceName,
87 #[metadata(copyto="__text__")]
89 pub service_tool_version: Option<String>,
90 pub service_version: String,
92 pub status: Status,
94}
95
96#[cfg(feature = "rand")]
97impl rand::distr::Distribution<Response> for rand::distr::StandardUniform {
98 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Response {
99 let word_count = rng.random_range(5..25);
100 Response {
101 message: Text(random_words(rng, word_count).join(" ")),
102 service_debug_info: None,
103 service_name: ServiceName::from_string(random_word(rng)),
104 service_tool_version: None,
105 service_version: "0.0".to_string(),
106 status: rng.random(),
107 }
108 }
109}
110
111
112#[derive(Serialize, Deserialize, Described)]
114#[metadata_type(ElasticMeta)]
115#[metadata(index=true, store=true)]
116pub struct Error {
117 #[serde(default)]
119 pub archive_ts: Option<DateTime<Utc>>,
120 #[serde(default="chrono::Utc::now")]
122 pub created: DateTime<Utc>,
123 #[metadata(store=false)]
125 pub expiry_ts: Option<DateTime<Utc>>,
126 pub response: Response,
128 #[metadata(copyto="__text__")]
130 pub sha256: Sha256,
131 #[serde(rename="type", default="default_error_type")]
133 pub error_type: ErrorTypes,
134}
135
136#[cfg(feature = "rand")]
137impl rand::distr::Distribution<Error> for rand::distr::StandardUniform {
138 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Error {
139 Error {
140 archive_ts: None,
141 created: chrono::Utc::now(),
142 expiry_ts: None,
143 response: rng.random(),
144 sha256: rng.random(),
145 error_type: rng.random(),
146 }
147 }
148}
149
150impl Error {
151 pub fn build_key(&self, service_tool_version: Option<&str>, task: Option<&Task>) -> Result<String, serde_json::Error> {
152 let key_list = [
153 self.sha256.to_string(),
154 self.response.service_name.replace('.', "_"),
155 format!("v{}", self.response.service_version.replace('.', "_")),
156 format!("c{}", generate_conf_key(service_tool_version, task, None)?),
157 format!("e{}", self.error_type as u64),
158 ];
159
160 Ok(key_list.join("."))
161 }
162
163 pub fn build_unique_key(&self, service_tool_version: Option<&str>, task: Option<&Task>) -> Result<String, serde_json::Error> {
164 Ok(self.build_key(service_tool_version, task)? + "." + &rand::random::<u64>().to_string())
165 }
166}
167
168fn default_error_type() -> ErrorTypes { ErrorTypes::Exception }
169
170impl Readable for Error {
171 fn set_from_archive(&mut self, _from_archive: bool) {}
172}