toggl-bridge/src/main.rs
2024-07-29 08:13:53 +01:00

114 lines
2.7 KiB
Rust

use axum::response::IntoResponse;
use sqlx::{Connection, PgPool};
use toggl::TogglApi;
use worker::Worker;
mod server;
mod toggl;
mod worker;
#[derive(Debug, thiserror::Error)]
enum AppError {
#[error("Database error: {0}")]
SqlxError(#[from] sqlx::Error),
#[error("Toggl error: {0}")]
TogglError(#[from] toggl::TogglError),
#[error("User modified since time delta is too large. Max allowed is 90 days.")]
LookBackTooLarge,
#[error("IO error: {0}")]
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>,
project_ids: Vec<u64>,
tag_ids: Vec<u64>,
}
use chrono::TimeDelta;
use clap::{Parser, Subcommand};
use std::net::IpAddr;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, env = "DATABASE_URL")]
database_url: String,
#[arg(long, env = "API_TOKEN")]
api_token: String,
#[arg(long, env = "DEFAULT_WORKSPACE_ID")]
default_workspace_id: u64,
}
#[derive(Subcommand)]
enum Commands {
Server {
#[arg(long, env = "IP", default_value = "127.0.0.1")]
ip: IpAddr,
#[arg(long, env = "PORT", default_value = "3000")]
port: u16,
},
Migrate,
Sync,
}
#[tokio::main]
async fn main() {
dotenvy::dotenv().expect("Failed to load .env file");
// Init tracing
tracing_subscriber::fmt::init();
let cli = Cli::parse();
let toggl_api = TogglApi::new(&cli.api_token, cli.default_workspace_id);
let mut db = PgPool::connect(&cli.database_url).await.unwrap();
sqlx::migrate!("./migrations")
.run(&db)
.await
.expect("Failed to run migrations");
// Return early if we are just migrating
if let Commands::Migrate = cli.command {
return;
}
let worker = Worker { db, toggl_api };
if let Commands::Server { ip, port } = cli.command {
server::serve(worker, ip, port)
.await
.expect("Failed to start server");
} else {
worker
.update(TimeDelta::days(30))
.await
.expect("Failed to update worker");
}
}