Skip to content

Commit

Permalink
Change presenters to formatters and output to std instead of writing …
Browse files Browse the repository at this point in the history
…to file
  • Loading branch information
mxdamien committed Mar 14, 2024
1 parent be9bb33 commit ec61b36
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 140 deletions.
24 changes: 15 additions & 9 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::{
config::Config, dbapiclient::DbApiClient, timetablepresenter::TimetablePresenter,
config::Config, dbapiclient::DbApiClient, timetableformatter::TimetableFormatter,
xmlparser::XmlParser,
};

pub struct App {
apiclient: Box<dyn DbApiClient>,
xmlparser: Box<dyn XmlParser>,
config: Config,
presenter: Box<dyn TimetablePresenter>,
formatter: Box<dyn TimetableFormatter>,
}

impl App {
Expand All @@ -19,30 +19,36 @@ impl App {
apiclient: Box<dyn DbApiClient>,
xmlparser: Box<dyn XmlParser>,
config: Config,
presenter: Box<dyn TimetablePresenter>,
formatter: Box<dyn TimetableFormatter>,
) -> Self {
Self {
apiclient,
xmlparser,
config,
presenter,
formatter,
}
}

pub async fn run(self) {
pub async fn run(self) -> Result<String, String> {
let mut ret: String = "".to_string();
for eva in &self.config.evas {
let timetable_changes = match self
let timetable = match self
.apiclient
.get(App::construct_changes_endpoint(eva))
.await
{
Ok(s) => s,
Err(_) => "".into(),
Err(e) => return Err(e.to_string()),
};

if let Ok(changes) = self.xmlparser.get_timetable(&timetable_changes) {
self.presenter.present(&changes, eva);
match self.xmlparser.get_timetable(&timetable) {
Ok(timetable) => match self.formatter.format(&timetable) {
Ok(s) => ret.push_str(&s),
Err(e) => return Err(e.to_string()),
},
Err(e) => return Err(e.to_string()),
}
}
Err("".to_string())
}
}
8 changes: 4 additions & 4 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Clone)]
pub enum PresenterType {
Console,
pub enum FormatterType {
SimpleString,
Json,
}

Expand All @@ -12,7 +12,7 @@ pub struct Config {
pub client_id: String,
pub api_key: String,
pub evas: Vec<String>,
pub presenter: PresenterType,
pub formatter: FormatterType,
}

impl ::std::default::Default for Config {
Expand All @@ -22,7 +22,7 @@ impl ::std::default::Default for Config {
client_id: "123456789".to_string(),
api_key: "123456789".to_string(),
evas: vec!["8003368".to_string()],
presenter: PresenterType::Console,
formatter: FormatterType::Json,
}
}
}
48 changes: 48 additions & 0 deletions src/dbapiclientreqwest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::{config::Config, dbapiclient::DbApiClient};

use reqwest::header::{HeaderMap, HeaderValue, ACCEPT};

pub struct DbApiClientReqwest {
config: Config,
}

impl DbApiClientReqwest {
pub fn new(config: Config) -> Self {
Self { config }
}

fn construct_headers(&self) -> HeaderMap {
let mut headers = HeaderMap::new();
headers.insert(
"DB-Api-Key",
HeaderValue::from_str(self.config.api_key.as_str()).unwrap(),
);
headers.insert(
"DB-Client-Id",
HeaderValue::from_str(self.config.client_id.as_str()).unwrap(),
);
headers.insert(ACCEPT, HeaderValue::from_static("application/xml"));
headers
}

fn construct_complete_url(&self, endpoint: String) -> String {
format!("{}{}", self.config.url, endpoint)
}
}

impl DbApiClient for DbApiClientReqwest {
fn get(&self, endpoint: String) -> Result<String, String> {
let client = reqwest::Client::new();
let res = client
.get(self.construct_complete_url(endpoint))
.headers(self.construct_headers())
.send();

let body = match res.text() {
Ok(it) => it,
Err(_err) => return Err(_err),
};

Ok(body)
}
}
30 changes: 15 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ mod config;
mod dbapiclient;
mod dbapiclientimpl;
mod timetable;
mod timetablepresenter;
mod timetablepresenterconsole;
mod timetablepresenterjson;
mod timetableformatter;
mod timetableformatterjson;
mod timetableformattersimplestring;
mod xmlparser;
mod xmlparserquickxml;

use app::App;
use config::Config;
use dbapiclientimpl::DbApiClientImpl;
use timetablepresenterconsole::TimetablePresenterConsole;
use timetablepresenterjson::TimetablePresenterJson;
use timetableformatterjson::TimetableFormatterJson;
use timetableformattersimplestring::TimetableFormatterSimpleString;
use xmlparserquickxml::XmlParserQuickXml;

extern crate confy;
Expand All @@ -28,12 +28,12 @@ fn load_config() -> Config {
}
}

