diff --git a/Dockerfile b/Dockerfile index 6ad7eb3..27bdeeb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,9 +35,7 @@ COPY --from=builder /nostr-rs-relay/target/release/nostr-rs-relay ${APP}/nostr-r RUN chown -R $APP_USER:$APP_USER ${APP} USER $APP_USER -WORKDIR ${APP_DATA} +WORKDIR ${APP} ENV RUST_LOG=info - - -CMD ["../nostr-rs-relay"] +CMD ["./nostr-rs-relay --db $APP_DATA"] diff --git a/config.toml b/config.toml index 2ea365d..f2265de 100644 --- a/config.toml +++ b/config.toml @@ -1,4 +1,8 @@ # Nostr-rs-relay configuration +[database] +# Directory for SQLite files. Defaults to the current directory. Can +# also be specified with the "--db dirname" command line option. +data_directory = "data" [network] # Bind to this network address @@ -18,15 +22,15 @@ port = 8080 messages_per_sec = 0 # Maximum WebSocket message in bytes. Defaults to 128k. -#max_ws_message_bytes = 131072 +max_ws_message_bytes = 131072 # Maximum WebSocket frame size in bytes. Defaults to 128k. -#max_ws_frame_bytes = 131072 +max_ws_frame_bytes = 131072 # Broadcast buffer size, in number of events. This prevents slow # readers from consuming memory. Defaults to 4096. -#broadcast_buffer = 4096 +broadcast_buffer = 4096 # Event persistence buffer size, in number of events. This provides # backpressure to senders if writes are slow. Defaults to 16. -#event_persist_buffer = 16 +event_persist_buffer = 16 diff --git a/src/config.rs b/src/config.rs index 72708bf..7bd7919 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,6 +8,12 @@ lazy_static! { pub static ref SETTINGS: RwLock = RwLock::new(Settings::default()); } +#[derive(Debug, Serialize, Deserialize)] +#[allow(unused)] +pub struct Database { + pub data_directory: String, +} + #[derive(Debug, Serialize, Deserialize)] #[allow(unused)] pub struct Network { @@ -46,6 +52,7 @@ pub struct Limits { #[derive(Debug, Serialize, Deserialize)] #[allow(unused)] pub struct Settings { + pub database: Database, pub network: Network, pub limits: Limits, pub retention: Retention, @@ -82,6 +89,9 @@ impl Settings { impl Default for Settings { fn default() -> Self { Settings { + database: Database { + data_directory: ".".to_owned(), + }, network: Network { port: 8080, address: "0.0.0.0".to_owned(), diff --git a/src/db.rs b/src/db.rs index 7b459ce..a9e197a 100644 --- a/src/db.rs +++ b/src/db.rs @@ -122,14 +122,18 @@ pub async fn db_writer( mut shutdown: tokio::sync::broadcast::Receiver<()>, ) -> tokio::task::JoinHandle> { task::spawn_blocking(move || { + // get database configuration settings + let config = SETTINGS.read().unwrap(); + let db_dir = &config.database.data_directory; + let full_path = Path::new(db_dir).join(DB_FILE); + // create a connection let mut conn = Connection::open_with_flags( - Path::new(DB_FILE), + &full_path, OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE, )?; - info!("opened database for writing"); + info!("opened database {:?} for writing", full_path); upgrade_db(&mut conn)?; // get rate limit settings - let config = SETTINGS.read().unwrap(); let rps_setting = config.limits.messages_per_sec; let mut lim_opt = None; let clock = governor::clock::QuantaClock::default(); @@ -373,9 +377,12 @@ pub async fn db_query( mut abandon_query_rx: tokio::sync::oneshot::Receiver<()>, ) { task::spawn_blocking(move || { + let config = SETTINGS.read().unwrap(); + let db_dir = &config.database.data_directory; + let full_path = Path::new(db_dir).join(DB_FILE); + let conn = - Connection::open_with_flags(Path::new(DB_FILE), OpenFlags::SQLITE_OPEN_READ_ONLY) - .unwrap(); + Connection::open_with_flags(&full_path, OpenFlags::SQLITE_OPEN_READ_ONLY).unwrap(); debug!("opened database for reading"); debug!("going to query for: {:?}", sub); // generate SQL query diff --git a/src/error.rs b/src/error.rs index a20119a..e070167 100644 --- a/src/error.rs +++ b/src/error.rs @@ -36,6 +36,8 @@ pub enum Error { SqlError(rusqlite::Error), #[error("Config error")] ConfigError(config::ConfigError), + #[error("Data directory does not exist")] + DatabaseDirError, } impl From for Error { diff --git a/src/main.rs b/src/main.rs index b705093..6c9adf4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,8 @@ use nostr_rs_relay::protostream; use nostr_rs_relay::protostream::NostrMessage::*; use nostr_rs_relay::protostream::NostrResponse::*; use std::collections::HashMap; +use std::env; +use std::path::Path; use tokio::net::{TcpListener, TcpStream}; use tokio::runtime::Builder; use tokio::sync::broadcast; @@ -20,17 +22,39 @@ use tokio::sync::mpsc; use tokio::sync::oneshot; use tungstenite::protocol::WebSocketConfig; +fn db_from_args(args: Vec) -> Option { + if args.len() == 3 { + if args.get(1) == Some(&"--db".to_owned()) { + return args.get(2).map(|x| x.to_owned()); + } + } + None +} + /// Start running a Nostr relay server. fn main() -> Result<(), Error> { // setup logger let _ = env_logger::try_init(); + // get database directory from args + let args: Vec = env::args().collect(); + let db_dir: Option = db_from_args(args); + info!("Using database: {:?}", db_dir); { let mut settings = config::SETTINGS.write().unwrap(); // replace default settings with those read from config.toml - let c = config::Settings::new(); + let mut c = config::Settings::new(); + // update with database location + if let Some(db) = db_dir { + c.database.data_directory = db.to_owned(); + } *settings = c; } let config = config::SETTINGS.read().unwrap(); + // do some config validation. + if !Path::new(&config.database.data_directory).is_dir() { + error!("Database directory does not exist"); + return Err(Error::DatabaseDirError); + } debug!("config: {:?}", config); let addr = format!("{}:{}", config.network.address.trim(), config.network.port); // configure tokio runtime