use std::path::Path;
use super::MAX_FILE_SIZE;
use mx20022_model::generated::{
camt::camt_053_001_11 as camt053,
pacs::{pacs_008_001_13 as pacs008, pacs_009_001_10 as pacs009},
};
use mx20022_translate::mappings::{
camt053_to_mt940::camt053_to_mt940, mt103_to_pacs008::mt103_to_pacs008,
mt202_to_pacs009::mt202_to_pacs009, mt940_to_camt053::mt940_to_camt053,
pacs008_to_mt103::pacs008_to_mt103, pacs009_to_mt202::pacs009_to_mt202,
};
use mx20022_translate::mappings::{TranslationError, TranslationWarnings};
use mx20022_translate::mt::{
fields::mt103::parse_mt103, fields::mt202::parse_mt202, fields::mt940::parse_mt940,
parser::parse,
};
#[derive(Debug)]
pub enum TranslateError {
Io(std::io::Error),
Translation(TranslationError),
Xml(mx20022_parse::ParseError),
FileTooLarge { size: u64, max: u64 },
UnknownTarget(String),
}
impl std::fmt::Display for TranslateError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TranslateError::Io(e) => write!(f, "I/O error: {e}"),
TranslateError::Translation(e) => write!(f, "translation error: {e}"),
TranslateError::Xml(e) => write!(f, "XML error: {e}"),
TranslateError::FileTooLarge { size, max } => {
write!(
f,
"file is too large ({size} bytes); maximum allowed is {max} bytes"
)
}
TranslateError::UnknownTarget(t) => write!(
f,
"unknown target format '{t}' — valid values: pacs008, mt103, pacs009, mt202, camt053, mt940"
),
}
}
}
impl std::error::Error for TranslateError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
TranslateError::Io(e) => Some(e),
TranslateError::Translation(e) => Some(e),
TranslateError::Xml(e) => Some(e),
TranslateError::FileTooLarge { .. } | TranslateError::UnknownTarget(_) => None,
}
}
}
impl From<std::io::Error> for TranslateError {
fn from(e: std::io::Error) -> Self {
TranslateError::Io(e)
}
}
impl From<TranslationError> for TranslateError {
fn from(e: TranslationError) -> Self {
TranslateError::Translation(e)
}
}
impl From<mx20022_parse::ParseError> for TranslateError {
fn from(e: mx20022_parse::ParseError) -> Self {
TranslateError::Xml(e)
}
}
fn print_warnings(warnings: &TranslationWarnings) {
for w in &warnings.warnings {
eprintln!("warning [{}]: {}", w.field, w.message);
}
}
fn derive_msg_id(file: &Path) -> String {
file.file_stem()
.and_then(|s| s.to_str())
.map_or_else(|| "MSG001".to_owned(), str::to_uppercase)
}
pub fn run(
file: &Path,
to: &str,
output: Option<&Path>,
msg_id: Option<&str>,
creation_time: Option<&str>,
) -> Result<(), TranslateError> {
let meta = std::fs::metadata(file)?;
if meta.len() > MAX_FILE_SIZE {
return Err(TranslateError::FileTooLarge {
size: meta.len(),
max: MAX_FILE_SIZE,
});
}
let input = std::fs::read_to_string(file)?;
let effective_msg_id = msg_id.map_or_else(|| derive_msg_id(file), str::to_owned);
let effective_ts = creation_time.unwrap_or("2000-01-01T00:00:00").to_owned();
let output_text = match to {
"pacs008" => {
let msg = parse(&input).map_err(TranslationError::MtParse)?;
let mt103 = parse_mt103(&msg.block4).map_err(TranslationError::MtParse)?;
let result = mt103_to_pacs008(&mt103, &effective_msg_id, &effective_ts)?;
print_warnings(&result.warnings);
mx20022_parse::ser::to_string_with_declaration(&result.message)?
}
"pacs009" => {
let msg = parse(&input).map_err(TranslationError::MtParse)?;
let mt202 = parse_mt202(&msg.block4).map_err(TranslationError::MtParse)?;
let result = mt202_to_pacs009(&mt202, &effective_msg_id, &effective_ts)?;
print_warnings(&result.warnings);
mx20022_parse::ser::to_string_with_declaration(&result.message)?
}
"camt053" => {
let msg = parse(&input).map_err(TranslationError::MtParse)?;
let mt940 = parse_mt940(&msg.block4).map_err(TranslationError::MtParse)?;
let result = mt940_to_camt053(&mt940, &effective_msg_id, &effective_ts)?;
print_warnings(&result.warnings);
mx20022_parse::ser::to_string_with_declaration(&result.message)?
}
"mt103" => {
let doc: pacs008::Document = mx20022_parse::de::from_str(&input)?;
let result = pacs008_to_mt103(&doc)?;
print_warnings(&result.warnings);
result.message
}
"mt202" => {
let doc: pacs009::Document = mx20022_parse::de::from_str(&input)?;
let result = pacs009_to_mt202(&doc)?;
print_warnings(&result.warnings);
result.message
}
"mt940" => {
let doc: camt053::Document = mx20022_parse::de::from_str(&input)?;
let result = camt053_to_mt940(&doc)?;
print_warnings(&result.warnings);
result.message
}
other => return Err(TranslateError::UnknownTarget(other.to_owned())),
};
match output {
Some(path) => std::fs::write(path, &output_text)?,
None => print!("{output_text}"),
}
Ok(())
}