mirror of
https://github.com/Lumither/nocturne.git
synced 2026-10-18 19:06:21 +00:00
ref(global) move modules, extract constants
This commit is contained in:
10 files changed
+216
-152
No files matched your search
@@ -0,0 +1,38 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::str::FromStr;
|
||||
|
||||
use constants::config::database::{default_value, var_name};
|
||||
use sqlx::postgres::{PgConnectOptions, PgPoolOptions};
|
||||
use sqlx::{ConnectOptions, Pool, Postgres};
|
||||
use tracing::info;
|
||||
|
||||
pub async fn init() -> Result<Pool<Postgres>, Box<dyn Error>> {
|
||||
let db_connect_option = PgConnectOptions::from_str(&parse_db_uri())
|
||||
.unwrap()
|
||||
.disable_statement_logging();
|
||||
Ok(PgPoolOptions::new().connect_with(db_connect_option).await?)
|
||||
}
|
||||
|
||||
fn parse_db_uri() -> String {
|
||||
env::var(var_name::URI).unwrap_or_else(|_| {
|
||||
info!(
|
||||
"`{}` env var is not set, \
|
||||
using `{}`, `{}`, `{}`, `{}` and `{}`",
|
||||
var_name::URI,
|
||||
var_name::USERNAME,
|
||||
var_name::PASSWORD,
|
||||
var_name::HOST,
|
||||
var_name::PORT,
|
||||
var_name::DBNAME
|
||||
);
|
||||
let postgres_user = env::var(var_name::USERNAME).unwrap_or(default_value::USERNAME.into());
|
||||
let postgres_password =
|
||||
env::var(var_name::PASSWORD).unwrap_or(default_value::PASSWORD.into());
|
||||
let db_host = env::var(var_name::HOST).unwrap_or(default_value::HOST.into());
|
||||
let db_port = env::var(var_name::PORT).unwrap_or(default_value::PORT.into());
|
||||
let postgres_db = env::var(var_name::DBNAME).unwrap_or(default_value::DBNAME.into());
|
||||
let db_type = default_value::DATABASE_TYPE;
|
||||
format!("{db_type}://{postgres_user}:{postgres_password}@{db_host}:{db_port}/{postgres_db}")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
use std::path::Path;
|
||||
use std::{env, io};
|
||||
|
||||
use chrono::Local;
|
||||
use constants::config::general::{default_value, var_name};
|
||||
use dirs::home_dir;
|
||||
use tracing::info;
|
||||
use tracing_appender::{non_blocking, non_blocking::WorkerGuard, rolling};
|
||||
use tracing_subscriber::{
|
||||
filter::LevelFilter, fmt, fmt::format::Writer, fmt::time::FormatTime, fmt::MakeWriter,
|
||||
layer::SubscriberExt, Layer, Registry,
|
||||
};
|
||||
|
||||
struct LocalTimer;
|
||||
|
||||
impl FormatTime for LocalTimer {
|
||||
fn format_time(&self, w: &mut Writer<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
w,
|
||||
"{}",
|
||||
Local::now().format(constants::time::DEFAULT_TIME_FORMAT)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
type _LogWriter = dyn for<'writer> MakeWriter<'writer, Writer = dyn io::Write + 'static> + 'static;
|
||||
|
||||
pub fn init() -> (WorkerGuard, WorkerGuard) {
|
||||
let log_path = match env::var(var_name::LOG_DIR) {
|
||||
Ok(path) => Path::new(&path).to_path_buf(),
|
||||
Err(_) => {
|
||||
let path = if let Ok(default_log_path) = env::var(var_name::WORK_DIR) {
|
||||
expand_home_path(default_log_path)
|
||||
} else {
|
||||
let fallback_path = expand_home_path(default_value::WORK_DIR.to_string());
|
||||
println!(
|
||||
"[warn] unset env var `{}` and `{}`, trying to log on fallback path: {}/log",
|
||||
var_name::LOG_DIR,
|
||||
var_name::WORK_DIR,
|
||||
fallback_path
|
||||
);
|
||||
fallback_path
|
||||
};
|
||||
Path::new(&path).join("log")
|
||||
}
|
||||
};
|
||||
|
||||
let (info_log_writer, info_guard) = non_blocking(rolling::never(&log_path, "info.log"));
|
||||
let (err_log_writer, error_guard) = non_blocking(rolling::never(&log_path, "error.log"));
|
||||
|
||||
let info_format = tracing_subscriber::fmt::format()
|
||||
.with_level(true)
|
||||
.with_target(true)
|
||||
.with_source_location(true)
|
||||
.with_ansi(false);
|
||||
let err_format = tracing_subscriber::fmt::format()
|
||||
.with_level(true)
|
||||
.with_target(true)
|
||||
.with_source_location(true)
|
||||
.with_ansi(false);
|
||||
let stdout_format = tracing_subscriber::fmt::format()
|
||||
.with_level(true)
|
||||
.with_target(true)
|
||||
.with_source_location(true)
|
||||
.with_timer(LocalTimer);
|
||||
|
||||
let subscribers = Registry::default()
|
||||
.with(
|
||||
fmt::Layer::default()
|
||||
.with_writer(info_log_writer)
|
||||
.event_format(info_format),
|
||||
)
|
||||
.with(
|
||||
fmt::Layer::default()
|
||||
.with_writer(err_log_writer)
|
||||
.event_format(err_format)
|
||||
.with_filter(LevelFilter::ERROR),
|
||||
)
|
||||
.with(
|
||||
fmt::Layer::default()
|
||||
.with_writer(io::stdout)
|
||||
.with_ansi(true)
|
||||
.event_format(stdout_format),
|
||||
);
|
||||
|
||||
tracing::subscriber::set_global_default(subscribers)
|
||||
.expect("[fatal] failed to setup logging system");
|
||||
|
||||
info!("logging to dir: {}", log_path.to_str().unwrap());
|
||||
|
||||
(info_guard, error_guard)
|
||||
}
|
||||
|
||||
fn expand_home_path(path: String) -> String {
|
||||
if path.starts_with('~') {
|
||||
let home_path = home_dir()
|
||||
.unwrap_or_else(|| panic!("[fatal] unable to locate home dir when parsing env `{}`, try to use absolute path instead", var_name::WORK_DIR));
|
||||
home_path
|
||||
.join(path.strip_prefix("~/").unwrap())
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
mod database;
|
||||
pub mod logger;
|
||||
pub mod server;
|
||||
|
||||
use macros::panic_with_log;
|
||||
use std::{env, panic};
|
||||
use tracing::{info, Level};
|
||||
|
||||
pub fn load_env() {
|
||||
if let Some(env_file) = env::args().nth(1) {
|
||||
match dotenv::from_filename(&env_file) {
|
||||
Ok(_) => {
|
||||
println!("[info] env loaded from {}, starting up", env_file);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("[fatal] failed to read {}: {}", env_file, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("[info] no .env file referred, starting up")
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start() {
|
||||
let db_pool = match database::init().await {
|
||||
Ok(pool) => {
|
||||
info!("database connection pool initialized");
|
||||
pool
|
||||
}
|
||||
Err(e) => {
|
||||
panic_with_log!(
|
||||
Level::ERROR,
|
||||
"database connection pool failed to initialize: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
match server::start(db_pool).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
panic_with_log!(Level::ERROR, "server panicked: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::num::ParseIntError;
|
||||
use std::process::exit;
|
||||
|
||||
use crate::blog;
|
||||
use axum::Router;
|
||||
use constants::config::server::{default_value, var_name};
|
||||
use macros::panic_with_log;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tracing::{error, info, warn, Level};
|
||||
|
||||
pub async fn start(db_pool: Pool<Postgres>) -> Result<(), Box<dyn Error>> {
|
||||
let app = Router::new()
|
||||
.nest("/blog", blog::get_router())
|
||||
.with_state(db_pool);
|
||||
|
||||
let port: u32 = match env::var(var_name::PORT) {
|
||||
Ok(value) => value.parse().unwrap_or_else(|e: ParseIntError| {
|
||||
warn!(
|
||||
"failed to parse `{}`, using default port: {}",
|
||||
var_name::PORT,
|
||||
e.to_string()
|
||||
);
|
||||
default_value::PORT
|
||||
}),
|
||||
Err(_) => default_value::PORT,
|
||||
};
|
||||
|
||||
let listener =
|
||||
match tokio::net::TcpListener::bind(format!("{}:{}", default_value::HOST, port)).await {
|
||||
Ok(listener) => {
|
||||
info!("server started on {}:{}", default_value::HOST, port);
|
||||
listener
|
||||
}
|
||||
Err(e) => {
|
||||
panic_with_log!(
|
||||
Level::ERROR,
|
||||
"failed to start server on {}:{}: {}",
|
||||
default_value::HOST,
|
||||
port,
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
axum::serve(listener, app).await.unwrap_or_else(|e| {
|
||||
error!("failed to start axum: {}", e.to_string());
|
||||
exit(1);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user