-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 83c57a7
Showing
13 changed files
with
471 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: [ master ] | ||
pull_request: | ||
branches: [ master ] | ||
|
||
env: | ||
CARGO_TERM_COLOR: always | ||
|
||
jobs: | ||
LinuxLatest: | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions-rs/toolchain@v1 | ||
with: | ||
profile: minimal | ||
toolchain: stable | ||
- uses: Swatinem/rust-cache@v1 | ||
|
||
- name: Build | ||
run: cargo build --verbose | ||
- name: Run tests | ||
run: cargo test --verbose | ||
|
||
WindowsLatest: | ||
|
||
runs-on: windows-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions-rs/toolchain@v1 | ||
with: | ||
profile: minimal | ||
toolchain: stable | ||
- uses: Swatinem/rust-cache@v1 | ||
|
||
- name: Build | ||
run: cargo build --verbose | ||
- name: Run tests | ||
run: cargo test --verbose | ||
|
||
MacOsLatest: | ||
|
||
runs-on: macos-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions-rs/toolchain@v1 | ||
with: | ||
profile: minimal | ||
toolchain: stable | ||
- uses: Swatinem/rust-cache@v1 | ||
|
||
- name: Build | ||
run: cargo build --verbose | ||
- name: Run tests | ||
run: cargo test --verbose |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Generated by Cargo | ||
# will have compiled files and executables | ||
debug/ | ||
target/ | ||
|
||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries | ||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html | ||
Cargo.lock | ||
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
|
||
# MSVC Windows builds of rustc generate these, which store debugging information | ||
*.pdb | ||
/.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "dbtimetable" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
reqwest = { version = "0.11", features = ["json"] } | ||
tokio = { version = "1", features = ["full"] } | ||
confy = { version = "0.3.1" } | ||
serde = { version = "1.0", features = ["derive"] } | ||
quick-xml = { version = "0.23.0", features = ["serialize"] } | ||
chrono = { version = "0.4.19" } | ||
merge = { version = "0.1.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2022 David Langhals | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
## dbtimetable | ||
A small Rust application to query the Deutsche Bahn (DB) timetable API. It can be used to display changes for a set of train stations | ||
|
||
## Setup | ||
You need to register with the DB API Marketplace to use the timeable API. | ||
[Link to API description](https://developers.deutschebahn.com/db-api-marketplace/apis/product/timetables/api/26494#/Timetables_10213/overview) | ||
You also need to obtain a Client ID and an API Key for the timeable API and set them in your local configuration. [config.rs](src/config.rs) | ||
|
||
## Configure your stations | ||
Stations are identified by their EVA numbers. The stations you want to observe have to be configured in your local configuration [config.rs](src/config.rs) | ||
A list of stations alongside their EVA numbers can be found here: [Link](https://data.deutschebahn.com/dataset/data-haltestellen.html) | ||
|
||
## License | ||
|
||
[License](LICENSE.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use crate::{ | ||
config::Config, dbapiclient::DbApiClient, timetablepresenter::TimetablePresenter, | ||
xmlparser::XmlParser, | ||
}; | ||
|
||
pub struct App { | ||
apiclient: DbApiClient, | ||
xmlparser: XmlParser, | ||
config: Config, | ||
presenter: Box<dyn TimetablePresenter>, | ||
} | ||
|
||
impl App { | ||
fn construct_changes_endpoint(eva: &String) -> String { | ||
format!("fchg/{}", eva) | ||
} | ||
|
||
pub fn new( | ||
apiclient: DbApiClient, | ||
xmlparser: XmlParser, | ||
config: Config, | ||
presenter: Box<dyn TimetablePresenter>, | ||
) -> Self { | ||
Self { | ||
apiclient, | ||
xmlparser, | ||
config, | ||
presenter, | ||
} | ||
} | ||
|
||
pub async fn run(self) { | ||
for eva in &self.config.evas { | ||
let timetable_changes = match self | ||
.apiclient | ||
.get(App::construct_changes_endpoint(eva)) | ||
.await | ||
{ | ||
Ok(s) => s, | ||
Err(_) => "".into(), | ||
}; | ||
|
||
match self.xmlparser.get_timetable(&timetable_changes) { | ||
Ok(changes) => { | ||
self.presenter.present(&changes); | ||
} | ||
Err(_) => (), | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use serde::{Serialize, Deserialize}; | ||
|
||
#[derive(Serialize, Deserialize, Clone)] | ||
pub struct Config { | ||
pub url: String, | ||
pub client_id: String, | ||
pub api_key: String, | ||
pub evas: Vec<String> | ||
} | ||
|
||
impl ::std::default::Default for Config { | ||
fn default() -> Self { | ||
Self { | ||
url: "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/".to_string(), | ||
client_id: "123456789".to_string(), | ||
api_key: "123456789".to_string(), | ||
evas: vec!("8003368".to_string()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use crate::config::Config; | ||
use reqwest::header::{HeaderMap, HeaderValue, ACCEPT}; | ||
|
||
pub struct DbApiClient { | ||
config: Config, | ||
} | ||
|
||
impl DbApiClient { | ||
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) | ||
} | ||
|
||
pub async fn get(&self, endpoint: String) -> Result<String, reqwest::Error> { | ||
let client = reqwest::Client::new(); | ||
let res = client | ||
.get(self.construct_complete_url(endpoint)) | ||
.headers(self.construct_headers()) | ||
.send() | ||
.await?; | ||
|
||
let body = match res.text().await { | ||
Ok(it) => it, | ||
Err(_err) => return Err(_err), | ||
}; | ||
|
||
Ok(body) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
mod app; | ||
mod config; | ||
mod dbapiclient; | ||
mod timetable; | ||
mod timetablepresenter; | ||
mod timetablepresenterconsole; | ||
mod xmlparser; | ||
|
||
use app::App; | ||
use config::Config; | ||
use dbapiclient::DbApiClient; | ||
use timetablepresenterconsole::TimetablePresenterConsole; | ||
use xmlparser::XmlParser; | ||
|
||
extern crate confy; | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), std::io::Error> { | ||
let config: Config = confy::load("dbtimetable")?; | ||
let apiclient = DbApiClient::new(config.clone()); | ||
let xmlparser = XmlParser::new(); | ||
let presenter = Box::new(TimetablePresenterConsole::new()); | ||
let app = App::new(apiclient, xmlparser, config.clone(), presenter); | ||
app.run().await; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use serde::Deserialize; | ||
use merge::Merge; | ||
|
||
#[derive(Deserialize, Merge)] | ||
pub struct ArrivalDeparture { | ||
pub cde: Option<String>, | ||
pub clt: Option<String>, | ||
pub cp: Option<String>, | ||
pub cpth: Option<String>, | ||
pub cs: Option<String>, | ||
pub ct: Option<String>, | ||
pub dc: Option<i64>, | ||
pub hi: Option<i32>, | ||
pub l: Option<String>, | ||
pub m: Option<Vec<Message>>, | ||
pub pde: Option<String>, | ||
pub pp: Option<String>, | ||
pub ppth: Option<String>, | ||
pub ps: Option<String>, | ||
pub pt: Option<String>, | ||
pub tra: Option<String>, | ||
pub wings: Option<String>, | ||
} | ||
|
||
#[derive(Deserialize, Merge)] | ||
pub struct TimetableStop { | ||
pub eva: Option<i64>, | ||
pub id: Option<String>, | ||
pub ar: Option<ArrivalDeparture>, | ||
pub conn: Option<String>, | ||
pub dp: Option<ArrivalDeparture>, | ||
pub hd: Option<String>, | ||
pub hpc: Option<String>, | ||
pub m: Option<Vec<Message>>, | ||
pub r: Option<String>, | ||
pub rtr: Option<String>, | ||
pub tl: Option<Triplabel>, | ||
pub f: Option<String>, | ||
} | ||
|
||
#[derive(Deserialize, Merge)] | ||
pub struct Triplabel { | ||
pub c: Option<String>, | ||
pub n: Option<String>, | ||
pub o: Option<String>, | ||
pub f: Option<String>, | ||
|
||
#[serde(rename = "false")] | ||
pub fa: Option<String>, | ||
pub t: Option<String>, | ||
} | ||
|
||
#[derive(Deserialize, Merge)] | ||
pub struct Message { | ||
pub id: Option<String>, | ||
pub t: Option<String>, | ||
pub ts: Option<String>, | ||
pub c: Option<String>, | ||
pub cat: Option<String>, | ||
pub del: Option<String>, | ||
pub dm: Option<String>, | ||
pub ec: Option<String>, | ||
pub elnk: Option<String>, | ||
pub ext: Option<String>, | ||
pub from: Option<String>, | ||
pub int: Option<String>, | ||
pub o: Option<String>, | ||
pub pr: Option<String>, | ||
pub tl: Option<Triplabel>, | ||
pub to: Option<String>, | ||
} | ||
|
||
#[derive(Deserialize, Merge)] | ||
pub struct Timetable { | ||
pub station: Option<String>, | ||
pub eva: Option<i64>, | ||
pub m: Option<Vec<Message>>, | ||
pub s: Option<Vec<TimetableStop>>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
use crate::timetable::Timetable; | ||
|
||
pub trait TimetablePresenter { | ||
fn present(&self, timetable: &Timetable); | ||
} |
Oops, something went wrong.