fn create_presenter(
presentertype: &config::PresenterType,
) -> Box<dyn timetablepresenter::TimetablePresenter> {
match presentertype {
config::PresenterType::Console => Box::new(TimetablePresenterConsole::new()),
config::PresenterType::Json => Box::new(TimetablePresenterJson::new()),
fn create_formatter(
formattertype: &config::FormatterType,
) -> Box<dyn timetableformatter::TimetableFormatter> {
match formattertype {
config::FormatterType::SimpleString => Box::new(TimetableFormatterSimpleString::new()),
config::FormatterType::Json => Box::new(TimetableFormatterJson::new()),
}
}

Expand All @@ -50,9 +50,9 @@ async fn main() -> Result<(), std::io::Error> {
let config = load_config();
let apiclient = create_apiclient(config.clone());
let xmlparser = create_xmlparser();
let presenter = create_presenter(&config.presenter);
let app = App::new(apiclient, xmlparser, config.clone(), presenter);
app.run().await;

let formatter = create_formatter(&config.formatter);
let app = App::new(apiclient, xmlparser, config.clone(), formatter);
let str_table = app.run().await;
print!("{}", str_table.unwrap_or("dbtimetable failed".to_string()));
Ok(())
}
5 changes: 5 additions & 0 deletions src/timetableformatter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use crate::timetable::Timetable;

pub trait TimetableFormatter {
fn format(&self, timetable: &Timetable) -> Result<String, String>;
}
22 changes: 7 additions & 15 deletions src/timetablepresenterjson.rs → src/timetableformatterjson.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::timetable::{ArrivalDeparture, Timetable};
use crate::timetablepresenter::TimetablePresenter;
use crate::timetableformatter::TimetableFormatter;
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::{BufWriter, Write};

#[derive(Serialize, Deserialize)]
struct TimetableStop {
Expand All @@ -14,21 +12,22 @@ struct TimetableStop {
actual_time: String,
}

pub struct TimetablePresenterJson();
pub struct TimetableFormatterJson();

impl TimetablePresenterJson {
impl TimetableFormatterJson {
#[allow(dead_code)]
pub fn new() -> Self {
Self {}
}
}

impl TimetablePresenter for TimetablePresenterJson {
fn present(&self, timetable: &Timetable, eva: &str) {
impl TimetableFormatter for TimetableFormatterJson {
fn format(&self, timetable: &Timetable) -> Result<String, String> {
let station = get_station_name(timetable);
let stops = get_stops(timetable, &station);
let json = to_json(&stops);
write_to_file(eva, &json);

Ok(json)
}
}

Expand Down Expand Up @@ -122,10 +121,3 @@ fn to_json(stops: &Vec<TimetableStop>) -> String {
let j = serde_json::to_string(&stops);
j.unwrap_or_default()
}

fn write_to_file(eva: &str, json: &String) {
let filename = format!("{}.json", &eva);
let f = File::create(filename).expect("Unable to create file");
let mut f = BufWriter::new(f);
f.write_all(json.as_bytes()).expect("Unable to write data");
}
103 changes: 103 additions & 0 deletions src/timetableformattersimplestring.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::timetable::{ArrivalDeparture, Timetable};
use crate::timetableformatter::TimetableFormatter;
use chrono::NaiveDateTime;

pub struct TimetableFormatterSimpleString();

impl TimetableFormatterSimpleString {
#[allow(dead_code)]
pub fn new() -> Self {
Self {}
}
}

impl TimetableFormatter for TimetableFormatterSimpleString {
fn format(&self, timetable: &Timetable) -> Result<String, String> {
let mut ret: String = "".to_string();
ret.push_str(&station_name(timetable));
ret.push_str(&seperator_lines(2));
ret.push_str(&timetablestop(timetable));
ret.push_str(&seperator_lines(1));

Ok(ret)
}
}

fn timetablestop(timetable: &Timetable) -> String {
if let Some(s) = &timetable.s {
let mut ret: String = "".to_string();
for item in s.iter() {
ret.push_str(&print_departure(item))
}
ret
} else {
"Timetable is empty.\n".to_string()
}
}

fn print_departure(s: &crate::timetable::TimetableStop) -> String {
let mut ret: String = "".to_string();
if let Some(dp) = &s.dp {
if let Some(tl) = &s.tl {
ret.push_str(&train_info(tl, dp));
ret.push_str(&time_info(dp));
ret.push_str(&seperator_lines(1));
}
}
ret
}

fn time_info(dp: &ArrivalDeparture) -> String {
let mut ret: String = "".to_string();
ret.push_str(&planned_time(dp));
ret.push_str(&changed_time(dp));
ret
}

fn planned_time(dp: &ArrivalDeparture) -> String {
let pt = dp.pt.as_deref().unwrap_or("-");
if let Ok(dt) = NaiveDateTime::parse_from_str(pt, "%y%m%d%H%M") {
return format!("Planned time: {}\n", dt);
}
"".to_string()
}

fn changed_time(dp: &crate::timetable::ArrivalDeparture) -> String {
let ct: &str = dp.ct.as_deref().unwrap_or("-");
match NaiveDateTime::parse_from_str(ct, "%y%m%d%H%M") {
Ok(dt) => format!("Actual time: {}\n", dt),
Err(_) => "Actual time: No delay\n".to_string(),
}
}

fn train_info(tl: &crate::timetable::Triplabel, dp: &crate::timetable::ArrivalDeparture) -> String {
format!(
"{} {}: {}\n",
tl.c.as_ref().unwrap_or(&"".to_string()),
dp.l.as_ref().unwrap_or(&"".to_string()),
dp.ppth
.as_ref()
.unwrap_or(&"".to_string())
.split('|')
.last()
.unwrap_or("")
)
}

fn station_name(timetable: &Timetable) -> String {
format!(
"{}\n",
timetable
.station
.as_ref()
.unwrap_or(&"Station name missing\n".to_string())
)
}

fn seperator_lines(count: i16) -> String {
let mut ret: String = "".to_string();
for _n in 0..count {
ret.push_str("----------------------\n");
}
ret
}
5 changes: 0 additions & 5 deletions src/timetablepresenter.rs

This file was deleted.

Loading

0 comments on commit ec61b36

Please sign in to comment.