add number stops from args
This commit is contained in:
+20
-5
@@ -2,9 +2,24 @@ use std::env::args;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
pub fn get_station_name_from_args() -> Result<String> {
|
||||
args()
|
||||
.into_iter()
|
||||
.nth(1)
|
||||
.context("getting station name from args")
|
||||
pub struct Args {
|
||||
pub name: String,
|
||||
pub number_stops: usize,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn try_get() -> Result<Self> {
|
||||
let mut iter = args().into_iter().skip(1);
|
||||
let name = iter.next().context("getting station name")?;
|
||||
let number_stops = get_number_stops(iter.next()).context("getting number of stops")?;
|
||||
|
||||
Ok(Self { name, number_stops })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_number_stops(arg: Option<String>) -> Result<usize> {
|
||||
match arg {
|
||||
Some(s) => s.parse().context("parsing number"),
|
||||
None => Ok(5),
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@ mod args;
|
||||
mod query;
|
||||
pub mod response;
|
||||
|
||||
pub use args::get_station_name_from_args;
|
||||
pub use args::Args;
|
||||
pub use query::get_departures_for_station;
|
||||
pub use response::format_departures;
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use departure::{format_departures, get_departures_for_station, get_station_name_from_args};
|
||||
use departure::{format_departures, get_departures_for_station, Args};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let station_name = get_station_name_from_args()?;
|
||||
let response = get_departures_for_station(station_name)?;
|
||||
let args = Args::try_get().context("parsing args")?;
|
||||
let response = get_departures_for_station(args).context("getting departures")?;
|
||||
let formatted = format_departures(response);
|
||||
println!("{formatted}");
|
||||
Ok(())
|
||||
|
||||
+68
-29
@@ -1,52 +1,91 @@
|
||||
use anyhow::Result;
|
||||
use ureq::Request;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::response::{PointFinderResponse, Response};
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
use crate::{
|
||||
response::{PointFinderResponse, Response},
|
||||
Args,
|
||||
};
|
||||
|
||||
const DEPARTURE_MONITOR: &str = "https://webapi.vvo-online.de/dm";
|
||||
const POINT_FINDER: &str = "https://webapi.vvo-online.de/tr/pointfinder";
|
||||
|
||||
pub fn get_departures_for_station(station_name: String) -> Result<Response> {
|
||||
let stopid = get_stopid_from_station_name(station_name)?;
|
||||
pub fn get_departures_for_station(args: Args) -> Result<Response> {
|
||||
let stopid = match get_stopid_from_station_name(args.name) {
|
||||
Ok(value) => value,
|
||||
Err(e) => bail!(
|
||||
"could not resolve stop ID. Check the spelling of the stop name\nserde error: {e}"
|
||||
),
|
||||
};
|
||||
|
||||
let json_string = create_json_request(DEPARTURE_MONITOR)
|
||||
.send_string(&format!(
|
||||
"{{
|
||||
\"stopid\":\"{stopid}\",
|
||||
\"limit\":5
|
||||
}}"
|
||||
))?
|
||||
.into_string()?;
|
||||
let number_stops = args.number_stops.to_string();
|
||||
let kv_pair = get_key_value_pair_for_departure(&stopid, &number_stops);
|
||||
|
||||
let json_string = create_json_request(DEPARTURE_MONITOR, kv_pair)
|
||||
.context("creating JSON request")?
|
||||
.into_string()
|
||||
.context("converting JSON reply to string")?;
|
||||
|
||||
let result = serde_json::from_str(&json_string)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_stopid_from_station_name(station_name: String) -> Result<String> {
|
||||
let json_string = create_json_request(POINT_FINDER)
|
||||
.send_string(&format!(
|
||||
"{{
|
||||
\"query\":\"{station_name}\",
|
||||
\"limit\":1,
|
||||
\"regionalOnly\":\"true\",
|
||||
\"stopsOnly\":\"true\"
|
||||
}}"
|
||||
))?
|
||||
.into_string()?;
|
||||
let kv_pair = get_key_value_pair_for_stopid(&station_name);
|
||||
|
||||
let json_string = create_json_request(POINT_FINDER, kv_pair)
|
||||
.context("creating JSON request")?
|
||||
.into_string()
|
||||
.context("converting JSON reply to string")?;
|
||||
|
||||
let response: PointFinderResponse = serde_json::from_str(&json_string)?;
|
||||
print!("{}", response.point.name);
|
||||
if let Some(area) = response.point.area {
|
||||
print!(", {area}");
|
||||
}
|
||||
println!("\n");
|
||||
print_station_name(&response);
|
||||
|
||||
let result = response.point.stopid;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn create_json_request(url: &str) -> Request {
|
||||
fn print_station_name(response: &PointFinderResponse) {
|
||||
print!("{}", response.point.name);
|
||||
let area = &response.point.area;
|
||||
if !area.is_empty() {
|
||||
print!(", {area}");
|
||||
}
|
||||
println!("\n");
|
||||
}
|
||||
|
||||
fn create_json_request(url: &str, kv_pair: HashMap<&str, &str>) -> Result<ureq::Response> {
|
||||
ureq::post(url)
|
||||
.set("Content-Type", "application/json")
|
||||
.set("charset", "UTF-8")
|
||||
.send_string(&create_json_body(kv_pair))
|
||||
.context("sending JSON to server")
|
||||
}
|
||||
|
||||
fn create_json_body(kv_pair: HashMap<&str, &str>) -> String {
|
||||
let mut result = String::from("{");
|
||||
for (k, v) in kv_pair {
|
||||
result.push_str(&format!("\"{k}\":\"{v}\","))
|
||||
}
|
||||
result.push('}');
|
||||
result
|
||||
}
|
||||
|
||||
fn get_key_value_pair_for_departure<'a>(
|
||||
stopid: &'a str,
|
||||
number_stops: &'a str,
|
||||
) -> HashMap<&'a str, &'a str> {
|
||||
let mut result = HashMap::new();
|
||||
result.insert("stopid", stopid);
|
||||
result.insert("limit", number_stops);
|
||||
result
|
||||
}
|
||||
|
||||
fn get_key_value_pair_for_stopid(name: &str) -> HashMap<&str, &str> {
|
||||
let mut result = HashMap::new();
|
||||
result.insert("query", name);
|
||||
result.insert("limit", "1");
|
||||
result.insert("regionalOnly", "true");
|
||||
result.insert("stopsOnly", "true");
|
||||
result
|
||||
}
|
||||
|
||||
+5
-5
@@ -85,15 +85,15 @@ pub struct PointFinderResponse {
|
||||
pub struct Point {
|
||||
pub stopid: String,
|
||||
pub name: String,
|
||||
pub area: Option<String>,
|
||||
pub area: String,
|
||||
}
|
||||
|
||||
impl From<(&str, &str, Option<&str>)> for Point {
|
||||
fn from(value: (&str, &str, Option<&str>)) -> Self {
|
||||
impl From<(&str, &str, &str)> for Point {
|
||||
fn from(value: (&str, &str, &str)) -> Self {
|
||||
Self {
|
||||
stopid: value.0.into(),
|
||||
name: value.1.into(),
|
||||
area: value.2.map(|s| s.into()),
|
||||
area: value.2.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ fn extract_data_from_response(line: &str) -> Result<Point> {
|
||||
let mut iter = line.trim_start_matches("\\\"").split_terminator('|');
|
||||
|
||||
let stopid = iter.next().context("getting stopid from line")?;
|
||||
let area = iter.nth(1).context("getting area from line").ok();
|
||||
let area = iter.nth(1).context("getting area from line")?;
|
||||
let name = iter.next().context("getting stop name from line")?;
|
||||
Ok((stopid, name, area).into())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user