feat: add database backend configuration options

Add environment variable configuration for database backend selection:
- Added DatabaseBackend enum (memory, nostrdb, lmdb) in src/config.rs
- Updated relay builder to use configured backend in src/nostr/builder.rs
- Added NGIT_DATABASE_BACKEND to .env.example with documentation
- Updated docs/reference/configuration.md with backend comparison table

NostrDB and LMDB backends prepared for future implementation when
nostr-relay-builder adds support. Currently defaults to in-memory
database with warning logs when persistent backends are selected.
This commit is contained in:
DanConwayDev
2025-11-21 04:04:05 +00:00
parent 25b206c007
commit 2e799fa7ec
4 changed files with 120 additions and 9 deletions
+6
View File
@@ -14,6 +14,12 @@ NGIT_RELAY_DESCRIPTION=A GRASP-compliant Git relay with Nostr authorization
NGIT_GIT_DATA_PATH=./data/git
NGIT_RELAY_DATA_PATH=./data/relay
# Database backend (memory, nostrdb, lmdb)
# - memory: In-memory database (default, fastest, no persistence)
# - nostrdb: NostrDB backend (persistent, optimized for Nostr) [Not yet implemented]
# - lmdb: LMDB backend (persistent, general purpose) [Not yet implemented]
NGIT_DATABASE_BACKEND=memory
# Server configuration
NGIT_BIND_ADDRESS=127.0.0.1:8080
+41
View File
@@ -224,6 +224,47 @@ NGIT_RELAY_DATA_PATH=/mnt/ssd/relay-data
---
#### `NGIT_DATABASE_BACKEND`
**Description:** Database backend type for storing Nostr events
**Type:** String (enum: memory, nostrdb, lmdb)
**Default:** `memory`
**Required:** No
**Valid Values:**
- `memory` - In-memory database (default, fastest, no persistence)
- `nostrdb` - NostrDB backend (persistent, optimized for Nostr) [Not yet implemented]
- `lmdb` - LMDB backend (persistent, general purpose) [Not yet implemented]
**Examples:**
```bash
# Development (default, no persistence)
NGIT_DATABASE_BACKEND=memory
# Production with NostrDB (when implemented)
NGIT_DATABASE_BACKEND=nostrdb
# Production with LMDB (when implemented)
NGIT_DATABASE_BACKEND=lmdb
```
**Comparison:**
| Backend | Persistence | Performance | Use Case |
|---------|-------------|-------------|----------|
| memory | No | Fastest | Development, testing |
| nostrdb | Yes | High | Production (Nostr-optimized) |
| lmdb | Yes | High | Production (general purpose) |
**Notes:**
- `memory` backend loses all data on restart
- NostrDB and LMDB backends will use `NGIT_RELAY_DATA_PATH` for storage
- NostrDB and LMDB are planned features, not yet available
- Default `memory` backend suitable for development and testing only
- Production deployments should use persistent backends when available
---
### Logging Configuration
#### `RUST_LOG`
+42
View File
@@ -2,6 +2,40 @@ use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::env;
/// Database backend type for the relay
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum DatabaseBackend {
/// In-memory database (default, fastest, no persistence)
Memory,
/// NostrDB backend (persistent, optimized for Nostr)
NostrDb,
/// LMDB backend (persistent, general purpose)
Lmdb,
}
impl Default for DatabaseBackend {
fn default() -> Self {
Self::Memory
}
}
impl std::str::FromStr for DatabaseBackend {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
match s.to_lowercase().as_str() {
"memory" => Ok(Self::Memory),
"nostrdb" => Ok(Self::NostrDb),
"lmdb" => Ok(Self::Lmdb),
_ => Err(anyhow::anyhow!(
"Invalid database backend: {}. Valid options: memory, nostrdb, lmdb",
s
)),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub domain: String,
@@ -11,6 +45,7 @@ pub struct Config {
pub git_data_path: String,
pub relay_data_path: String,
pub bind_address: String,
pub database_backend: DatabaseBackend,
}
impl Config {
@@ -18,6 +53,12 @@ impl Config {
// Load .env file if present
dotenvy::dotenv().ok();
// Parse database backend from environment
let database_backend = env::var("NGIT_DATABASE_BACKEND")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or_default();
Ok(Config {
domain: env::var("NGIT_DOMAIN").unwrap_or_else(|_| "localhost:8080".to_string()),
owner_npub: env::var("NGIT_OWNER_NPUB").context("NGIT_OWNER_NPUB must be set")?,
@@ -31,6 +72,7 @@ impl Config {
.unwrap_or_else(|_| "./data/relay".to_string()),
bind_address: env::var("NGIT_BIND_ADDRESS")
.unwrap_or_else(|_| "127.0.0.1:8080".to_string()),
database_backend,
})
}
}
+31 -9
View File
@@ -11,7 +11,7 @@ use nostr::prelude::{Alphabet, SingleLetterTag};
use nostr::{EventId, Filter, Kind, PublicKey};
use nostr_relay_builder::prelude::*;
use crate::config::Config;
use crate::config::{Config, DatabaseBackend};
use crate::nostr::events::{
validate_announcement, validate_state, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE,
};
@@ -397,14 +397,36 @@ pub fn create_relay(config: &Config) -> Result<LocalRelay> {
// Determine database path
let db_path = Path::new(&config.relay_data_path);
// Create database - using in-memory for now, can switch to persistent later
// TODO: Add configuration for NostrDB or LMDB backends
let database = Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions {
events: true,
max_events: Some(100_000),
}));
tracing::info!("Using in-memory database (path: {})", db_path.display());
// Create database based on configuration
let database = match config.database_backend {
DatabaseBackend::Memory => {
tracing::info!("Using in-memory database (no persistence)");
Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions {
events: true,
max_events: Some(100_000),
}))
}
DatabaseBackend::NostrDb => {
tracing::info!("Using NostrDB backend at: {}", db_path.display());
// TODO: Implement NostrDB backend once nostr-relay-builder supports it
// For now, fall back to memory database
tracing::warn!("NostrDB backend not yet implemented, using in-memory database");
Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions {
events: true,
max_events: Some(100_000),
}))
}
DatabaseBackend::Lmdb => {
tracing::info!("Using LMDB backend at: {}", db_path.display());
// TODO: Implement LMDB backend once nostr-relay-builder supports it
// For now, fall back to memory database
tracing::warn!("LMDB backend not yet implemented, using in-memory database");
Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions {
events: true,
max_events: Some(100_000),
}))
}
};
// Build relay with GRASP-01 validation
// Clone Arc for the write policy so both relay and policy can access the database