Add a basic sync route
This commit is contained in:
parent
5ecd691e41
commit
7f445a24e0
18
src/main.rs
18
src/main.rs
@ -1,3 +1,4 @@
|
||||
use axum::response::IntoResponse;
|
||||
use sqlx::{Connection, PgPool};
|
||||
use toggl::TogglApi;
|
||||
use worker::Worker;
|
||||
@ -22,6 +23,19 @@ enum AppError {
|
||||
IO(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> axum::http::Response<axum::body::Body> {
|
||||
let status = match &self {
|
||||
AppError::SqlxError(_) => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
AppError::TogglError(_) => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
AppError::LookBackTooLarge => axum::http::StatusCode::BAD_REQUEST,
|
||||
AppError::IO(_) => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
|
||||
(status, self.to_string()).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
struct TableSummary {
|
||||
client_ids: Vec<u64>,
|
||||
workspace_ids: Vec<u64>,
|
||||
@ -49,5 +63,7 @@ async fn main() {
|
||||
|
||||
let worker = Worker { db, toggl_api };
|
||||
|
||||
server::serve().await.expect("Failed to start server")
|
||||
server::serve(
|
||||
worker
|
||||
).await.expect("Failed to start server")
|
||||
}
|
||||
|
||||
@ -1,14 +1,22 @@
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
routing::{get, post},
|
||||
Json, Router,
|
||||
};
|
||||
use axum::{http::StatusCode, routing::{get, post}, Json, Router, Extension};
|
||||
use axum::response::IntoResponse;
|
||||
use chrono::TimeDelta;
|
||||
|
||||
use crate::AppError;
|
||||
use crate::worker::Worker;
|
||||
|
||||
pub async fn serve() -> Result<(), AppError> {
|
||||
async fn sync(Extension(worker): Extension<Worker>) -> Result<impl IntoResponse, AppError> {
|
||||
worker.update(TimeDelta::days(30)).await?;
|
||||
|
||||
Ok("Ok")
|
||||
}
|
||||
|
||||
pub async fn serve(worker: Worker) -> Result<(), AppError> {
|
||||
// build our application with a route
|
||||
let app = Router::new();
|
||||
let app = Router::new()
|
||||
.route("/health", get(|| async { "Ok" }))
|
||||
.route("/sync", post(sync))
|
||||
.layer(Extension(worker));
|
||||
|
||||
// run our app with hyper, listening globally on port 3000
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||
|
||||
@ -13,7 +13,7 @@ use support::ReqwestRateLimiter;
|
||||
mod support;
|
||||
pub mod types;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TogglApi {
|
||||
client: ClientWithMiddleware,
|
||||
pub workspace_id: u64,
|
||||
|
||||
@ -21,13 +21,14 @@ macro_rules! cast_slice_opts {
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Worker {
|
||||
pub(crate) db: PgPool,
|
||||
pub(crate) toggl_api: TogglApi,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
async fn get_ids(&mut self) -> Result<TableSummary, AppError> {
|
||||
async fn get_ids(&self) -> Result<TableSummary, AppError> {
|
||||
let client_ids = sqlx::query!("select id from tracking_clients")
|
||||
.fetch_all(&self.db)
|
||||
.await?;
|
||||
@ -52,7 +53,7 @@ impl Worker {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn fetch_within(&mut self, start: NaiveDate, end: NaiveDate) -> Result<(), AppError> {
|
||||
pub async fn fetch_within(&self, start: NaiveDate, end: NaiveDate) -> Result<(), AppError> {
|
||||
let results = self
|
||||
.toggl_api
|
||||
.search(
|
||||
@ -73,7 +74,7 @@ impl Worker {
|
||||
self.update_database(time_entries).await
|
||||
}
|
||||
|
||||
pub async fn fetch_changed_since(&mut self, look_back: TimeDelta) -> Result<(), AppError> {
|
||||
pub async fn fetch_changed_since(&self, look_back: TimeDelta) -> Result<(), AppError> {
|
||||
if look_back > TimeDelta::days(90) {
|
||||
return Err(AppError::LookBackTooLarge);
|
||||
}
|
||||
@ -81,7 +82,7 @@ impl Worker {
|
||||
self.update_time_entries(Utc::now() - look_back).await
|
||||
}
|
||||
|
||||
pub async fn update(&mut self, default_look_back: TimeDelta) -> Result<(), AppError> {
|
||||
pub async fn update(&self, default_look_back: TimeDelta) -> Result<(), AppError> {
|
||||
let result = sqlx::query!("select max(updated_at) as last_updated_at from time_entries")
|
||||
.fetch_optional(&self.db)
|
||||
.await
|
||||
@ -94,7 +95,7 @@ impl Worker {
|
||||
self.update_time_entries(fetch_since).await
|
||||
}
|
||||
|
||||
async fn update_time_entries(&mut self, fetch_since: DateTime<Utc>) -> Result<(), AppError> {
|
||||
async fn update_time_entries(&self, fetch_since: DateTime<Utc>) -> Result<(), AppError> {
|
||||
let time_entries = self
|
||||
.toggl_api
|
||||
.get_time_entries_for_user_modified_since(fetch_since)
|
||||
@ -103,7 +104,7 @@ impl Worker {
|
||||
self.update_database(time_entries).await
|
||||
}
|
||||
|
||||
async fn update_database(&mut self, time_entries: Vec<TimeEntry>) -> Result<(), AppError> {
|
||||
async fn update_database(&self, time_entries: Vec<TimeEntry>) -> Result<(), AppError> {
|
||||
let existing_ids = self.get_ids().await?;
|
||||
|
||||
let fetch_workspaces = time_entries
|
||||
@ -143,7 +144,7 @@ impl Worker {
|
||||
}
|
||||
|
||||
async fn update_time_entries_chunk(
|
||||
&mut self,
|
||||
&self,
|
||||
time_entries: &[TimeEntry],
|
||||
) -> Result<(), AppError> {
|
||||
let time_entries = Soa::from(time_entries);
|
||||
@ -186,7 +187,7 @@ impl Worker {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_workspaces(&mut self, workspace_ids: &[u64]) -> Result<(), AppError> {
|
||||
async fn update_workspaces(&self, workspace_ids: &[u64]) -> Result<(), AppError> {
|
||||
let workspaces = workspace_ids
|
||||
.iter()
|
||||
.map(|id| self.toggl_api.get_workspace(*id));
|
||||
@ -216,7 +217,7 @@ impl Worker {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_projects(&mut self, existing_ids: &TableSummary) -> Result<(), AppError> {
|
||||
async fn update_projects(&self, existing_ids: &TableSummary) -> Result<(), AppError> {
|
||||
let projects = self.toggl_api.get_projects().await?;
|
||||
|
||||
let fetch_clients = projects
|
||||
@ -273,7 +274,7 @@ impl Worker {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn update_tags(&mut self) -> Result<(), AppError> {
|
||||
pub(crate) async fn update_tags(&self) -> Result<(), AppError> {
|
||||
let tags = self.toggl_api.get_tags().await?;
|
||||
let tags: Soa<Tag> = Soa::from(tags.as_slice());
|
||||
|
||||
@ -305,7 +306,7 @@ impl Worker {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_clients(&mut self) -> Result<(), AppError> {
|
||||
async fn update_clients(&self) -> Result<(), AppError> {
|
||||
let clients = self.toggl_api.get_clients().await?;
|
||||
|
||||
let clients: Soa<TrackingClient> = Soa::from(clients.as_slice());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user