add config options via env vars and file
This commit is contained in:
parent
7754599e72
commit
283b702c56
5 changed files with 95 additions and 28 deletions
|
@ -28,8 +28,7 @@ async fn auth_middleware(
|
|||
req: Request,
|
||||
next: Next,
|
||||
) -> Response {
|
||||
let admin_tok = headers.get("x-admin-tok");
|
||||
if headers.get("x-admin-tok") == Some(&HeaderValue::from_static(ADMIN_TOK)) {
|
||||
if state.check_admin_tok(&headers) {
|
||||
let res = next.run(req).await;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -114,25 +114,21 @@ pub async fn post(
|
|||
return StatusCode::BAD_REQUEST.into_response();
|
||||
}
|
||||
|
||||
if headers.get("x-admin-tok") == Some(&HeaderValue::from_static(ADMIN_TOK)) {
|
||||
sqlx::query!(
|
||||
r#"insert into messages (chat_id, content, from_admin) values ($1, $2, true);"#,
|
||||
chat.id,
|
||||
body
|
||||
)
|
||||
.execute(state.pool())
|
||||
.await
|
||||
.unwrap();
|
||||
let is_admin = state.check_admin_tok(&headers);
|
||||
|
||||
sqlx::query!(
|
||||
r#"insert into messages (chat_id, content, from_admin) values ($1, $2, $3);"#,
|
||||
chat.id,
|
||||
body,
|
||||
is_admin
|
||||
)
|
||||
.execute(state.pool())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if is_admin {
|
||||
StatusCode::OK.into_response()
|
||||
} else {
|
||||
sqlx::query!(
|
||||
r#"insert into messages (chat_id, content, from_admin) values ($1, $2, false);"#,
|
||||
chat.id,
|
||||
body
|
||||
)
|
||||
.execute(state.pool())
|
||||
.await
|
||||
.unwrap();
|
||||
Redirect::to(&format!("/{url_path}")).into_response()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use axum::response::IntoResponse;
|
||||
use http::StatusCode;
|
||||
use config::Config;
|
||||
use http::{HeaderMap, HeaderValue, StatusCode};
|
||||
use sqlx::{Pool, Postgres};
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -9,23 +12,85 @@ type Result<T> = std::result::Result<T, AppStateError>;
|
|||
const DB_URL: &str = "postgres://chatdings@localhost/chatdings";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AppState {
|
||||
pub struct AppState(Arc<AppStateInner>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppStateInner {
|
||||
pool: Pool<Postgres>,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
mod config {
|
||||
use std::{env, fs};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Config {
|
||||
db_url: String,
|
||||
admin_token: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn read_from_env() -> Self {
|
||||
let db_url = env::var("CHATDINGS_DB_URL")
|
||||
.expect("environment variable CHATDINGS_DB_URL has to exist");
|
||||
let admin_token_path = env::var("CHATDINGS_ADMIN_TOKEN_PATH")
|
||||
.expect("environment variable CHATDINGS_ADMIN_TOKEN has to exist");
|
||||
let admin_token = fs::read_to_string(&admin_token_path)
|
||||
.expect(&format!("failed to read '{admin_token_path:?}'"))
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
Self {
|
||||
db_url,
|
||||
admin_token,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn db_url(&self) -> &str {
|
||||
&self.db_url
|
||||
}
|
||||
|
||||
pub fn admin_tok(&self) -> &str {
|
||||
&self.admin_token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub async fn init() -> Result<Self> {
|
||||
let pool = Pool::<Postgres>::connect(DB_URL).await?;
|
||||
Ok(Self(Arc::new(AppStateInner::init().await?)))
|
||||
}
|
||||
pub async fn fetch_chat_by_url_path(&self, url_path: &str) -> Result<Chat> {
|
||||
self.0.fetch_chat_by_url_path(url_path).await
|
||||
}
|
||||
pub async fn fetch_messages(&self, chat: &Chat) -> Result<Vec<Message>> {
|
||||
self.0.fetch_messages(chat).await
|
||||
}
|
||||
pub async fn send_message(&self, chat: &Chat, content: String, from_admin: bool) -> Result<()> {
|
||||
self.0.send_message(chat, content, from_admin).await
|
||||
}
|
||||
pub fn check_admin_tok(&self, headers: &HeaderMap) -> bool {
|
||||
self.0.check_admin_tok(headers)
|
||||
}
|
||||
pub fn pool(&self) -> &Pool<Postgres> {
|
||||
self.0.pool()
|
||||
}
|
||||
}
|
||||
|
||||
impl AppStateInner {
|
||||
async fn init() -> Result<Self> {
|
||||
let config = Config::read_from_env();
|
||||
let pool = Pool::<Postgres>::connect(config.db_url()).await?;
|
||||
|
||||
sqlx::migrate!()
|
||||
.run(&pool)
|
||||
.await
|
||||
.expect("migration should not fail");
|
||||
|
||||
Ok(Self { pool })
|
||||
Ok(Self { pool, config })
|
||||
}
|
||||
|
||||
pub async fn fetch_chat_by_url_path(&self, url_path: &str) -> Result<Chat> {
|
||||
async fn fetch_chat_by_url_path(&self, url_path: &str) -> Result<Chat> {
|
||||
Ok(
|
||||
sqlx::query_as!(Chat, r#"select * from chats where url_path = $1"#, url_path)
|
||||
.fetch_one(&self.pool)
|
||||
|
@ -33,7 +98,7 @@ impl AppState {
|
|||
)
|
||||
}
|
||||
|
||||
pub async fn fetch_messages(&self, chat: &Chat) -> Result<Vec<Message>> {
|
||||
async fn fetch_messages(&self, chat: &Chat) -> Result<Vec<Message>> {
|
||||
Ok(sqlx::query_as!(
|
||||
Message,
|
||||
r#"select * from messages where chat_id = $1"#,
|
||||
|
@ -43,11 +108,15 @@ impl AppState {
|
|||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_message(&self, chat: &Chat, content: String, from_admin: bool) -> Result<()> {
|
||||
async fn send_message(&self, chat: &Chat, content: String, from_admin: bool) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn pool(&self) -> &Pool<Postgres> {
|
||||
fn check_admin_tok(&self, headers: &HeaderMap) -> bool {
|
||||
headers.get("x-admin-tok") == Some(&HeaderValue::from_str(self.config.admin_tok()).unwrap())
|
||||
}
|
||||
|
||||
fn pool(&self) -> &Pool<Postgres> {
|
||||
&self.pool
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,8 +59,10 @@
|
|||
listen_addresses = "127.0.0.1";
|
||||
};
|
||||
|
||||
env = {
|
||||
env = rec {
|
||||
DATABASE_URL = "postgres://localhost/chatdings";
|
||||
CHATDINGS_DB_URL = DATABASE_URL;
|
||||
CHATDINGS_ADMIN_TOKEN_PATH = "./test_admin_tok.txt";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
|
1
test_admin_tok.txt
Normal file
1
test_admin_tok.txt
Normal file
|
@ -0,0 +1 @@
|
|||
miauu
|
Loading…
Reference in a new issue