Convert to proper CLI and add SQLX prepare statements

This commit is contained in:
2024-07-28 13:59:21 +01:00
parent b62d6db866
commit d78d82f8fa
15 changed files with 378 additions and 31 deletions
+42 -20
View File
@@ -42,47 +42,69 @@ struct TableSummary {
tag_ids: Vec<u64>,
}
struct Environment {
use clap::{Parser, Subcommand};
use std::net::IpAddr;
use chrono::TimeDelta;
#[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,
}
impl Environment {
fn from_env() -> Self {
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let api_token = std::env::var("API_TOKEN").expect("API_TOKEN must be set");
let default_workspace_id = std::env::var("DEFAULT_WORKSPACE_ID")
.expect("DEFAULT_WORKSPACE_ID must be set")
.parse()
.expect("DEFAULT_WORKSPACE_ID must be a number");
#[derive(Subcommand)]
enum Commands {
Server {
#[arg(long, env = "IP", default_value = "127.0.0.1")]
ip: IpAddr,
Self {
database_url,
api_token,
default_workspace_id,
}
}
#[arg(long, env = "PORT", default_value = "3000")]
port: u16,
},
Migrate,
Sync,
}
#[tokio::main]
async fn main() {
dotenv::dotenv().expect("Failed to load .env file");
dotenvy::dotenv().expect("Failed to load .env file");
// Init tracing
tracing_subscriber::fmt::init();
let env_config = Environment::from_env();
let cli = Cli::parse();
let toggl_api = TogglApi::new(&env_config.api_token, env_config.default_workspace_id);
let mut db = PgPool::connect(&env_config.database_url).await.unwrap();
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 };
server::serve(worker).await.expect("Failed to start server")
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");
}
}
+3 -2
View File
@@ -1,3 +1,4 @@
use std::net::IpAddr;
use axum::response::IntoResponse;
use axum::{
http::StatusCode,
@@ -15,7 +16,7 @@ async fn sync(Extension(worker): Extension<Worker>) -> Result<impl IntoResponse,
Ok("Ok")
}
pub async fn serve(worker: Worker) -> Result<(), AppError> {
pub async fn serve(worker: Worker, ip: IpAddr, port: u16) -> Result<(), AppError> {
// build our application with a route
let app = Router::new()
.route("/health", get(|| async { "Ok" }))
@@ -23,7 +24,7 @@ pub async fn serve(worker: Worker) -> Result<(), AppError> {
.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?;
let listener = tokio::net::TcpListener::bind((ip, port)).await?;
axum::serve(listener, app)
.with_graceful_shutdown(async {