1use crate::{ParseError, SwiftParser, SwiftValidationError};
2use async_trait::async_trait;
3use dataflow_rs::engine::error::DataflowError;
4use dataflow_rs::engine::{
5 AsyncFunctionHandler, FunctionConfig,
6 error::Result,
7 message::{Change, Message},
8};
9use datalogic_rs::DataLogic;
10use serde_json::{Value, json};
11use std::sync::Arc;
12use tracing::{debug, instrument};
13
14pub struct Validate;
15
16#[async_trait]
17impl AsyncFunctionHandler for Validate {
18 #[instrument(skip(self, message, config, _datalogic))]
19 async fn execute(
20 &self,
21 message: &mut Message,
22 config: &FunctionConfig,
23 _datalogic: Arc<DataLogic>,
24 ) -> Result<(usize, Vec<Change>)> {
25 debug!("Starting MT message validation");
26
27 let input = match config {
29 FunctionConfig::Custom { input, .. } => input,
30 _ => {
31 return Err(DataflowError::Validation(
32 "Invalid configuration type".to_string(),
33 ));
34 }
35 };
36
37 let mt_message_field =
38 input
39 .get("mt_message")
40 .and_then(Value::as_str)
41 .ok_or_else(|| {
42 DataflowError::Validation("'mt_message' parameter is required".to_string())
43 })?;
44
45 let validation_result_field = input
46 .get("validation_result")
47 .and_then(Value::as_str)
48 .ok_or_else(|| {
49 DataflowError::Validation("'validation_result' parameter is required".to_string())
50 })?;
51
52 let mt_content = if mt_message_field == "payload" {
54 if let Some(s) = message.payload.as_str() {
56 s.to_string()
57 } else {
58 message.payload.to_string().trim_matches('"').to_string()
60 }
61 } else {
62 let field_value = message.data().get(mt_message_field).ok_or_else(|| {
64 DataflowError::Validation(format!(
65 "MT message field '{}' not found in message data",
66 mt_message_field
67 ))
68 })?;
69
70 if let Some(mt_msg) = field_value.get("mt_message").and_then(Value::as_str) {
72 mt_msg.to_string()
73 } else if let Some(s) = field_value.as_str() {
74 s.to_string()
76 } else {
77 return Err(DataflowError::Validation(format!(
78 "Field '{}' does not contain a valid MT message",
79 mt_message_field
80 )));
81 }
82 };
83
84 debug!(
85 mt_message_field = %mt_message_field,
86 validation_result_field = %validation_result_field,
87 "Validating MT message"
88 );
89
90 let validation_result = self.validate_mt_message(&mt_content)?;
92
93 message.data_mut().as_object_mut().unwrap().insert(
95 validation_result_field.to_string(),
96 validation_result.clone(),
97 );
98
99 message.metadata_mut().as_object_mut().unwrap().insert(
101 "validation".to_string(),
102 json!({
103 "validated": true,
104 "timestamp": chrono::Utc::now().to_rfc3339(),
105 }),
106 );
107
108 message.invalidate_context_cache();
109
110 Ok((
111 200,
112 vec![Change {
113 path: Arc::from(format!("data.{}", validation_result_field)),
114 old_value: Arc::new(Value::Null),
115 new_value: Arc::new(validation_result),
116 }],
117 ))
118 }
119}
120
121impl Validate {
122 fn validate_mt_message(&self, mt_content: &str) -> Result<Value> {
123 let mut errors = Vec::new();
124
125 match SwiftParser::parse_auto(mt_content) {
127 Ok(parsed_message) => {
128 let validation_errors = self.validate_network_rules(&parsed_message);
130
131 if !validation_errors.is_empty() {
132 for validation_error in validation_errors {
134 errors.push(self.format_validation_error(&validation_error));
135 }
136 }
137 }
138 Err(parse_error) => {
139 errors.push(format!("Parse error: {}", parse_error));
141
142 match &parse_error {
144 ParseError::InvalidFieldFormat(e) => {
145 errors.push(format!(
146 "Field {} - {}: Invalid value '{}', expected format: {}",
147 e.field_tag, e.component_name, e.value, e.format_spec
148 ));
149 }
150 ParseError::MissingRequiredField {
151 field_tag,
152 field_name,
153 ..
154 } => {
155 errors.push(format!(
156 "Missing required field: {} ({})",
157 field_tag, field_name
158 ));
159 }
160 ParseError::InvalidFormat { message } => {
161 errors.push(format!("Invalid message format: {}", message));
162 }
163 ParseError::ValidationFailed {
164 errors: validation_errors,
165 } => {
166 for validation_error in validation_errors {
167 errors.push(validation_error.to_string());
168 }
169 }
170 _ => {
171 }
173 }
174 }
175 }
176
177 let is_valid = errors.is_empty();
178
179 Ok(json!({
180 "valid": is_valid,
181 "errors": errors,
182 "timestamp": chrono::Utc::now().to_rfc3339(),
183 }))
184 }
185
186 fn validate_network_rules(
188 &self,
189 parsed_message: &crate::parsed_message::ParsedSwiftMessage,
190 ) -> Vec<SwiftValidationError> {
191 use crate::parsed_message::ParsedSwiftMessage;
192
193 match parsed_message {
195 ParsedSwiftMessage::MT101(msg) => msg.fields.validate_network_rules(false),
196 ParsedSwiftMessage::MT103(msg) => msg.fields.validate_network_rules(false),
197 ParsedSwiftMessage::MT104(msg) => msg.fields.validate_network_rules(false),
198 ParsedSwiftMessage::MT107(msg) => msg.fields.validate_network_rules(false),
199 ParsedSwiftMessage::MT110(msg) => msg.fields.validate_network_rules(false),
200 ParsedSwiftMessage::MT111(msg) => msg.fields.validate_network_rules(false),
201 ParsedSwiftMessage::MT112(msg) => msg.fields.validate_network_rules(false),
202 ParsedSwiftMessage::MT190(msg) => msg.fields.validate_network_rules(false),
203 ParsedSwiftMessage::MT191(msg) => msg.fields.validate_network_rules(false),
204 ParsedSwiftMessage::MT192(msg) => msg.fields.validate_network_rules(false),
205 ParsedSwiftMessage::MT196(msg) => msg.fields.validate_network_rules(false),
206 ParsedSwiftMessage::MT199(msg) => msg.fields.validate_network_rules(false),
207 ParsedSwiftMessage::MT200(msg) => msg.fields.validate_network_rules(false),
208 ParsedSwiftMessage::MT202(msg) => msg.fields.validate_network_rules(false),
209 ParsedSwiftMessage::MT204(msg) => msg.fields.validate_network_rules(false),
210 ParsedSwiftMessage::MT205(msg) => msg.fields.validate_network_rules(false),
211 ParsedSwiftMessage::MT210(msg) => msg.fields.validate_network_rules(false),
212 ParsedSwiftMessage::MT290(msg) => msg.fields.validate_network_rules(false),
213 ParsedSwiftMessage::MT291(msg) => msg.fields.validate_network_rules(false),
214 ParsedSwiftMessage::MT292(msg) => msg.fields.validate_network_rules(false),
215 ParsedSwiftMessage::MT296(msg) => msg.fields.validate_network_rules(false),
216 ParsedSwiftMessage::MT299(msg) => msg.fields.validate_network_rules(false),
217 ParsedSwiftMessage::MT900(msg) => msg.fields.validate_network_rules(false),
218 ParsedSwiftMessage::MT910(msg) => msg.fields.validate_network_rules(false),
219 ParsedSwiftMessage::MT920(msg) => msg.fields.validate_network_rules(false),
220 ParsedSwiftMessage::MT935(msg) => msg.fields.validate_network_rules(false),
221 ParsedSwiftMessage::MT940(msg) => msg.fields.validate_network_rules(false),
222 ParsedSwiftMessage::MT941(msg) => msg.fields.validate_network_rules(false),
223 ParsedSwiftMessage::MT942(msg) => msg.fields.validate_network_rules(false),
224 ParsedSwiftMessage::MT950(msg) => msg.fields.validate_network_rules(false),
225 }
226 }
227
228 fn format_validation_error(&self, error: &SwiftValidationError) -> String {
230 use crate::errors::SwiftValidationError;
231
232 match error {
233 SwiftValidationError::Format(err) => {
234 format!(
235 "[{}] Field {}: {} - Invalid value '{}' (expected: {})",
236 err.code, err.field, err.message, err.value, err.expected
237 )
238 }
239 SwiftValidationError::Content(err) => {
240 format!(
241 "[{}] Field {}: {} - Content '{}' violates requirement: {}",
242 err.code, err.field, err.message, err.content, err.requirements
243 )
244 }
245 SwiftValidationError::Relation(err) => {
246 let related = if !err.related_fields.is_empty() {
247 format!(" (related: {})", err.related_fields.join(", "))
248 } else {
249 String::new()
250 };
251 let instruction = err
252 .instruction_context
253 .as_ref()
254 .map(|ctx| format!(" [{}]", ctx))
255 .unwrap_or_default();
256 format!(
257 "[{}] Field {}: {}{}{}",
258 err.code, err.field, err.message, related, instruction
259 )
260 }
261 SwiftValidationError::Business(err) => {
262 let related = if !err.related_fields.is_empty() {
263 format!(" (related: {})", err.related_fields.join(", "))
264 } else {
265 String::new()
266 };
267 format!(
268 "[{}] Field {}: {} - Rule: {}{}",
269 err.code, err.field, err.message, err.rule_description, related
270 )
271 }
272 SwiftValidationError::General(err) => {
273 let category = err
274 .category
275 .as_ref()
276 .map(|c| format!(" [{}]", c))
277 .unwrap_or_default();
278 format!(
279 "[{}] Field {}: {} - Value '{}'{}",
280 err.code, err.field, err.message, err.value, category
281 )
282 }
283 }
284 }
285}