added config.toml
support for flexible server configuration, integrated toml
crate for parsing, refactored configuration management to use AppSettings
, and updated database initialization logic
This commit is contained in:
55
backend-rust/Cargo.lock
generated
55
backend-rust/Cargo.lock
generated
@@ -1124,6 +1124,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
@@ -1467,6 +1468,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -1932,6 +1942,45 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_parser"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||||
|
dependencies = [
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_writer"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -2399,6 +2448,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-rt"
|
name = "wit-bindgen-rt"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
|
@@ -13,3 +13,4 @@ sqlx = { version = "0.8", features = ["runtime-tokio", "tls-native-tls", "sqlite
|
|||||||
dotenv = "0.15"
|
dotenv = "0.15"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
toml = "0.9.5"
|
||||||
|
3
backend-rust/config.toml
Normal file
3
backend-rust/config.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[server]
|
||||||
|
host = '127.0.0.1'
|
||||||
|
port = 8090
|
@@ -1,33 +1,67 @@
|
|||||||
|
use serde::Deserialize;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use toml::Value;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Config {
|
pub struct AppSettings {
|
||||||
|
pub config_path: String,
|
||||||
pub db_path: String,
|
pub db_path: String,
|
||||||
pub migration_path: String,
|
pub migration_path: String,
|
||||||
|
pub config: Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
pub server: Server,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Server {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
#[derive(Deserialize, Debug)]
|
||||||
pub fn from_env() -> Self {
|
struct ConfigFile {
|
||||||
|
server: Server,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppSettings {
|
||||||
|
pub fn get_app_settings() -> Self {
|
||||||
|
let config_file = Self::load_config_file().unwrap_or_else(|| {
|
||||||
|
info!("Using default config values");
|
||||||
|
ConfigFile {
|
||||||
|
server: Server {
|
||||||
|
host: "127.0.0.1".to_string(),
|
||||||
|
port: 1337,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
config_path: Self::get_config_path(),
|
||||||
db_path: Self::get_db_path(),
|
db_path: Self::get_db_path(),
|
||||||
migration_path: std::env::var("MIGRATION_PATH")
|
migration_path: String::from("./migrations"),
|
||||||
.unwrap_or_else(|_| "./migrations".to_string()),
|
config: Config {
|
||||||
host: env::var("HOST").unwrap_or_else(|_| "127.0.0.1".to_string()),
|
server: config_file.server,
|
||||||
port: env::var("PORT")
|
},
|
||||||
.unwrap_or_else(|_| "1337".to_string())
|
|
||||||
.parse()
|
|
||||||
.expect("PORT must be a number"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_db_path() -> String {
|
fn load_config_file() -> Option<ConfigFile> {
|
||||||
if let Ok(db_path) = env::var("DATABASE_PATH") {
|
let config_path = Self::get_config_path();
|
||||||
return db_path;
|
let contents = std::fs::read_to_string(&config_path)
|
||||||
}
|
.map_err(|e| error!("Failed to read config file: {}", e))
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
toml::from_str(&contents)
|
||||||
|
.map_err(|e| error!("Failed to parse TOML: {}", e))
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_db_path() -> String {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
// Development: Use backend-rust directory
|
// Development: Use backend-rust directory
|
||||||
// TODO: Change later
|
// TODO: Change later
|
||||||
@@ -40,6 +74,19 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_config_path() -> String {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
// Development: Use backend-rust directory
|
||||||
|
// TODO: Change later
|
||||||
|
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
path.push("config.toml");
|
||||||
|
path.to_str().unwrap().to_string()
|
||||||
|
} else {
|
||||||
|
// Production: Use standard Linux applications data directory
|
||||||
|
"$HOME/owly-news-summariser/config.toml".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn database_url(&self) -> String {
|
pub fn database_url(&self) -> String {
|
||||||
format!("sqlite:{}", self.db_path)
|
format!("sqlite:{}", self.db_path)
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
use crate::config::Config;
|
use crate::config::{AppSettings};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use sqlx::migrate::Migrator;
|
use sqlx::migrate::Migrator;
|
||||||
use sqlx::sqlite::{SqliteConnectOptions, SqliteConnection};
|
use sqlx::sqlite::{SqliteConnectOptions};
|
||||||
use sqlx::{Pool, Sqlite, SqlitePool};
|
use sqlx::{Pool, Sqlite, SqlitePool};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
pub const MIGRATOR: Migrator = sqlx::migrate!("./migrations");
|
pub const MIGRATOR: Migrator = sqlx::migrate!("./migrations");
|
||||||
|
|
||||||
pub async fn initialize_db(config: &Config) -> Result<Pool<Sqlite>> {
|
pub async fn initialize_db(app_settings: &AppSettings) -> Result<Pool<Sqlite>> {
|
||||||
config.ensure_db_directory()?;
|
app_settings.ensure_db_directory()?;
|
||||||
|
|
||||||
let options = SqliteConnectOptions::from_str(&config.database_url())?
|
let options = SqliteConnectOptions::from_str(&app_settings.database_url())?
|
||||||
.create_if_missing(true)
|
.create_if_missing(true)
|
||||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||||
.foreign_keys(true);
|
.foreign_keys(true);
|
||||||
|
@@ -4,16 +4,12 @@ mod db;
|
|||||||
mod models;
|
mod models;
|
||||||
mod services;
|
mod services;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::{AppSettings};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use sqlx::sqlite::SqliteConnectOptions;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use tokio::signal;
|
use tokio::signal;
|
||||||
use tokio::signal::ctrl_c;
|
use tracing::{info};
|
||||||
use tokio::signal::unix::signal;
|
|
||||||
use tracing::{error, info};
|
|
||||||
use tracing_subscriber;
|
use tracing_subscriber;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@@ -23,15 +19,15 @@ async fn main() -> Result<()> {
|
|||||||
.compact()
|
.compact()
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let config = Config::from_env();
|
let app_settings = AppSettings::get_app_settings();
|
||||||
|
|
||||||
let pool = db::initialize_db(&config).await?;
|
let pool = db::initialize_db(&app_settings).await?;
|
||||||
|
|
||||||
let app = create_app(pool);
|
let app = create_app(pool);
|
||||||
|
|
||||||
let listener =
|
let listener =
|
||||||
tokio::net::TcpListener::bind(format!("{}:{}", config.host, config.port)).await?;
|
tokio::net::TcpListener::bind(format!("{}:{}", app_settings.config.server.host, app_settings.config.server.port)).await?;
|
||||||
info!("Server starting on {}:{}", config.host, config.port);
|
info!("Server starting on {}:{}", app_settings.config.server.host, app_settings.config.server.port);
|
||||||
|
|
||||||
axum::serve(listener, app)
|
axum::serve(listener, app)
|
||||||
.with_graceful_shutdown(shutdown_signal())
|
.with_graceful_shutdown(shutdown_signal())
|
||||||
|
Reference in New Issue
Block a user