Skip to content

Commit

Permalink
formatting fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
CommanderStorm committed Jan 24, 2024
1 parent 9c1eb7c commit 4ac6ceb
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 52 deletions.
2 changes: 1 addition & 1 deletion server/feedback/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod github;
mod post_feedback;
mod proposed_edits;
mod tokens;
type BoxedError=Box<dyn Error + Send + Sync>;
type BoxedError = Box<dyn Error + Send + Sync>;

const MAX_JSON_PAYLOAD: usize = 1024 * 1024; // 1 MB

Expand Down
73 changes: 53 additions & 20 deletions server/main-api/src/calendar/fetch/connectum.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::env;
use cached::instant::Instant;
use chrono::{DateTime, Utc};
use log::{debug, error, info};
use oauth2::{AuthUrl, ClientId, ClientSecret, Scope, TokenResponse, TokenUrl};
use oauth2::basic::{BasicClient, BasicTokenResponse};
use oauth2::reqwest::async_http_client;
use oauth2::url::Url;
use oauth2::{AuthUrl, ClientId, ClientSecret, Scope, TokenResponse, TokenUrl};
use sqlx::PgPool;
use std::env;

use crate::calendar::fetch::CalendarEntryFetcher;
use crate::calendar::models::Event;
Expand All @@ -23,36 +23,59 @@ impl CalendarEntryFetcher for APIRequestor {
pool: pool.clone(),
}
}
async fn fetch(&self, id: &str, start_after: &DateTime<Utc>, end_before: &DateTime<Utc>) -> Result<super::CalendarEntries, crate::BoxedError> {
async fn fetch(
&self,
id: &str,
start_after: &DateTime<Utc>,
end_before: &DateTime<Utc>,
) -> Result<super::CalendarEntries, crate::BoxedError> {
let tumonline_id = id.replace('.', "");

let sync_start = Utc::now();
let start = Instant::now();
// Make OAuth2 secured request
let oauth_token = self.fetch_oauth_token().await?;
let bearer_token = oauth_token.access_token().secret().clone();
let url = format!("https://review.campus.tum.de/RSYSTEM/co/connectum/api/rooms/{tumonline_id}/calendars");
let url = format!(
"https://review.campus.tum.de/RSYSTEM/co/connectum/api/rooms/{tumonline_id}/calendars"
);

let events: Vec<Event> = self.client
let events: Vec<Event> = self
.client
.get(url)
.bearer_auth(bearer_token)
.send()
.await?
.json()
.await?;
info!("finished fetching for {id}: {cnt} calendar events in {elapsed:?}", cnt=events.len(), elapsed=start.elapsed());
info!(
"finished fetching for {id}: {cnt} calendar events in {elapsed:?}",
cnt = events.len(),
elapsed = start.elapsed()
);
let events = events
.into_iter()
.map(|mut e| {
e.room_code = id.into();
e
})
.collect::<Vec<Event>>();
self.store(&events, &sync_start, id).await?;
let events = events
.into_iter()
.filter(|e| *start_after <= e.start_at && *end_before >= e.end_at)
.collect();
Ok((sync_start,events))
Ok((sync_start, events))
}
}

