mirror of
https://github.com/Blah-IM/blahrs.git
synced 2025-05-01 08:41:09 +00:00
Split out socket config and switch back to toml
crate
basic-toml does not support externally-tagged enum yet. See: https://github.com/dtolnay/basic-toml/issues/8
This commit is contained in:
parent
4f0f1405dc
commit
c5263c607c
7 changed files with 92 additions and 48 deletions
63
Cargo.lock
generated
63
Cargo.lock
generated
|
@ -244,15 +244,6 @@ version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "basic-toml"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
@ -309,7 +300,6 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
"axum-extra",
|
"axum-extra",
|
||||||
"basic-toml",
|
|
||||||
"blah",
|
"blah",
|
||||||
"clap",
|
"clap",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
|
@ -327,6 +317,7 @@ dependencies = [
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
"toml",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -1749,6 +1740,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2111,6 +2111,40 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.4.0",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
@ -2554,6 +2588,15 @@ 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.6.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.35"
|
version = "0.7.35"
|
||||||
|
|
|
@ -7,7 +7,6 @@ edition = "2021"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
axum = { version = "0.7", features = ["ws"] }
|
axum = { version = "0.7", features = ["ws"] }
|
||||||
axum-extra = "0.9"
|
axum-extra = "0.9"
|
||||||
basic-toml = "0.1.9"
|
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
ed25519-dalek = "2"
|
ed25519-dalek = "2"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
|
@ -22,6 +21,7 @@ serde_json = "1"
|
||||||
serde_urlencoded = "0.7.1"
|
serde_urlencoded = "0.7.1"
|
||||||
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time"] }
|
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time"] }
|
||||||
tokio-stream = { version = "0.1", features = ["sync"] }
|
tokio-stream = { version = "0.1", features = ["sync"] }
|
||||||
|
toml = "0.8"
|
||||||
tower-http = { version = "0.5", features = ["cors", "limit"] }
|
tower-http = { version = "0.5", features = ["cors", "limit"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
|
|
|
@ -16,12 +16,12 @@ path = "/var/lib/blahd/db.sqlite"
|
||||||
# Note that parent directory will never be created and must already exist.
|
# Note that parent directory will never be created and must already exist.
|
||||||
create = true
|
create = true
|
||||||
|
|
||||||
[server]
|
[listen]
|
||||||
|
|
||||||
# (Required)
|
# (Required)
|
||||||
# The socket address to listen on.
|
# The local address to listen on.
|
||||||
listen = "localhost:8080"
|
address = "localhost:8080"
|
||||||
|
|
||||||
|
[server]
|
||||||
# (Required)
|
# (Required)
|
||||||
# The global absolute URL prefix where this service is hosted.
|
# The global absolute URL prefix where this service is hosted.
|
||||||
# It is for link generation and must not have trailing slash.
|
# It is for link generation and must not have trailing slash.
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use blahd::config::Config;
|
use blahd::config::{Config, ListenConfig};
|
||||||
use blahd::{AppState, Database};
|
use blahd::{AppState, Database};
|
||||||
|
|
||||||
/// Blah Chat Server
|
/// Blah Chat Server
|
||||||
|
@ -29,7 +30,7 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
fn parse_config(path: &std::path::Path) -> Result<Config> {
|
fn parse_config(path: &std::path::Path) -> Result<Config> {
|
||||||
let src = std::fs::read_to_string(path)?;
|
let src = std::fs::read_to_string(path)?;
|
||||||
let config = basic_toml::from_str::<Config>(&src)?;
|
let config = toml::from_str::<Config>(&src)?;
|
||||||
config.validate()?;
|
config.validate()?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
@ -38,12 +39,11 @@ fn main() -> Result<()> {
|
||||||
Cli::Serve { config } => {
|
Cli::Serve { config } => {
|
||||||
let config = parse_config(&config)?;
|
let config = parse_config(&config)?;
|
||||||
let db = Database::open(&config.database).context("failed to open database")?;
|
let db = Database::open(&config.database).context("failed to open database")?;
|
||||||
let st = AppState::new(db, config.server);
|
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()
|
.build()
|
||||||
.context("failed to initialize tokio runtime")?
|
.context("failed to initialize tokio runtime")?
|
||||||
.block_on(st.serve())
|
.block_on(main_serve(db, config))
|
||||||
}
|
}
|
||||||
Cli::Validate { config } => {
|
Cli::Validate { config } => {
|
||||||
parse_config(&config)?;
|
parse_config(&config)?;
|
||||||
|
@ -51,3 +51,21 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn main_serve(db: Database, config: Config) -> Result<()> {
|
||||||
|
let listener = match &config.listen {
|
||||||
|
ListenConfig::Address(addr) => tokio::net::TcpListener::bind(addr)
|
||||||
|
.await
|
||||||
|
.context("failed to listen on socket")?,
|
||||||
|
};
|
||||||
|
let st = AppState::new(db, config.server);
|
||||||
|
|
||||||
|
tracing::info!("listening on {:?}", config.listen);
|
||||||
|
let router = blahd::router(Arc::new(st));
|
||||||
|
let _ = sd_notify::notify(true, &[sd_notify::NotifyState::Ready]);
|
||||||
|
|
||||||
|
axum::serve(listener, router)
|
||||||
|
.await
|
||||||
|
.context("failed to serve")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{ensure, Result};
|
use anyhow::{ensure, Result};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use serde_inline_default::serde_inline_default;
|
use serde_inline_default::serde_inline_default;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use url::Url;
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub database: DatabaseConfig,
|
pub database: DatabaseConfig,
|
||||||
|
pub listen: ListenConfig,
|
||||||
pub server: ServerConfig,
|
pub server: ServerConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,11 +26,17 @@ pub struct DatabaseConfig {
|
||||||
pub create: bool,
|
pub create: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ListenConfig {
|
||||||
|
Address(String),
|
||||||
|
// TODO: Unix socket.
|
||||||
|
}
|
||||||
|
|
||||||
#[serde_inline_default]
|
#[serde_inline_default]
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub listen: String,
|
|
||||||
pub base_url: Url,
|
pub base_url: Url,
|
||||||
|
|
||||||
#[serde_inline_default(1024.try_into().expect("not zero"))]
|
#[serde_inline_default(1024.try_into().expect("not zero"))]
|
||||||
|
@ -71,7 +78,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn example_config() {
|
fn example_config() {
|
||||||
let src = std::fs::read_to_string("config.example.toml").unwrap();
|
let src = std::fs::read_to_string("config.example.toml").unwrap();
|
||||||
let config = basic_toml::from_str::<Config>(&src).unwrap();
|
let config = toml::from_str::<Config>(&src).unwrap();
|
||||||
config.validate().unwrap();
|
config.validate().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::num::NonZeroUsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use axum::extract::ws;
|
use axum::extract::ws;
|
||||||
use axum::extract::{Path, Query, State, WebSocketUpgrade};
|
use axum::extract::{Path, Query, State, WebSocketUpgrade};
|
||||||
use axum::http::{header, StatusCode};
|
use axum::http::{header, StatusCode};
|
||||||
|
@ -57,10 +57,6 @@ impl AppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serve(self) -> Result<()> {
|
|
||||||
serve(Arc::new(self)).await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn verify_signed_data<T: Serialize>(&self, data: &WithSig<T>) -> Result<(), ApiError> {
|
fn verify_signed_data<T: Serialize>(&self, data: &WithSig<T>) -> Result<(), ApiError> {
|
||||||
let Ok(()) = data.verify() else {
|
let Ok(()) = data.verify() else {
|
||||||
return Err(error_response!(
|
return Err(error_response!(
|
||||||
|
@ -94,20 +90,6 @@ impl AppState {
|
||||||
|
|
||||||
type ArcState = State<Arc<AppState>>;
|
type ArcState = State<Arc<AppState>>;
|
||||||
|
|
||||||
async fn serve(st: Arc<AppState>) -> Result<()> {
|
|
||||||
let listener = tokio::net::TcpListener::bind(&st.config.listen)
|
|
||||||
.await
|
|
||||||
.context("failed to listen on socket")?;
|
|
||||||
tracing::info!("listening on {}", st.config.listen);
|
|
||||||
let router = router(st.clone());
|
|
||||||
let _ = sd_notify::notify(true, &[sd_notify::NotifyState::Ready]);
|
|
||||||
|
|
||||||
axum::serve(listener, router)
|
|
||||||
.await
|
|
||||||
.context("failed to serve")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn router(st: Arc<AppState>) -> Router {
|
pub fn router(st: Arc<AppState>) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/ws", get(handle_ws))
|
.route("/ws", get(handle_ws))
|
||||||
|
|
|
@ -37,13 +37,7 @@ fn server() -> Server {
|
||||||
let listener = TcpListener::from_std(listener).unwrap();
|
let listener = TcpListener::from_std(listener).unwrap();
|
||||||
|
|
||||||
// TODO: Testing config is hard to build because it does have a `Default` impl.
|
// TODO: Testing config is hard to build because it does have a `Default` impl.
|
||||||
let config = basic_toml::from_str(&format!(
|
let config = toml::from_str(&format!(r#"base_url="http://{LOCALHOST}:{port}""#)).unwrap();
|
||||||
r#"
|
|
||||||
listen = "" # TODO: unused
|
|
||||||
base_url = "http://{LOCALHOST}:{port}"
|
|
||||||
"#
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
let st = AppState::new(db, config);
|
let st = AppState::new(db, config);
|
||||||
let router = blahd::router(Arc::new(st));
|
let router = blahd::router(Arc::new(st));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue