1use std::io::Read;
2
3use json_comments::StripComments;
4
5pub fn strip_comments_from_json_str(json_str: &String) -> std::io::Result<String> {
10 let mut content_without_comments = String::new();
11 StripComments::new(json_str.as_bytes()).read_to_string(&mut content_without_comments)?;
12 Ok(content_without_comments)
13}
14
15pub fn strip_comments_from_json_reader(reader: impl Read) -> impl Read {
17 StripComments::new(reader)
18}
19
20#[derive(thiserror::Error, Debug)]
23pub enum ValidationError {
24 #[error("config.json semantic issue: {error_message}")]
25 ConfigSemanticsError { error_message: String },
26 #[error("genesis.json semantic issue: {error_message}")]
27 GenesisSemanticsError { error_message: String },
28 #[error("config.json file issue: {error_message}")]
29 ConfigFileError { error_message: String },
30 #[error("genesis.json file issue: {error_message}")]
31 GenesisFileError { error_message: String },
32 #[error("node_key.json file issue: {error_message}")]
33 NodeKeyFileError { error_message: String },
34 #[error("validator_key.json file issue: {error_message}")]
35 ValidatorKeyFileError { error_message: String },
36 #[error("cross config files semantic issue: {error_message}")]
37 CrossFileSematicError { error_message: String },
38}
39
40pub struct ValidationErrors(Vec<ValidationError>);
42
43impl ValidationErrors {
44 pub fn new() -> Self {
45 ValidationErrors(Vec::new())
46 }
47
48 pub fn is_empty(&self) -> bool {
49 self.0.is_empty()
50 }
51
52 pub fn push_errors(&mut self, error: ValidationError) {
53 self.0.push(error)
54 }
55
56 pub fn push_config_semantics_error(&mut self, error_message: String) {
57 self.0.push(ValidationError::ConfigSemanticsError { error_message: error_message })
58 }
59
60 pub fn push_config_file_error(&mut self, error_message: String) {
61 self.0.push(ValidationError::ConfigFileError { error_message: error_message })
62 }
63
64 pub fn push_genesis_semantics_error(&mut self, error_message: String) {
65 self.0.push(ValidationError::GenesisSemanticsError { error_message: error_message })
66 }
67
68 pub fn push_genesis_file_error(&mut self, error_message: String) {
69 self.0.push(ValidationError::GenesisFileError { error_message: error_message })
70 }
71
72 pub fn push_node_key_file_error(&mut self, error_message: String) {
73 self.0.push(ValidationError::NodeKeyFileError { error_message: error_message })
74 }
75
76 pub fn push_validator_key_file_error(&mut self, error_message: String) {
77 self.0.push(ValidationError::ValidatorKeyFileError { error_message: error_message })
78 }
79
80 pub fn push_cross_file_semantics_error(&mut self, error_message: String) {
81 self.0.push(ValidationError::CrossFileSematicError { error_message: error_message })
82 }
83
84 fn generate_final_error_message(&self) -> Option<String> {
86 if self.0.is_empty() {
87 None
88 } else {
89 let mut final_error_message = String::new();
90 for error in &self.0 {
91 final_error_message += "\n";
92
93 match error {
94 ValidationError::ConfigSemanticsError { error_message }
95 | ValidationError::GenesisSemanticsError { error_message } => {
96 final_error_message += error_message
99 }
100 _ => final_error_message += &error.to_string(),
101 };
102 }
103 Some(final_error_message)
104 }
105 }
106
107 pub fn generate_error_message_per_type(&self) -> Option<String> {
110 if self.0.is_empty() {
111 None
112 } else {
113 let mut final_error_message = String::new();
114 for error in &self.0 {
115 final_error_message += "\n";
116 final_error_message += &error.to_string();
117 }
118 final_error_message += "\n";
119 Some(final_error_message)
120 }
121 }
122
123 pub fn return_ok_or_error(&self) -> anyhow::Result<()> {
126 if self.0.is_empty() {
127 tracing::info!(target: "config", "All validations have passed!");
128 Ok(())
129 } else {
130 Err(anyhow::Error::msg(format!(
131 "\nThe following config checks failed:{}\nPlease fix the config json files and validate again!",
132 self.generate_final_error_message().unwrap()
133 )))
134 }
135 }
136}