impl APIRequestor {

async fn store(&self,events:&[Event],last_sync:&DateTime<Utc>, id:&str)->Result<(), crate::BoxedError>{
async fn store(
&self,
events: &[Event],
last_sync: &DateTime<Utc>,
id: &str,
) -> Result<(), crate::BoxedError> {
// insert into db
let mut tx = self.pool.begin().await?;
if let Err(e) = self.delete_events(id, &mut tx).await {
Expand All @@ -63,13 +86,19 @@ impl APIRequestor {
for (i, event) in events.iter().enumerate() {
// conflicts cannot occur because all values for said room were dropped
if let Err(e) = event.store(&mut tx).await {
error!(
"ignoring insert {event:?} ({i}/{total}) because {e:?}",
total = events.len()
);
debug!(
"ignoring insert {event:?} ({i}/{total}) because {e:?}",
total = events.len()
);
}
}
sqlx::query!("UPDATE de SET last_calendar_scrape_at = $1 WHERE key=$2", last_sync, id).execute(&self.pool).await?;
sqlx::query!(
"UPDATE de SET last_calendar_scrape_at = $1 WHERE key=$2",
last_sync,
id
)
.execute(&self.pool)
.await?;
tx.commit().await?;
debug!("finished inserting into the db for {id}");
Ok(())
Expand All @@ -90,15 +119,19 @@ impl APIRequestor {
AuthUrl::from_url(auth_url),
Some(TokenUrl::from_url(token_url)),
)
.exchange_client_credentials()
.add_scope(Scope::new("connectum-rooms.read".into()))
.request_async(async_http_client)
.await;
.exchange_client_credentials()
.add_scope(Scope::new("connectum-rooms.read".into()))
.request_async(async_http_client)
.await;
Ok(token?) // not directly returned for typing issues
}
async fn delete_events(&self, id: &str, tx: &mut sqlx::Transaction<'_, sqlx::Postgres>) -> Result<sqlx::postgres::PgQueryResult, sqlx::Error> {
async fn delete_events(
&self,
id: &str,
tx: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<sqlx::postgres::PgQueryResult, sqlx::Error> {
sqlx::query!(r#"DELETE FROM calendar WHERE room_code = $1"#, id)
.execute(&mut **tx)
.await
}
}
}
24 changes: 16 additions & 8 deletions server/main-api/src/calendar/fetch/db.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
use crate::calendar::fetch::CalendarEntryFetcher;
use chrono::{DateTime, Utc};
use sqlx::PgPool;
use crate::calendar::fetch::CalendarEntryFetcher;

pub(super) struct DbRequestor {
pool: PgPool,
last_calendar_scrape_at: Option<DateTime<Utc>>,
}


impl CalendarEntryFetcher for DbRequestor {
fn new(pool: &PgPool, last_calendar_scrape_at: &Option<DateTime<Utc>>) -> Self {
Self { pool: pool.clone(),last_calendar_scrape_at: *last_calendar_scrape_at }
Self {
pool: pool.clone(),
last_calendar_scrape_at: *last_calendar_scrape_at,
}
}
async fn fetch(&self, id: &str, start_after: &DateTime<Utc>, end_before: &DateTime<Utc>) -> Result<super::CalendarEntries, crate::BoxedError> {
async fn fetch(
&self,
id: &str,
start_after: &DateTime<Utc>,
end_before: &DateTime<Utc>,
) -> Result<super::CalendarEntries, crate::BoxedError> {
let events = sqlx::query_as!(crate::calendar::models::Event, r#"SELECT id,room_code,start_at,end_at,stp_title_de,stp_title_en,stp_type,entry_type AS "entry_type!:crate::calendar::models::EventType",detailed_entry_type
FROM calendar
WHERE room_code = $1 AND start_at >= $2 AND end_at <= $3"#,
id, start_after, end_before)
.fetch_all(&self.pool)
.await?;
let last_scrape=self.last_calendar_scrape_at.expect("an entry exists in the db, therefore the time of last scrape is known");
Ok((last_scrape,events))
let last_scrape = self
.last_calendar_scrape_at
.expect("an entry exists in the db, therefore the time of last scrape is known");
Ok((last_scrape, events))
}

}
}
46 changes: 33 additions & 13 deletions server/main-api/src/calendar/fetch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ use db::DbRequestor;

use crate::calendar::models::Event;

mod db;
mod connectum;
mod db;

type CalendarEntries = (DateTime<Utc>, Vec<Event>);

trait CalendarEntryFetcher {
fn new(pool: &PgPool, last_calendar_scrape_at: &Option<DateTime<Utc>>) -> Self;
async fn fetch(&self, id: &str, start_after: &DateTime<Utc>, end_before: &DateTime<Utc>) -> Result<CalendarEntries, crate::BoxedError>;
async fn fetch(
&self,
id: &str,
start_after: &DateTime<Utc>,
end_before: &DateTime<Utc>,
) -> Result<CalendarEntries, crate::BoxedError>;
}

pub struct StrategyExecutor {
Expand All @@ -28,33 +33,48 @@ pub struct StrategyExecutor {
}

impl StrategyExecutor {
pub(super) fn new(pool: &PgPool, id: &str, start_after: &DateTime<Utc>, end_before: &DateTime<Utc>) -> Self {
pub(super) fn new(
pool: &PgPool,
id: &str,
start_after: &DateTime<Utc>,
end_before: &DateTime<Utc>,
) -> Self {
Self {
pool: pool.clone(),
id: id.into(),
start_after: *start_after,
end_before: *end_before,
}
}
async fn exec<T: CalendarEntryFetcher>(&self, last_calendar_scrape_at: &Option<DateTime<Utc>>) -> Result<CalendarEntries, crate::BoxedError> {
T::new(&self.pool,last_calendar_scrape_at).fetch(&self.id, &self.start_after, &self.end_before).await
async fn exec<T: CalendarEntryFetcher>(
&self,
last_calendar_scrape_at: &Option<DateTime<Utc>>,
) -> Result<CalendarEntries, crate::BoxedError> {
T::new(&self.pool, last_calendar_scrape_at)
.fetch(&self.id, &self.start_after, &self.end_before)
.await
}

pub(super) async fn exec_with_retrying(self, last_calendar_scrape_at: &Option<DateTime<Utc>>) -> Result<CalendarEntries, HttpResponse> {
pub(super) async fn exec_with_retrying(
self,
last_calendar_scrape_at: &Option<DateTime<Utc>>,
) -> Result<CalendarEntries, HttpResponse> {
let intial = match last_calendar_scrape_at {
Some(l) => if Self::one_hour_ago() < *l {
self.exec::<APIRequestor>(last_calendar_scrape_at).await
} else {
self.exec::<DbRequestor>(last_calendar_scrape_at).await
},
Some(l) => {
if Self::one_hour_ago() < *l {
self.exec::<APIRequestor>(last_calendar_scrape_at).await
} else {
self.exec::<DbRequestor>(last_calendar_scrape_at).await
}
}
None => self.exec::<APIRequestor>(last_calendar_scrape_at).await,
};

match intial {
Ok(r) => Ok(r),
Err(e) => {
error!("could not fetch due to {e:?}");
let last_scrape=last_calendar_scrape_at.unwrap_or_default();
let last_scrape = last_calendar_scrape_at.unwrap_or_default();
if Self::three_days_ago() < last_scrape {
match self.exec::<DbRequestor>(last_calendar_scrape_at).await {
Ok(res) => Ok(res),
Expand Down Expand Up @@ -85,4 +105,4 @@ impl StrategyExecutor {
.checked_sub_days(three_days)
.expect("time travel is impossible and chronos is Y2K38-save")
}
}
}
13 changes: 8 additions & 5 deletions server/main-api/src/calendar/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use actix_web::{get, HttpResponse, web};
use actix_web::{get, web, HttpResponse};
use chrono::{DateTime, Utc};
use log::error;
use serde::Deserialize;
use sqlx::PgPool;

use crate::models::Location;

mod models;
mod fetch;

mod models;

async fn get_location(pool: &PgPool, id: &str) -> Result<Option<Location>, sqlx::Error> {
sqlx::query_as!(Location, "SELECT * FROM de WHERE key = $1", id)
Expand Down Expand Up @@ -48,8 +47,12 @@ pub async fn calendar_handler(
"https://campus.tum.de/tumonline/wbKalender.wbRessource?pResNr={id}",
id = 0
); // TODO: room.tumonline_calendar_id
let fetching_strategy = fetch::StrategyExecutor::new(&data.db, &id, &args.start_after, &args.end_before);
match fetching_strategy.exec_with_retrying(&location.last_calendar_scrape_at).await {
let fetching_strategy =
fetch::StrategyExecutor::new(&data.db, &id, &args.start_after, &args.end_before);
match fetching_strategy
.exec_with_retrying(&location.last_calendar_scrape_at)
.await
{
Ok((last_sync, events)) => HttpResponse::Ok().json(models::Events {
events,
last_sync,
Expand Down
6 changes: 2 additions & 4 deletions server/main-api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod models;
mod search;
mod setup;
mod utils;
type BoxedError=Box<dyn Error + Send + Sync>;
type BoxedError = Box<dyn Error + Send + Sync>;
const MAX_JSON_PAYLOAD: usize = 1024 * 1024; // 1 MB

#[derive(Debug)]
Expand Down Expand Up @@ -89,9 +89,7 @@ async fn main() -> Result<(), crate::BoxedError> {
.wrap(middleware::Logger::default().exclude("/api/status"))
.wrap(middleware::Compress::default())
.app_data(web::JsonConfig::default().limit(MAX_JSON_PAYLOAD))
.app_data(web::Data::new(AppData {
db: pool.clone(),
}))
.app_data(web::Data::new(AppData { db: pool.clone() }))
.service(health_status_handler)
.service(calendar::calendar_handler)
.service(web::scope("/api/preview").configure(maps::configure))
Expand Down
1 change: 0 additions & 1 deletion server/main-api/src/setup/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#[cfg(not(feature = "skip_db_setup"))]
pub(crate) mod database;

Expand Down

0 comments on commit 4ac6ceb

Please sign in to comment.