add number stops from args
This commit is contained in:
+20
-5
@@ -2,9 +2,24 @@ use std::env::args;
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
pub fn get_station_name_from_args() -> Result<String> {
|
pub struct Args {
|
||||||
args()
|
pub name: String,
|
||||||
.into_iter()
|
pub number_stops: usize,
|
||||||
.nth(1)
|
}
|
||||||
.context("getting station name from args")
|
|
||||||
|
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;
|
mod query;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
|
|
||||||
pub use args::get_station_name_from_args;
|
pub use args::Args;
|
||||||
pub use query::get_departures_for_station;
|
pub use query::get_departures_for_station;
|
||||||
pub use response::format_departures;
|
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<()> {
|
fn main() -> Result<()> {
|
||||||
let station_name = get_station_name_from_args()?;
|
let args = Args::try_get().context("parsing args")?;
|
||||||
let response = get_departures_for_station(station_name)?;
|
let response = get_departures_for_station(args).context("getting departures")?;
|
||||||
let formatted = format_departures(response);
|
let formatted = format_departures(response);
|
||||||
println!("{formatted}");
|
println!("{formatted}");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+68
-29
@@ -1,52 +1,91 @@
|
|||||||
use anyhow::Result;
|
use std::collections::HashMap;
|
||||||
use ureq::Request;
|
|
||||||
|
|
||||||
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 DEPARTURE_MONITOR: &str = "https://webapi.vvo-online.de/dm";
|
||||||
const POINT_FINDER: &str = "https://webapi.vvo-online.de/tr/pointfinder";
|
const POINT_FINDER: &str = "https://webapi.vvo-online.de/tr/pointfinder";
|
||||||
|
|
||||||
pub fn get_departures_for_station(station_name: String) -> Result<Response> {
|
pub fn get_departures_for_station(args: Args) -> Result<Response> {
|
||||||
let stopid = get_stopid_from_station_name(station_name)?;
|
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)
|
let number_stops = args.number_stops.to_string();
|
||||||
.send_string(&format!(
|
let kv_pair = get_key_value_pair_for_departure(&stopid, &number_stops);
|
||||||
"{{
|
|
||||||
\"stopid\":\"{stopid}\",
|
let json_string = create_json_request(DEPARTURE_MONITOR, kv_pair)
|
||||||
\"limit\":5
|
.context("creating JSON request")?
|
||||||
}}"
|
.into_string()
|
||||||
))?
|
.context("converting JSON reply to string")?;
|
||||||
.into_string()?;
|
|
||||||
|
|
||||||
let result = serde_json::from_str(&json_string)?;
|
let result = serde_json::from_str(&json_string)?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_stopid_from_station_name(station_name: String) -> Result<String> {
|
fn get_stopid_from_station_name(station_name: String) -> Result<String> {
|
||||||
let json_string = create_json_request(POINT_FINDER)
|
let kv_pair = get_key_value_pair_for_stopid(&station_name);
|
||||||
.send_string(&format!(
|
|
||||||
"{{
|
let json_string = create_json_request(POINT_FINDER, kv_pair)
|
||||||
\"query\":\"{station_name}\",
|
.context("creating JSON request")?
|
||||||
\"limit\":1,
|
.into_string()
|
||||||
\"regionalOnly\":\"true\",
|
.context("converting JSON reply to string")?;
|
||||||
\"stopsOnly\":\"true\"
|
|
||||||
}}"
|
|
||||||
))?
|
|
||||||
.into_string()?;
|
|
||||||
|
|
||||||
let response: PointFinderResponse = serde_json::from_str(&json_string)?;
|
let response: PointFinderResponse = serde_json::from_str(&json_string)?;
|
||||||
print!("{}", response.point.name);
|
print_station_name(&response);
|
||||||
if let Some(area) = response.point.area {
|
|
||||||
print!(", {area}");
|
|
||||||
}
|
|
||||||
println!("\n");
|
|
||||||
|
|
||||||
let result = response.point.stopid;
|
let result = response.point.stopid;
|
||||||
Ok(result)
|
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)
|
ureq::post(url)
|
||||||
.set("Content-Type", "application/json")
|
.set("Content-Type", "application/json")
|
||||||
.set("charset", "UTF-8")
|
.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 struct Point {
|
||||||
pub stopid: String,
|
pub stopid: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub area: Option<String>,
|
pub area: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(&str, &str, Option<&str>)> for Point {
|
impl From<(&str, &str, &str)> for Point {
|
||||||
fn from(value: (&str, &str, Option<&str>)) -> Self {
|
fn from(value: (&str, &str, &str)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stopid: value.0.into(),
|
stopid: value.0.into(),
|
||||||
name: value.1.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 mut iter = line.trim_start_matches("\\\"").split_terminator('|');
|
||||||
|
|
||||||
let stopid = iter.next().context("getting stopid from line")?;
|
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")?;
|
let name = iter.next().context("getting stop name from line")?;
|
||||||
Ok((stopid, name, area).into())
|
Ok((stopid, name, area).into())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user