use serde::{Deserialize, Serialize};
use serde_json;
use clap::Parser;
use jfsm::{Cli, JsonError, Outputer, JsonOutputer, raw::RawMetadata, time::TimeMetadata, perms::PermsMetadata, fpdir::FpDirMetadata, request::Request, ErrorMessage};
#[derive(Serialize, Deserialize, Debug)]
struct ResponseStruct {
#[serde(skip_serializing_if = "Option::is_none")]
path: Option<FpDirMetadata>,
raw: RawMetadata,
#[serde(skip_serializing_if = "Option::is_none")]
perms: Option<PermsMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
time: Option<TimeMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
ts: Option<u128>,
}
#[derive(Serialize, Deserialize, Debug)]
struct OutputJsonMessage {
request: Request,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
data: Option<OutputData>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum OutputData {
Success { response: ResponseStruct },
Error { error: ErrorMessage },
}
fn main() {
let cli = Cli::parse();
let request = cli.build_request();
match compute_output_message(&cli, &request) {
Ok(message) => {
let json_outputer = JsonOutputer;
let json_string = serde_json::to_string_pretty(&message).unwrap_or_else(|_| {
serde_json::to_string(&message).unwrap_or_default()
});
let output = json_outputer.output(&json_string);
println!("{}", output);
}
Err(e) => {
let error_code = if e.message == "PATH-NOT-EXIST" {
6
} else if e.message == "PERMISSION-ERROR" {
77
} else if e.message == "PARSING-ERROR" {
65
} else {
1
};
let error_message = ErrorMessage {
code: error_code,
message: e.message.clone(),
};
let output = OutputJsonMessage {
request: request.clone(),
data: Some(OutputData::Error { error: error_message }),
};
let json_outputer = JsonOutputer;
let json_string = serde_json::to_string_pretty(&output).unwrap_or_else(|_| {
serde_json::to_string(&output).unwrap_or_default()
});
let output_str = json_outputer.output(&json_string);
println!("{}", output_str);
std::process::exit(error_code);
}
}
}
fn compute_output_message(cli: &Cli, request: &Request) -> Result<OutputJsonMessage, JsonError> {
let raw_metadata = RawMetadata::from_path(&cli.filepath)?;
let mut response = ResponseStruct {
path: None,
raw: raw_metadata,
perms: None,
time: None,
ts: None,
};
if cli.all || cli.path {
let fpdir_metadata = FpDirMetadata::from_raw(&response.raw);
response.path = Some(fpdir_metadata);
}
if cli.all || cli.perms {
let perms_metadata = PermsMetadata::from_raw(&response.raw);
response.perms = Some(perms_metadata);
}
if cli.all || cli.time {
let time_metadata = TimeMetadata::from_raw(&response.raw);
response.time = Some(time_metadata);
}
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
.as_nanos();
response.ts = Some(timestamp);
let output = OutputJsonMessage {
request: request.clone(),
data: Some(OutputData::Success { response }),
};
Ok(output)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::NamedTempFile;
use std::io::Write;
#[test]
fn test_output_message() {
let mut file = NamedTempFile::new().expect("Failed to create temp file");
writeln!(file, "test content").expect("Failed to write to temp file");
let filepath = file.path().to_str().expect("Failed to convert path to string");
let cli = Cli {
filepath: filepath.to_string(),
all: false,
path: false,
perms: false,
time: false,
id: None,
};
let request = cli.build_request();
let message = compute_output_message(&cli, &request).expect("Failed to compute output message");
let json_outputer = JsonOutputer;
let json_string = serde_json::to_string_pretty(&message).unwrap_or_else(|_| {
serde_json::to_string(&message).unwrap_or_default()
});
let output = json_outputer.output(&json_string);
let parsed: serde_json::Value = serde_json::from_str(&output).expect("Failed to parse JSON");
assert!(parsed.get("request").is_some());
assert!(parsed.get("response").is_some());
let response_obj = parsed.get("response").expect("Response field missing");
let raw_obj = response_obj.get("raw").expect("Raw field missing");
let pathname = raw_obj.get("pathname").expect("Pathname field missing");
assert!(!pathname.as_str().unwrap().is_empty());
let ts = response_obj.get("ts").expect("Ts field missing");
assert!(ts.is_number());
}
}