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,
|
req: Request,
|
||||||
next: Next,
|
next: Next,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let admin_tok = headers.get("x-admin-tok");
|
if state.check_admin_tok(&headers) {
|
||||||
if headers.get("x-admin-tok") == Some(&HeaderValue::from_static(ADMIN_TOK)) {
|
|
||||||
let res = next.run(req).await;
|
let res = next.run(req).await;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,25 +114,21 @@ pub async fn post(
|
||||||
return StatusCode::BAD_REQUEST.into_response();
|
return StatusCode::BAD_REQUEST.into_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
if headers.get("x-admin-tok") == Some(&HeaderValue::from_static(ADMIN_TOK)) {
|
let is_admin = state.check_admin_tok(&headers);
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"insert into messages (chat_id, content, from_admin) values ($1, $2, true);"#,
|
r#"insert into messages (chat_id, content, from_admin) values ($1, $2, $3);"#,
|
||||||
chat.id,
|
chat.id,
|
||||||
body
|
body,
|
||||||
|
is_admin
|
||||||
)
|
)
|
||||||
.execute(state.pool())
|
.execute(state.pool())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if is_admin {
|
||||||
StatusCode::OK.into_response()
|
StatusCode::OK.into_response()
|
||||||
} else {
|
} 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()
|
Redirect::to(&format!("/{url_path}")).into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use http::StatusCode;
|
use config::Config;
|
||||||
|
use http::{HeaderMap, HeaderValue, StatusCode};
|
||||||
use sqlx::{Pool, Postgres};
|
use sqlx::{Pool, Postgres};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -9,23 +12,85 @@ type Result<T> = std::result::Result<T, AppStateError>;
|
||||||
const DB_URL: &str = "postgres://chatdings@localhost/chatdings";
|
const DB_URL: &str = "postgres://chatdings@localhost/chatdings";
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState(Arc<AppStateInner>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AppStateInner {
|
||||||
pool: Pool<Postgres>,
|
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 {
|
impl AppState {
|
||||||
pub async fn init() -> Result<Self> {
|
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!()
|
sqlx::migrate!()
|
||||||
.run(&pool)
|
.run(&pool)
|
||||||
.await
|
.await
|
||||||
.expect("migration should not fail");
|
.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(
|
Ok(
|
||||||
sqlx::query_as!(Chat, r#"select * from chats where url_path = $1"#, url_path)
|
sqlx::query_as!(Chat, r#"select * from chats where url_path = $1"#, url_path)
|
||||||
.fetch_one(&self.pool)
|
.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!(
|
Ok(sqlx::query_as!(
|
||||||
Message,
|
Message,
|
||||||
r#"select * from messages where chat_id = $1"#,
|
r#"select * from messages where chat_id = $1"#,
|
||||||
|
@ -43,11 +108,15 @@ impl AppState {
|
||||||
.await?)
|
.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!()
|
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
|
&self.pool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,10 @@
|
||||||
listen_addresses = "127.0.0.1";
|
listen_addresses = "127.0.0.1";
|
||||||
};
|
};
|
||||||
|
|
||||||
env = {
|
env = rec {
|
||||||
DATABASE_URL = "postgres://localhost/chatdings";
|
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