summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Anshul Gupta <ansg191@yahoo.com> 2022-08-15 22:21:27 -0700
committerGravatar Anshul Gupta <ansg191@yahoo.com> 2022-08-15 22:21:27 -0700
commit5805ef77fef8b9b3a2f83a71091f83651a49dd89 (patch)
treedbf3eba1fd5ea7bc34f50c4e05f1101681fd0541
parentedc5985b1744dcffb8bf1b41ce273508573589fe (diff)
downloadtouchpad-5805ef77fef8b9b3a2f83a71091f83651a49dd89.tar.gz
touchpad-5805ef77fef8b9b3a2f83a71091f83651a49dd89.tar.zst
touchpad-5805ef77fef8b9b3a2f83a71091f83651a49dd89.zip
Adds individual_event endpoint to touchpad live
Also moves Touchpad conversions into conversion.rs and into its own FromTouchpadLive & TryFromTouchpadLive traits.
-rw-r--r--rust/proto/src/lib.rs49
-rw-r--r--rust/scraper/src/main.rs3
-rw-r--r--rust/scraper/src/touchpad/conversion.rs58
-rw-r--r--rust/scraper/src/touchpad/error.rs4
-rw-r--r--rust/scraper/src/touchpad/mod.rs75
-rw-r--r--rust/scraper/src/touchpad/request_response.rs4
6 files changed, 139 insertions, 54 deletions
diff --git a/rust/proto/src/lib.rs b/rust/proto/src/lib.rs
index 1a16c15..1a8199b 100644
--- a/rust/proto/src/lib.rs
+++ b/rust/proto/src/lib.rs
@@ -1,55 +1,12 @@
-use chrono::{DateTime, TimeZone, Utc};
+use chrono::{DateTime, Utc};
use std::ops::{Deref, DerefMut};
include!("gen/mod.rs");
-impl From<&str> for touchpad::common::v1::Gender {
- fn from(s: &str) -> Self {
- match s {
- "Male" => Self::Male,
- "Female" => Self::Female,
- _ => Self::Unspecified,
- }
- }
-}
-
-impl From<&str> for touchpad::common::v1::Stroke {
- fn from(s: &str) -> Self {
- match s {
- "Fly" => Self::Fly,
- "Back" => Self::Back,
- "Breast" => Self::Breast,
- "Free" => Self::Free,
- "Medley" => Self::Medley,
- _ => Self::Unspecified,
- }
- }
-}
-
-impl From<&str> for touchpad::common::v1::EventTimeResult {
- fn from(s: &str) -> Self {
- match s {
- "DQ" => Self::Dq,
- "DNS" => Self::Dns,
- "SCR" => Self::Scr,
- _ => Self::Unspecified,
- }
- }
-}
+//region ProtoTimestamp
pub struct ProtoTimestamp(pbjson_types::Timestamp);
-impl ProtoTimestamp {
- const TOUCHPAD_DATE_FORMAT: &'static str = "%Y-%m-%d";
-
- pub fn from_touchpad(str: &str) -> Result<Self, chrono::format::ParseError> {
- let date = chrono::NaiveDate::parse_from_str(str, ProtoTimestamp::TOUCHPAD_DATE_FORMAT)?;
- let datetime = chrono::NaiveDateTime::new(date, chrono::NaiveTime::from_hms(0, 0, 0));
-
- Ok(Utc.from_utc_datetime(&datetime).into())
- }
-}
-
impl Into<pbjson_types::Timestamp> for ProtoTimestamp {
fn into(self) -> pbjson_types::Timestamp {
self.0
@@ -75,3 +32,5 @@ impl DerefMut for ProtoTimestamp {
&mut self.0
}
}
+
+//endregion
diff --git a/rust/scraper/src/main.rs b/rust/scraper/src/main.rs
index 80a2f8f..7d6a4a2 100644
--- a/rust/scraper/src/main.rs
+++ b/rust/scraper/src/main.rs
@@ -15,5 +15,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let swimmers = client.swimmers(18618).await?;
println!("{:?}", swimmers);
+ let event = client.individual_event(18618, 1031911).await?;
+ println!("{:?}", event);
+
Ok(())
} \ No newline at end of file
diff --git a/rust/scraper/src/touchpad/conversion.rs b/rust/scraper/src/touchpad/conversion.rs
new file mode 100644
index 0000000..6c7b550
--- /dev/null
+++ b/rust/scraper/src/touchpad/conversion.rs
@@ -0,0 +1,58 @@
+use chrono::{NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
+
+pub trait FromTouchpadLive<T>: Sized {
+ fn from_touchpad(value: T) -> Self;
+}
+
+pub trait TryFromTouchpadLive<T>: Sized {
+ type Error;
+
+ fn try_from_touchpad(value: T) -> Result<Self, Self::Error>;
+}
+
+impl FromTouchpadLive<&str> for proto::touchpad::common::v1::Gender {
+ fn from_touchpad(value: &str) -> Self {
+ match value {
+ "Male" => Self::Male,
+ "Female" => Self::Female,
+ _ => Self::Unspecified,
+ }
+ }
+}
+
+impl FromTouchpadLive<&str> for proto::touchpad::common::v1::Stroke {
+ fn from_touchpad(value: &str) -> Self {
+ match value {
+ "Fly" => Self::Fly,
+ "Back" => Self::Back,
+ "Breast" => Self::Breast,
+ "Free" => Self::Free,
+ "Medley" => Self::Medley,
+ _ => Self::Unspecified,
+ }
+ }
+}
+
+impl FromTouchpadLive<&str> for proto::touchpad::common::v1::EventTimeResult {
+ fn from_touchpad(value: &str) -> Self {
+ match value {
+ "DQ" => Self::Dq,
+ "DNS" => Self::Dns,
+ "SCR" => Self::Scr,
+ _ => Self::Unspecified,
+ }
+ }
+}
+
+impl TryFromTouchpadLive<&str> for proto::ProtoTimestamp {
+ type Error = chrono::format::ParseError;
+
+ fn try_from_touchpad(value: &str) -> Result<Self, Self::Error> {
+ const TOUCHPAD_DATE_FORMAT: &'static str = "%Y-%m-%d";
+
+ let date = NaiveDate::parse_from_str(value, TOUCHPAD_DATE_FORMAT)?;
+ let datetime = NaiveDateTime::new(date, NaiveTime::from_hms(0, 0, 0));
+
+ Ok(Utc.from_utc_datetime(&datetime).into())
+ }
+} \ No newline at end of file
diff --git a/rust/scraper/src/touchpad/error.rs b/rust/scraper/src/touchpad/error.rs
index 57c2eda..b9216e4 100644
--- a/rust/scraper/src/touchpad/error.rs
+++ b/rust/scraper/src/touchpad/error.rs
@@ -9,5 +9,7 @@ pub enum TouchpadLiveError {
#[error("Abort Error")]
AbortError(#[from] tokio::task::JoinError),
#[error("Integer Parse Error")]
- ParseError(#[from] std::num::ParseIntError)
+ ParseError(#[from] std::num::ParseIntError),
+ #[error("Not Found")]
+ NotFoundError,
} \ No newline at end of file
diff --git a/rust/scraper/src/touchpad/mod.rs b/rust/scraper/src/touchpad/mod.rs
index fdbd591..6d965eb 100644
--- a/rust/scraper/src/touchpad/mod.rs
+++ b/rust/scraper/src/touchpad/mod.rs
@@ -1,5 +1,6 @@
mod error;
mod request_response;
+mod conversion;
use futures::{future, TryFutureExt};
use proto::touchpad::common::v1;
@@ -9,10 +10,11 @@ use std::collections::HashMap;
pub use error::TouchpadLiveError;
use proto::ProtoTimestamp;
-use crate::touchpad::request_response::{
- EventsResponse, ParticipantResponse, TeamInfoResponse,
-};
+use crate::touchpad::request_response::{EventsResponse, EventTimeResponse, ParticipantResponse, TeamInfoResponse};
use request_response::MeetInfoResponse;
+use crate::touchpad::conversion::TryFromTouchpadLive;
+
+use self::conversion::FromTouchpadLive;
const BASE_URL: &'static str = "https://www.touchpadlive.com/rest/touchpadlive";
@@ -57,8 +59,8 @@ impl TouchpadLiveClient {
Ok(v1::SwimMeet {
id,
meet_name: resp.meet_name,
- start: Some(ProtoTimestamp::from_touchpad(&resp.start_date)?.into()),
- end: Some(ProtoTimestamp::from_touchpad(&resp.end_date)?.into()),
+ start: Some(ProtoTimestamp::try_from_touchpad(&resp.start_date)?.into()),
+ end: Some(ProtoTimestamp::try_from_touchpad(&resp.end_date)?.into()),
teams: teams
.into_iter()
.map(|t| v1::Team {
@@ -79,10 +81,11 @@ impl TouchpadLiveClient {
age_hi: ev.age_hi as u32,
age_lo: ev.age_lo as u32,
distance: ev.distance,
+ gender: v1::Gender::from_touchpad (ev.stroke.as_str()) as i32,
event: None,
event_num: ev.event_number.parse()?,
meet_id: id,
- stroke: v1::Stroke::from(ev.stroke.as_str()) as i32,
+ stroke: v1::Stroke::from_touchpad(ev.stroke.as_str()) as i32,
}))
.collect()
}
@@ -113,6 +116,23 @@ impl TouchpadLiveClient {
Ok(process_swimmers(swimmers, &swimmer_map, events))
}
+
+ pub async fn individual_event(&self, meet_id: u32, ev_id: u32) -> Result<v1::Event, TouchpadLiveError> {
+ let (events, times) = {
+ let events = get_events(self.client.clone(), meet_id);
+
+ let event = get_event(self.client.clone(), "individual", meet_id, ev_id);
+
+ future::try_join(events, event)
+ }.await?;
+
+ let event = events
+ .into_iter()
+ .find(|ev| ev.id == ev_id)
+ .ok_or(TouchpadLiveError::NotFoundError)?;
+
+ create_individual_event_proto(meet_id, event, times)
+ }
}
async fn get_events(client: Client, id: u32) -> Result<Vec<EventsResponse>, TouchpadLiveError> {
@@ -124,6 +144,15 @@ async fn get_events(client: Client, id: u32) -> Result<Vec<EventsResponse>, Touc
.await?)
}
+async fn get_event(client: Client, tp: &str, meet_id: u32, ev_id: u32) -> Result<Vec<EventTimeResponse>, TouchpadLiveError> {
+ Ok(client
+ .get(format!("{}/meets/{}/{}/{}", BASE_URL, meet_id, tp, ev_id))
+ .send()
+ .await?
+ .json()
+ .await?)
+}
+
fn events_to_map<I: IntoIterator<Item=EventsResponse>>(events: I) -> HashMap<u32, EventsResponse> {
events.into_iter().map(|ev| (ev.id, ev)).collect()
}
@@ -146,7 +175,7 @@ fn process_swimmers(
for event in swimmer_events.unwrap() {
let ev_info_result = event_map.get(event);
if let Some(ev_info) = ev_info_result {
- gender = ev_info.gender.as_str().into();
+ gender = v1::Gender::from_touchpad(ev_info.gender.as_str());
if gender != v1::Gender::Unspecified {
break;
}
@@ -166,3 +195,35 @@ fn process_swimmers(
proto_swimmers
}
+
+fn create_individual_event_proto(
+ meet_id: u32,
+ event: EventsResponse,
+ times: Vec<EventTimeResponse>,
+) -> Result<v1::Event, TouchpadLiveError> {
+ let ev_id = event.id;
+
+ let proto_times = times
+ .into_iter()
+ .filter_map(|t| Some(v1::individual_event::IndividualEventTime {
+ swimmer_id: t.swimmer_id?,
+ time: Some(t.into_proto(ev_id)),
+ }))
+ .collect();
+
+ Ok(v1::Event {
+ age_hi: event.age_hi as u32,
+ age_lo: event.age_lo as u32,
+ distance: event.distance,
+ event_num: event.event_number.parse()?,
+ gender: v1::Gender::from_touchpad(event.gender.as_str()) as i32,
+ id: ev_id,
+ meet_id,
+ stroke: v1::Stroke::from_touchpad(event.stroke.as_str()) as i32,
+ event: Some(v1::event::Event::Individual(
+ v1::IndividualEvent {
+ times: proto_times,
+ }
+ )),
+ })
+}
diff --git a/rust/scraper/src/touchpad/request_response.rs b/rust/scraper/src/touchpad/request_response.rs
index 67b8a0b..cafdd60 100644
--- a/rust/scraper/src/touchpad/request_response.rs
+++ b/rust/scraper/src/touchpad/request_response.rs
@@ -1,5 +1,7 @@
use serde::Deserialize;
+use super::conversion::FromTouchpadLive;
+
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MeetInfoResponse {
@@ -92,7 +94,7 @@ impl EventTimeResponse {
};
let result = {
- let result = proto::touchpad::common::v1::EventTimeResult::from(
+ let result = proto::touchpad::common::v1::EventTimeResult::from_touchpad(
self.final_formatted_time.as_str(),
);