Restructure server around Server struct
This commit is contained in:
parent
45abda2b6d
commit
9bdfc79c8b
5 changed files with 92 additions and 95 deletions
|
|
@ -2,14 +2,12 @@ mod args;
|
|||
mod config;
|
||||
mod server;
|
||||
mod somehow;
|
||||
mod state;
|
||||
mod util;
|
||||
|
||||
use std::{io, path::PathBuf, process};
|
||||
|
||||
use clap::Parser;
|
||||
use directories::ProjectDirs;
|
||||
use state::AppState;
|
||||
use tokio::{select, signal::unix::SignalKind};
|
||||
use tracing::{debug, error, info, Level};
|
||||
use tracing_subscriber::{
|
||||
|
|
@ -19,6 +17,7 @@ use tracing_subscriber::{
|
|||
use crate::{
|
||||
args::{Args, NAME, VERSION},
|
||||
config::Config,
|
||||
server::Server,
|
||||
};
|
||||
|
||||
fn set_up_logging(verbose: u8) {
|
||||
|
|
@ -99,12 +98,12 @@ async fn run() -> somehow::Result<()> {
|
|||
info!("You are running {NAME} {VERSION}");
|
||||
|
||||
let config = load_config(args.config)?;
|
||||
let state = AppState::new(config, &args.db, &args.repo).await?;
|
||||
let server = Server::new(config, &args.db, &args.repo).await?;
|
||||
|
||||
info!("Startup complete, running");
|
||||
select! {
|
||||
_ = wait_for_signal() => {}
|
||||
_ = server::run(state.clone()) => {}
|
||||
_ = server.run() => {}
|
||||
}
|
||||
|
||||
select! {
|
||||
|
|
@ -118,7 +117,7 @@ async fn run() -> somehow::Result<()> {
|
|||
// In order to fix this, I could maybe register a bare signal handler
|
||||
// (instead of using tokio streams) that just calls process::exit(1) and
|
||||
// nothing else?
|
||||
_ = state.shut_down() => {}
|
||||
_ = server.shut_down() => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,13 +1,87 @@
|
|||
mod recurring;
|
||||
mod web;
|
||||
|
||||
use std::{path::Path, sync::Arc, time::Duration};
|
||||
|
||||
use axum::extract::FromRef;
|
||||
use gix::ThreadSafeRepository;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous},
|
||||
SqlitePool,
|
||||
};
|
||||
use tokio::select;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::{somehow, state::AppState};
|
||||
use crate::{config::Config, somehow};
|
||||
|
||||
pub async fn run(state: AppState) -> somehow::Result<()> {
|
||||
async fn open_db(db_path: &Path) -> sqlx::Result<SqlitePool> {
|
||||
let options = SqliteConnectOptions::new()
|
||||
// https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
.journal_mode(SqliteJournalMode::Wal)
|
||||
// https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
// NORMAL recommended when using WAL, can't cause corruption
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
// https://www.sqlite.org/pragma.html#pragma_foreign_keys
|
||||
.foreign_keys(true)
|
||||
// https://www.sqlite.org/pragma.html#pragma_trusted_schema
|
||||
// The docs recommend always turning this off
|
||||
.pragma("trusted_schema", "false")
|
||||
.filename(db_path)
|
||||
.create_if_missing(true)
|
||||
// https://www.sqlite.org/lang_analyze.html#recommended_usage_pattern
|
||||
// https://www.sqlite.org/pragma.html#pragma_analysis_limit
|
||||
// https://www.sqlite.org/pragma.html#pragma_optimize
|
||||
.optimize_on_close(true, Some(1000));
|
||||
|
||||
info!(path = %db_path.display(), "Opening db");
|
||||
let pool = SqlitePoolOptions::new()
|
||||
// Regularly optimize the db as recommended by the sqlite docs
|
||||
// https://www.sqlite.org/lang_analyze.html#recommended_usage_pattern
|
||||
// https://github.com/launchbadge/sqlx/issues/2111#issuecomment-1254394698
|
||||
.max_lifetime(Some(Duration::from_secs(60 * 60 * 24)))
|
||||
.connect_with(options)
|
||||
.await?;
|
||||
|
||||
debug!("Applying outstanding db migrations");
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
fn open_repo(repo_path: &Path) -> somehow::Result<ThreadSafeRepository> {
|
||||
info!(path = %repo_path.display(), "Opening repo");
|
||||
Ok(ThreadSafeRepository::open(repo_path)?)
|
||||
}
|
||||
|
||||
#[derive(Clone, FromRef)]
|
||||
pub struct Server {
|
||||
pub config: &'static Config,
|
||||
pub db: SqlitePool,
|
||||
pub repo: Arc<ThreadSafeRepository>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub async fn new(
|
||||
config: &'static Config,
|
||||
db_path: &Path,
|
||||
repo_path: &Path,
|
||||
) -> somehow::Result<Self> {
|
||||
Ok(Self {
|
||||
config,
|
||||
db: open_db(db_path).await?,
|
||||
repo: Arc::new(open_repo(repo_path)?),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn run(&self) -> somehow::Result<()> {
|
||||
select! {
|
||||
e = web::run(state.clone()) => e,
|
||||
() = recurring::run(state.clone()) => Ok(()),
|
||||
e = web::run(self.clone()) => e,
|
||||
() = recurring::run(self.clone()) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn shut_down(self) {
|
||||
info!("Closing db");
|
||||
self.db.close().await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ mod repo;
|
|||
|
||||
use tracing::{debug_span, error, Instrument};
|
||||
|
||||
use crate::state::AppState;
|
||||
use super::Server;
|
||||
|
||||
async fn recurring_task(state: &AppState) {
|
||||
async fn recurring_task(state: &Server) {
|
||||
async {
|
||||
if let Err(e) = repo::update(&state.db, state.repo.clone()).await {
|
||||
error!("Error updating repo:\n{e:?}");
|
||||
|
|
@ -28,7 +28,7 @@ async fn recurring_task(state: &AppState) {
|
|||
.await;
|
||||
}
|
||||
|
||||
pub async fn run(state: AppState) {
|
||||
pub async fn run(state: Server) {
|
||||
loop {
|
||||
recurring_task(&state).await;
|
||||
tokio::time::sleep(state.config.repo.update_delay).await;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ mod queue;
|
|||
mod queue_id;
|
||||
mod r#static;
|
||||
|
||||
use axum::{routing::get, Router, Server};
|
||||
use axum::{routing::get, Router};
|
||||
|
||||
use crate::{config::Config, somehow, state::AppState};
|
||||
use crate::{config::Config, somehow};
|
||||
|
||||
use super::Server;
|
||||
|
||||
pub enum Tab {
|
||||
Index,
|
||||
|
|
@ -37,7 +39,7 @@ impl Base {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn run(state: AppState) -> somehow::Result<()> {
|
||||
pub async fn run(state: Server) -> somehow::Result<()> {
|
||||
// TODO Add text body to body-less status codes
|
||||
|
||||
let app = Router::new()
|
||||
|
|
@ -50,7 +52,7 @@ pub async fn run(state: AppState) -> somehow::Result<()> {
|
|||
.fallback(get(r#static::static_handler))
|
||||
.with_state(state.clone());
|
||||
|
||||
Server::bind(&"0.0.0.0:8000".parse().unwrap())
|
||||
axum::Server::bind(&"0.0.0.0:8000".parse().unwrap())
|
||||
.serve(app.into_make_service())
|
||||
.await?;
|
||||
|
||||
|
|
|
|||
78
src/state.rs
78
src/state.rs
|
|
@ -1,78 +0,0 @@
|
|||
//! Globally accessible application state.
|
||||
|
||||
use std::{path::Path, sync::Arc, time::Duration};
|
||||
|
||||
use axum::extract::FromRef;
|
||||
use gix::ThreadSafeRepository;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous},
|
||||
SqlitePool,
|
||||
};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::{config::Config, somehow};
|
||||
|
||||
async fn open_db(db_path: &Path) -> sqlx::Result<SqlitePool> {
|
||||
let options = SqliteConnectOptions::new()
|
||||
// https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
.journal_mode(SqliteJournalMode::Wal)
|
||||
// https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
// NORMAL recommended when using WAL, can't cause corruption
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
// https://www.sqlite.org/pragma.html#pragma_foreign_keys
|
||||
.foreign_keys(true)
|
||||
// https://www.sqlite.org/pragma.html#pragma_trusted_schema
|
||||
// The docs recommend always turning this off
|
||||
.pragma("trusted_schema", "false")
|
||||
.filename(db_path)
|
||||
.create_if_missing(true)
|
||||
// https://www.sqlite.org/lang_analyze.html#recommended_usage_pattern
|
||||
// https://www.sqlite.org/pragma.html#pragma_analysis_limit
|
||||
// https://www.sqlite.org/pragma.html#pragma_optimize
|
||||
.optimize_on_close(true, Some(1000));
|
||||
|
||||
info!(path = %db_path.display(), "Opening db");
|
||||
let pool = SqlitePoolOptions::new()
|
||||
// Regularly optimize the db as recommended by the sqlite docs
|
||||
// https://www.sqlite.org/lang_analyze.html#recommended_usage_pattern
|
||||
// https://github.com/launchbadge/sqlx/issues/2111#issuecomment-1254394698
|
||||
.max_lifetime(Some(Duration::from_secs(60 * 60 * 24)))
|
||||
.connect_with(options)
|
||||
.await?;
|
||||
|
||||
debug!("Applying outstanding db migrations");
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
fn open_repo(repo_path: &Path) -> somehow::Result<ThreadSafeRepository> {
|
||||
info!(path = %repo_path.display(), "Opening repo");
|
||||
Ok(ThreadSafeRepository::open(repo_path)?)
|
||||
}
|
||||
|
||||
#[derive(Clone, FromRef)]
|
||||
pub struct AppState {
|
||||
pub config: &'static Config,
|
||||
pub db: SqlitePool,
|
||||
pub repo: Arc<ThreadSafeRepository>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub async fn new(
|
||||
config: &'static Config,
|
||||
db_path: &Path,
|
||||
repo_path: &Path,
|
||||
) -> somehow::Result<Self> {
|
||||
Ok(Self {
|
||||
config,
|
||||
db: open_db(db_path).await?,
|
||||
repo: Arc::new(open_repo(repo_path)?),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn shut_down(self) {
|
||||
info!("Closing db");
|
||||
self.db.close().await;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue