1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
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(())
}
|