mod protos; mod fancy; use protos::protos::gtfs_realtime::FeedMessage; use protobuf::Message; use clap::Parser; // use anyhow::Context; use miette::{WrapErr, IntoDiagnostic, miette}; use reqwest::header::{HeaderValue, CONTENT_TYPE}; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { /// uri of the GTFS RT feed to fetch & display url: String, /// emit the feed as json #[arg(long)] json: bool, #[arg(long="ignore-nonfatal", short='i')] ignore_nonfatal: bool } #[tokio::main] async fn main() -> miette::Result<()> { let args = Args::parse(); let resp = reqwest::get(&args.url) .await.into_diagnostic().wrap_err("Request failed")? .error_for_status().into_diagnostic()?; if !args.ignore_nonfatal { let ct = HeaderValue::from_static("application/octet-stream"); match resp.headers().get(CONTENT_TYPE) { Some(content_type) if ct == content_type => (), Some(other_type) => Err(miette!("should be {:?}", ct)) .wrap_err(format!("Bad Content-Type {:?}", other_type))?, None => Err(miette!("Content-Type header is missing"))? } } let resp = resp .bytes().await.into_diagnostic()?; let proto = FeedMessage::parse_from_bytes(&resp[..]) .into_diagnostic() .wrap_err("Could not parse protobuf format")?; match args.json { true => println!("{}", protobuf_json_mapping::print_to_string(&proto).into_diagnostic()?), false => println!("{}", fancy::print_to_string_fancy(&proto)) } Ok(()) }