mirror of
https://github.com/Blah-IM/blahrs.git
synced 2025-05-01 00:31:09 +00:00
Make more server constants configurable
This commit is contained in:
parent
abdc32b51f
commit
6e7229e4ac
5 changed files with 57 additions and 16 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -300,6 +300,7 @@ dependencies = [
|
|||
"sd-notify",
|
||||
"serde",
|
||||
"serde-aux",
|
||||
"serde-inline-default",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
|
@ -1455,6 +1456,17 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-inline-default"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9980133dc534d02ab08df3b384295223a45090c40a4c46240e3eaa982b495910"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.209"
|
||||
|
|
|
@ -26,3 +26,4 @@ uuid = { version = "1", features = ["v4"] }
|
|||
|
||||
blah = { path = "..", features = ["rusqlite"] }
|
||||
basic-toml = "0.1.9"
|
||||
serde-inline-default = "0.2.0"
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
[database]
|
||||
# (Required)
|
||||
# The path to the main SQLite database.
|
||||
# It will be created and initialized if not exist.
|
||||
path = "/path/to/db.sqlite"
|
||||
|
||||
[server]
|
||||
|
||||
# (Required)
|
||||
# The socket address to listen on.
|
||||
listen = "localhost:8080"
|
||||
|
||||
# (Required)
|
||||
# The global absolute URL prefix where this service is hosted.
|
||||
# It is for link generation and must not have trailing slash.
|
||||
base_url = "http://localhost:8080"
|
||||
|
||||
# Maximum number of items in a single response, eg. get chat items.
|
||||
# More items will be paged.
|
||||
max_page_len = 1024
|
||||
|
||||
# Maximum request body length in bytes.
|
||||
max_request_len = 4096
|
||||
|
||||
# Maximum length of a single event queue.
|
||||
event_queue_len = 1024
|
||||
|
||||
# The maximum timestamp tolerence in seconds for request validation.
|
||||
timestamp_tolerence_secs = 90
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::path::PathBuf;
|
|||
|
||||
use anyhow::{ensure, Result};
|
||||
use serde::Deserialize;
|
||||
use serde_inline_default::serde_inline_default;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
@ -16,11 +17,22 @@ pub struct DatabaseConfig {
|
|||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
#[serde_inline_default]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ServerConfig {
|
||||
pub listen: String,
|
||||
pub base_url: String,
|
||||
|
||||
#[serde_inline_default(1024)]
|
||||
pub max_page_len: usize,
|
||||
#[serde_inline_default(4096)] // 4KiB
|
||||
pub max_request_len: usize,
|
||||
#[serde_inline_default(1024)]
|
||||
pub event_queue_len: usize,
|
||||
|
||||
#[serde_inline_default(90)]
|
||||
pub timestamp_tolerence_secs: u64,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
|
@ -26,11 +26,6 @@ use tokio_stream::StreamExt;
|
|||
use utils::ExpiringSet;
|
||||
use uuid::Uuid;
|
||||
|
||||
const PAGE_LEN: usize = 64;
|
||||
const EVENT_QUEUE_LEN: usize = 1024;
|
||||
const MAX_BODY_LEN: usize = 4 << 10; // 4KiB
|
||||
const TIMESTAMP_TOLERENCE: u64 = 90;
|
||||
|
||||
#[macro_use]
|
||||
mod middleware;
|
||||
mod config;
|
||||
|
@ -105,7 +100,9 @@ impl AppState {
|
|||
Ok(Self {
|
||||
conn: Mutex::new(conn),
|
||||
room_listeners: Mutex::new(HashMap::new()),
|
||||
used_nonces: Mutex::new(ExpiringSet::new(Duration::from_secs(TIMESTAMP_TOLERENCE))),
|
||||
used_nonces: Mutex::new(ExpiringSet::new(Duration::from_secs(
|
||||
config.server.timestamp_tolerence_secs,
|
||||
))),
|
||||
|
||||
config,
|
||||
})
|
||||
|
@ -124,7 +121,7 @@ impl AppState {
|
|||
.expect("after UNIX epoch")
|
||||
.as_secs()
|
||||
.abs_diff(data.signee.timestamp);
|
||||
if timestamp_diff > TIMESTAMP_TOLERENCE {
|
||||
if timestamp_diff > self.config.server.timestamp_tolerence_secs {
|
||||
return Err(error_response!(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"invalid_timestamp",
|
||||
|
@ -161,7 +158,9 @@ async fn main_async(st: AppState) -> Result<()> {
|
|||
.with_state(st.clone())
|
||||
// NB. This comes at last (outmost layer), so inner errors will still be wraped with
|
||||
// correct CORS headers.
|
||||
.layer(tower_http::limit::RequestBodyLimitLayer::new(MAX_BODY_LEN))
|
||||
.layer(tower_http::limit::RequestBodyLimitLayer::new(
|
||||
st.config.server.max_request_len,
|
||||
))
|
||||
.layer(tower_http::cors::CorsLayer::permissive());
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(&st.config.server.listen)
|
||||
|
@ -276,8 +275,7 @@ async fn room_get_item(
|
|||
WithRejection(params, _): WithRejection<Query<GetRoomItemParams>, ApiError>,
|
||||
OptionalAuth(user): OptionalAuth,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let (room_meta, items) =
|
||||
query_room_items(&st.conn.lock().unwrap(), ruuid, user.as_ref(), ¶ms)?;
|
||||
let (room_meta, items) = query_room_items(&st, ruuid, user.as_ref(), ¶ms)?;
|
||||
|
||||
// TODO: This format is to-be-decided. Or do we even need this interface other than
|
||||
// `feed.json`?
|
||||
|
@ -289,7 +287,7 @@ async fn room_get_feed(
|
|||
WithRejection(Path(ruuid), _): WithRejection<Path<Uuid>, ApiError>,
|
||||
params: Query<GetRoomItemParams>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let (room_meta, items) = query_room_items(&st.conn.lock().unwrap(), ruuid, None, ¶ms)?;
|
||||
let (room_meta, items) = query_room_items(&st, ruuid, None, ¶ms)?;
|
||||
|
||||
let items = items
|
||||
.into_iter()
|
||||
|
@ -314,7 +312,7 @@ async fn room_get_feed(
|
|||
|
||||
let base_url = &st.config.server.base_url;
|
||||
let feed_url = format!("{base_url}/room/{ruuid}/feed.json");
|
||||
let next_url = (items.len() == PAGE_LEN).then(|| {
|
||||
let next_url = (items.len() == st.config.server.max_page_len).then(|| {
|
||||
let last_id = &items.last().expect("page size is not 0").id;
|
||||
format!("{feed_url}?before_id={last_id}")
|
||||
});
|
||||
|
@ -401,12 +399,14 @@ fn get_room_if_readable<T>(
|
|||
}
|
||||
|
||||
fn query_room_items(
|
||||
conn: &rusqlite::Connection,
|
||||
st: &AppState,
|
||||
ruuid: Uuid,
|
||||
user: Option<&UserKey>,
|
||||
params: &GetRoomItemParams,
|
||||
) -> Result<(RoomMetadata, Vec<(u64, ChatItem)>), ApiError> {
|
||||
let (rid, title, attrs) = get_room_if_readable(conn, ruuid, user, |row| {
|
||||
let conn = st.conn.lock().unwrap();
|
||||
|
||||
let (rid, title, attrs) = get_room_if_readable(&conn, ruuid, user, |row| {
|
||||
Ok((
|
||||
row.get::<_, u64>("rid")?,
|
||||
row.get::<_, String>("title")?,
|
||||
|
@ -432,7 +432,7 @@ fn query_room_items(
|
|||
named_params! {
|
||||
":rid": rid,
|
||||
":before_cid": params.before_id,
|
||||
":limit": PAGE_LEN,
|
||||
":limit": st.config.server.max_page_len,
|
||||
},
|
||||
|row| {
|
||||
let cid = row.get::<_, u64>("cid")?;
|
||||
|
@ -543,7 +543,7 @@ async fn room_event(
|
|||
let rx = match st.room_listeners.lock().unwrap().entry(rid) {
|
||||
Entry::Occupied(ent) => ent.get().subscribe(),
|
||||
Entry::Vacant(ent) => {
|
||||
let (tx, rx) = broadcast::channel(EVENT_QUEUE_LEN);
|
||||
let (tx, rx) = broadcast::channel(st.config.server.event_queue_len);
|
||||
ent.insert(tx);
|
||||
rx
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue