diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/git/authorization.rs | 12 | ||||
| -rw-r--r-- | src/git/handlers.rs | 7 | ||||
| -rw-r--r-- | src/http/mod.rs | 9 | ||||
| -rw-r--r-- | src/nostr/builder.rs | 56 |
4 files changed, 48 insertions, 36 deletions
diff --git a/src/git/authorization.rs b/src/git/authorization.rs index 3b0e759..4896fc0 100644 --- a/src/git/authorization.rs +++ b/src/git/authorization.rs | |||
| @@ -31,9 +31,9 @@ use anyhow::{anyhow, Result}; | |||
| 31 | use nostr_relay_builder::prelude::*; | 31 | use nostr_relay_builder::prelude::*; |
| 32 | use nostr_sdk::{EventId, ToBech32}; | 32 | use nostr_sdk::{EventId, ToBech32}; |
| 33 | use std::collections::{HashMap, HashSet}; | 33 | use std::collections::{HashMap, HashSet}; |
| 34 | use std::sync::Arc; | ||
| 35 | use tracing::debug; | 34 | use tracing::debug; |
| 36 | 35 | ||
| 36 | use crate::nostr::builder::SharedDatabase; | ||
| 37 | use crate::nostr::events::{ | 37 | use crate::nostr::events::{ |
| 38 | RepositoryAnnouncement, RepositoryState, KIND_PR, KIND_PR_UPDATE, KIND_REPOSITORY_ANNOUNCEMENT, | 38 | RepositoryAnnouncement, RepositoryState, KIND_PR, KIND_PR_UPDATE, KIND_REPOSITORY_ANNOUNCEMENT, |
| 39 | KIND_REPOSITORY_STATE, | 39 | KIND_REPOSITORY_STATE, |
| @@ -56,7 +56,7 @@ pub struct RepositoryData { | |||
| 56 | /// This performs a single database query to fetch both announcement and state events, | 56 | /// This performs a single database query to fetch both announcement and state events, |
| 57 | /// which is more efficient than separate queries. | 57 | /// which is more efficient than separate queries. |
| 58 | pub async fn fetch_repository_data( | 58 | pub async fn fetch_repository_data( |
| 59 | database: &Arc<MemoryDatabase>, | 59 | database: &SharedDatabase, |
| 60 | identifier: &str, | 60 | identifier: &str, |
| 61 | ) -> Result<RepositoryData> { | 61 | ) -> Result<RepositoryData> { |
| 62 | let filter = Filter::new() | 62 | let filter = Filter::new() |
| @@ -284,7 +284,7 @@ pub fn is_latest_state( | |||
| 284 | /// | 284 | /// |
| 285 | /// Returns an `AuthorizationResult` that indicates whether a push is authorized. | 285 | /// Returns an `AuthorizationResult` that indicates whether a push is authorized. |
| 286 | pub async fn get_authorization_from_db( | 286 | pub async fn get_authorization_from_db( |
| 287 | database: &Arc<MemoryDatabase>, | 287 | database: &SharedDatabase, |
| 288 | identifier: &str, | 288 | identifier: &str, |
| 289 | ) -> Result<AuthorizationResult> { | 289 | ) -> Result<AuthorizationResult> { |
| 290 | // Fetch all repository data with a single query | 290 | // Fetch all repository data with a single query |
| @@ -340,7 +340,7 @@ pub async fn get_authorization_from_db( | |||
| 340 | /// | 340 | /// |
| 341 | /// Returns an `AuthorizationResult` that indicates whether a push is authorized. | 341 | /// Returns an `AuthorizationResult` that indicates whether a push is authorized. |
| 342 | pub async fn get_authorization_for_owner( | 342 | pub async fn get_authorization_for_owner( |
| 343 | database: &Arc<MemoryDatabase>, | 343 | database: &SharedDatabase, |
| 344 | identifier: &str, | 344 | identifier: &str, |
| 345 | owner_pubkey: &str, | 345 | owner_pubkey: &str, |
| 346 | ) -> Result<AuthorizationResult> { | 346 | ) -> Result<AuthorizationResult> { |
| @@ -817,7 +817,7 @@ pub fn npub_to_pubkey(npub: &str) -> Result<String> { | |||
| 817 | /// - `Ok(None)` if the event doesn't exist (push should be allowed) | 817 | /// - `Ok(None)` if the event doesn't exist (push should be allowed) |
| 818 | /// - `Err(_)` on database errors | 818 | /// - `Err(_)` on database errors |
| 819 | pub async fn get_event_commit_tag( | 819 | pub async fn get_event_commit_tag( |
| 820 | database: &Arc<MemoryDatabase>, | 820 | database: &SharedDatabase, |
| 821 | event_id: &EventId, | 821 | event_id: &EventId, |
| 822 | ) -> Result<Option<String>> { | 822 | ) -> Result<Option<String>> { |
| 823 | // Query for PR (1618) and PR Update (1619) events with this ID | 823 | // Query for PR (1618) and PR Update (1619) events with this ID |
| @@ -872,7 +872,7 @@ pub async fn get_event_commit_tag( | |||
| 872 | /// * `Ok(())` if all refs/nostr/ pushes are valid | 872 | /// * `Ok(())` if all refs/nostr/ pushes are valid |
| 873 | /// * `Err(_)` if any ref has invalid event ID format or fails commit validation | 873 | /// * `Err(_)` if any ref has invalid event ID format or fails commit validation |
| 874 | pub async fn validate_nostr_ref_pushes( | 874 | pub async fn validate_nostr_ref_pushes( |
| 875 | database: &Arc<MemoryDatabase>, | 875 | database: &SharedDatabase, |
| 876 | pushed_refs: &[(String, String, String)], | 876 | pushed_refs: &[(String, String, String)], |
| 877 | ) -> Result<()> { | 877 | ) -> Result<()> { |
| 878 | for (_, new_oid, ref_name) in pushed_refs { | 878 | for (_, new_oid, ref_name) in pushed_refs { |
diff --git a/src/git/handlers.rs b/src/git/handlers.rs index e84cabb..8e5f5e1 100644 --- a/src/git/handlers.rs +++ b/src/git/handlers.rs | |||
| @@ -4,9 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use http_body_util::Full; | 5 | use http_body_util::Full; |
| 6 | use hyper::{body::Bytes, Response, StatusCode}; | 6 | use hyper::{body::Bytes, Response, StatusCode}; |
| 7 | use nostr_relay_builder::prelude::MemoryDatabase; | ||
| 8 | use std::path::PathBuf; | 7 | use std::path::PathBuf; |
| 9 | use std::sync::Arc; | ||
| 10 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; | 8 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
| 11 | use tracing::{debug, error, info, warn}; | 9 | use tracing::{debug, error, info, warn}; |
| 12 | 10 | ||
| @@ -18,6 +16,7 @@ use super::protocol::{GitService, PktLine}; | |||
| 18 | use super::subprocess::GitSubprocess; | 16 | use super::subprocess::GitSubprocess; |
| 19 | use super::try_set_head_if_available; | 17 | use super::try_set_head_if_available; |
| 20 | 18 | ||
| 19 | use crate::nostr::builder::SharedDatabase; | ||
| 21 | use crate::nostr::events::RepositoryState; | 20 | use crate::nostr::events::RepositoryState; |
| 22 | 21 | ||
| 23 | /// Handle GET /info/refs?service=git-{upload,receive}-pack | 22 | /// Handle GET /info/refs?service=git-{upload,receive}-pack |
| @@ -178,7 +177,7 @@ pub async fn handle_upload_pack( | |||
| 178 | pub async fn handle_receive_pack( | 177 | pub async fn handle_receive_pack( |
| 179 | repo_path: PathBuf, | 178 | repo_path: PathBuf, |
| 180 | request_body: Bytes, | 179 | request_body: Bytes, |
| 181 | database: Option<Arc<MemoryDatabase>>, | 180 | database: Option<SharedDatabase>, |
| 182 | identifier: &str, | 181 | identifier: &str, |
| 183 | owner_pubkey: &str, | 182 | owner_pubkey: &str, |
| 184 | ) -> Result<Response<Full<Bytes>>, GitError> { | 183 | ) -> Result<Response<Full<Bytes>>, GitError> { |
| @@ -310,7 +309,7 @@ pub async fn handle_receive_pack( | |||
| 310 | /// 5. Validates that pushed refs match the state | 309 | /// 5. Validates that pushed refs match the state |
| 311 | /// 6. Validates refs/nostr/<event-id> has valid event id and if event exists, `c` tag matches ref | 310 | /// 6. Validates refs/nostr/<event-id> has valid event id and if event exists, `c` tag matches ref |
| 312 | async fn authorize_push( | 311 | async fn authorize_push( |
| 313 | database: &Arc<MemoryDatabase>, | 312 | database: &SharedDatabase, |
| 314 | identifier: &str, | 313 | identifier: &str, |
| 315 | owner_pubkey: &str, | 314 | owner_pubkey: &str, |
| 316 | request_body: &Bytes, | 315 | request_body: &Bytes, |
diff --git a/src/http/mod.rs b/src/http/mod.rs index 5cf8dbe..4665281 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs | |||
| @@ -7,7 +7,6 @@ pub mod nip11; | |||
| 7 | use std::future::Future; | 7 | use std::future::Future; |
| 8 | use std::net::SocketAddr; | 8 | use std::net::SocketAddr; |
| 9 | use std::pin::Pin; | 9 | use std::pin::Pin; |
| 10 | use std::sync::Arc; | ||
| 11 | 10 | ||
| 12 | use base64::Engine; | 11 | use base64::Engine; |
| 13 | use http_body_util::{BodyExt, Full}; | 12 | use http_body_util::{BodyExt, Full}; |
| @@ -17,7 +16,6 @@ use hyper::server::conn::http1; | |||
| 17 | use hyper::service::Service; | 16 | use hyper::service::Service; |
| 18 | use hyper::{Method, Request, Response}; | 17 | use hyper::{Method, Request, Response}; |
| 19 | use hyper_util::rt::TokioIo; | 18 | use hyper_util::rt::TokioIo; |
| 20 | use nostr_relay_builder::prelude::MemoryDatabase; | ||
| 21 | use nostr_relay_builder::LocalRelay; | 19 | use nostr_relay_builder::LocalRelay; |
| 22 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; | 20 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; |
| 23 | use nostr_sdk::hashes::{Hash, HashEngine}; | 21 | use nostr_sdk::hashes::{Hash, HashEngine}; |
| @@ -26,6 +24,7 @@ use tokio::net::TcpListener; | |||
| 26 | 24 | ||
| 27 | use crate::config::Config; | 25 | use crate::config::Config; |
| 28 | use crate::git; | 26 | use crate::git; |
| 27 | use crate::nostr::builder::SharedDatabase; | ||
| 29 | 28 | ||
| 30 | /// CORS headers required by GRASP-01 specification (lines 40-47) | 29 | /// CORS headers required by GRASP-01 specification (lines 40-47) |
| 31 | const CORS_ALLOW_ORIGIN: &str = "*"; | 30 | const CORS_ALLOW_ORIGIN: &str = "*"; |
| @@ -90,7 +89,7 @@ struct HttpService { | |||
| 90 | config: Config, | 89 | config: Config, |
| 91 | remote: SocketAddr, | 90 | remote: SocketAddr, |
| 92 | /// Database reference for direct queries (e.g., push authorization) | 91 | /// Database reference for direct queries (e.g., push authorization) |
| 93 | database: Arc<MemoryDatabase>, | 92 | database: SharedDatabase, |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | impl HttpService { | 95 | impl HttpService { |
| @@ -98,7 +97,7 @@ impl HttpService { | |||
| 98 | relay: LocalRelay, | 97 | relay: LocalRelay, |
| 99 | config: Config, | 98 | config: Config, |
| 100 | remote: SocketAddr, | 99 | remote: SocketAddr, |
| 101 | database: Arc<MemoryDatabase>, | 100 | database: SharedDatabase, |
| 102 | ) -> Self { | 101 | ) -> Self { |
| 103 | Self { | 102 | Self { |
| 104 | relay, | 103 | relay, |
| @@ -423,7 +422,7 @@ fn derive_accept_key(request_key: &[u8]) -> String { | |||
| 423 | pub async fn run_server( | 422 | pub async fn run_server( |
| 424 | config: Config, | 423 | config: Config, |
| 425 | relay: LocalRelay, | 424 | relay: LocalRelay, |
| 426 | database: Arc<MemoryDatabase>, | 425 | database: SharedDatabase, |
| 427 | ) -> anyhow::Result<()> { | 426 | ) -> anyhow::Result<()> { |
| 428 | let bind_addr: SocketAddr = config.bind_address.parse()?; | 427 | let bind_addr: SocketAddr = config.bind_address.parse()?; |
| 429 | 428 | ||
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs index 2f182ea..eabb38f 100644 --- a/src/nostr/builder.rs +++ b/src/nostr/builder.rs | |||
| @@ -9,6 +9,7 @@ use std::sync::Arc; | |||
| 9 | use nostr::nips::nip19::ToBech32; | 9 | use nostr::nips::nip19::ToBech32; |
| 10 | use nostr::prelude::{Alphabet, SingleLetterTag}; | 10 | use nostr::prelude::{Alphabet, SingleLetterTag}; |
| 11 | use nostr::{EventId, Filter, Kind, PublicKey}; | 11 | use nostr::{EventId, Filter, Kind, PublicKey}; |
| 12 | use nostr_lmdb::NostrLMDB; | ||
| 12 | use nostr_relay_builder::prelude::*; | 13 | use nostr_relay_builder::prelude::*; |
| 13 | 14 | ||
| 14 | use crate::config::{Config, DatabaseBackend}; | 15 | use crate::config::{Config, DatabaseBackend}; |
| @@ -18,6 +19,9 @@ use crate::nostr::events::{ | |||
| 18 | KIND_PR_UPDATE, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE, | 19 | KIND_PR_UPDATE, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE, |
| 19 | }; | 20 | }; |
| 20 | 21 | ||
| 22 | /// Type alias for the shared database used by the relay | ||
| 23 | pub type SharedDatabase = Arc<dyn NostrDatabase>; | ||
| 24 | |||
| 21 | /// Result of aligning a repository with authorized state | 25 | /// Result of aligning a repository with authorized state |
| 22 | #[derive(Debug, Default)] | 26 | #[derive(Debug, Default)] |
| 23 | struct AlignmentResult { | 27 | struct AlignmentResult { |
| @@ -35,23 +39,33 @@ struct AlignmentResult { | |||
| 35 | /// | 39 | /// |
| 36 | /// Validates all events according to GRASP-01 specification: | 40 | /// Validates all events according to GRASP-01 specification: |
| 37 | /// - Repository announcements must list service in clone and relays tags | 41 | /// - Repository announcements must list service in clone and relays tags |
| 38 | /// - Repository state announcements must have valid structure | 42 | /// - Repository state announcements must have valid structure |
| 39 | /// - Other events must reference accepted repositories or events | 43 | /// - Other events must reference accepted repositories or events |
| 40 | /// - Forward references are supported (events referenced by accepted events) | 44 | /// - Forward references are supported (events referenced by accepted events) |
| 41 | /// - Orphan events with no valid references are rejected | 45 | /// - Orphan events with no valid references are rejected |
| 42 | /// | 46 | /// |
| 43 | /// Uses stateful database queries to check event relationships. | 47 | /// Uses stateful database queries to check event relationships. |
| 44 | #[derive(Debug, Clone)] | 48 | #[derive(Clone)] |
| 45 | pub struct Nip34WritePolicy { | 49 | pub struct Nip34WritePolicy { |
| 46 | domain: String, | 50 | domain: String, |
| 47 | database: Arc<MemoryDatabase>, | 51 | database: SharedDatabase, |
| 48 | git_data_path: PathBuf, | 52 | git_data_path: PathBuf, |
| 49 | } | 53 | } |
| 50 | 54 | ||
| 55 | impl std::fmt::Debug for Nip34WritePolicy { | ||
| 56 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| 57 | f.debug_struct("Nip34WritePolicy") | ||
| 58 | .field("domain", &self.domain) | ||
| 59 | .field("git_data_path", &self.git_data_path) | ||
| 60 | .field("database", &"<database>") | ||
| 61 | .finish() | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 51 | impl Nip34WritePolicy { | 65 | impl Nip34WritePolicy { |
| 52 | pub fn new( | 66 | pub fn new( |
| 53 | domain: impl Into<String>, | 67 | domain: impl Into<String>, |
| 54 | database: Arc<MemoryDatabase>, | 68 | database: SharedDatabase, |
| 55 | git_data_path: impl Into<PathBuf>, | 69 | git_data_path: impl Into<PathBuf>, |
| 56 | ) -> Self { | 70 | ) -> Self { |
| 57 | Self { | 71 | Self { |
| @@ -104,7 +118,7 @@ impl Nip34WritePolicy { | |||
| 104 | /// The authorized_pubkeys should be the owner and maintainers of a specific | 118 | /// The authorized_pubkeys should be the owner and maintainers of a specific |
| 105 | /// announcement, so different owners with the same identifier don't interfere. | 119 | /// announcement, so different owners with the same identifier don't interfere. |
| 106 | async fn is_latest_state_for_identifier( | 120 | async fn is_latest_state_for_identifier( |
| 107 | database: &Arc<MemoryDatabase>, | 121 | database: &SharedDatabase, |
| 108 | state: &RepositoryState, | 122 | state: &RepositoryState, |
| 109 | authorized_pubkeys: &[PublicKey], | 123 | authorized_pubkeys: &[PublicKey], |
| 110 | ) -> Result<bool, String> { | 124 | ) -> Result<bool, String> { |
| @@ -155,7 +169,7 @@ impl Nip34WritePolicy { | |||
| 155 | /// should update HEAD in the repository of the announcement owner, | 169 | /// should update HEAD in the repository of the announcement owner, |
| 156 | /// not in the maintainer's own (possibly non-existent) repository. | 170 | /// not in the maintainer's own (possibly non-existent) repository. |
| 157 | async fn find_authorized_announcements( | 171 | async fn find_authorized_announcements( |
| 158 | database: &Arc<MemoryDatabase>, | 172 | database: &SharedDatabase, |
| 159 | identifier: &str, | 173 | identifier: &str, |
| 160 | state_author: &PublicKey, | 174 | state_author: &PublicKey, |
| 161 | ) -> Result<Vec<RepositoryAnnouncement>, String> { | 175 | ) -> Result<Vec<RepositoryAnnouncement>, String> { |
| @@ -205,7 +219,7 @@ impl Nip34WritePolicy { | |||
| 205 | /// - This state event is the latest for the identifier in that context | 219 | /// - This state event is the latest for the identifier in that context |
| 206 | async fn identify_owner_repositories( | 220 | async fn identify_owner_repositories( |
| 207 | &self, | 221 | &self, |
| 208 | database: &Arc<MemoryDatabase>, | 222 | database: &SharedDatabase, |
| 209 | state: &RepositoryState, | 223 | state: &RepositoryState, |
| 210 | ) -> Result<Vec<(RepositoryAnnouncement, std::path::PathBuf)>, String> { | 224 | ) -> Result<Vec<(RepositoryAnnouncement, std::path::PathBuf)>, String> { |
| 211 | // Find all announcements where state author is authorized | 225 | // Find all announcements where state author is authorized |
| @@ -485,7 +499,7 @@ impl Nip34WritePolicy { | |||
| 485 | /// Ok(Some(n)) if n refs were deleted, Ok(None) if no action taken, Err on failure | 499 | /// Ok(Some(n)) if n refs were deleted, Ok(None) if no action taken, Err on failure |
| 486 | async fn validate_pr_nostr_ref( | 500 | async fn validate_pr_nostr_ref( |
| 487 | &self, | 501 | &self, |
| 488 | database: &Arc<MemoryDatabase>, | 502 | database: &SharedDatabase, |
| 489 | event: &Event, | 503 | event: &Event, |
| 490 | ) -> Result<Option<usize>, String> { | 504 | ) -> Result<Option<usize>, String> { |
| 491 | let event_id = event.id.to_hex(); | 505 | let event_id = event.id.to_hex(); |
| @@ -651,7 +665,7 @@ impl Nip34WritePolicy { | |||
| 651 | /// Check if any addressable events (repositories) exist in database | 665 | /// Check if any addressable events (repositories) exist in database |
| 652 | /// Returns the first matching addressable reference found, or None if none match | 666 | /// Returns the first matching addressable reference found, or None if none match |
| 653 | async fn find_accepted_repository( | 667 | async fn find_accepted_repository( |
| 654 | database: &Arc<MemoryDatabase>, | 668 | database: &SharedDatabase, |
| 655 | addressables: &[String], | 669 | addressables: &[String], |
| 656 | ) -> Result<Option<String>, String> { | 670 | ) -> Result<Option<String>, String> { |
| 657 | if addressables.is_empty() { | 671 | if addressables.is_empty() { |
| @@ -724,7 +738,7 @@ impl Nip34WritePolicy { | |||
| 724 | /// Check if any events exist in database | 738 | /// Check if any events exist in database |
| 725 | /// Returns the first matching event ID found, or None if none match | 739 | /// Returns the first matching event ID found, or None if none match |
| 726 | async fn find_accepted_event( | 740 | async fn find_accepted_event( |
| 727 | database: &Arc<MemoryDatabase>, | 741 | database: &SharedDatabase, |
| 728 | event_ids: &[EventId], | 742 | event_ids: &[EventId], |
| 729 | ) -> Result<Option<EventId>, String> { | 743 | ) -> Result<Option<EventId>, String> { |
| 730 | if event_ids.is_empty() { | 744 | if event_ids.is_empty() { |
| @@ -752,7 +766,7 @@ impl Nip34WritePolicy { | |||
| 752 | /// This optimization recognizes that replaceable events are referenced by coordinate address, | 766 | /// This optimization recognizes that replaceable events are referenced by coordinate address, |
| 753 | /// while regular events are referenced by event ID. | 767 | /// while regular events are referenced by event ID. |
| 754 | async fn is_referenced_by_accepted( | 768 | async fn is_referenced_by_accepted( |
| 755 | database: &Arc<MemoryDatabase>, | 769 | database: &SharedDatabase, |
| 756 | event: &Event, | 770 | event: &Event, |
| 757 | ) -> Result<bool, String> { | 771 | ) -> Result<bool, String> { |
| 758 | let kind_u16 = event.kind.as_u16(); | 772 | let kind_u16 = event.kind.as_u16(); |
| @@ -1152,14 +1166,14 @@ pub struct RelayWithDatabase { | |||
| 1152 | /// The local relay instance | 1166 | /// The local relay instance |
| 1153 | pub relay: LocalRelay, | 1167 | pub relay: LocalRelay, |
| 1154 | /// The database Arc that can be used for direct queries | 1168 | /// The database Arc that can be used for direct queries |
| 1155 | pub database: Arc<MemoryDatabase>, | 1169 | pub database: SharedDatabase, |
| 1156 | } | 1170 | } |
| 1157 | 1171 | ||
| 1158 | /// Create a configured LocalRelay with full GRASP-01 validation | 1172 | /// Create a configured LocalRelay with full GRASP-01 validation |
| 1159 | /// | 1173 | /// |
| 1160 | /// Returns a `RelayWithDatabase` struct containing: | 1174 | /// Returns a `RelayWithDatabase` struct containing: |
| 1161 | /// - The `LocalRelay` for handling WebSocket connections | 1175 | /// - The `LocalRelay` for handling WebSocket connections |
| 1162 | /// - The `Arc<MemoryDatabase>` for direct database queries (e.g., push authorization) | 1176 | /// - The `SharedDatabase` for direct database queries (e.g., push authorization) |
| 1163 | pub fn create_relay(config: &Config) -> Result<RelayWithDatabase> { | 1177 | pub fn create_relay(config: &Config) -> Result<RelayWithDatabase> { |
| 1164 | tracing::info!("Configuring nostr relay with GRASP-01 validation..."); | 1178 | tracing::info!("Configuring nostr relay with GRASP-01 validation..."); |
| 1165 | 1179 | ||
| @@ -1167,7 +1181,7 @@ pub fn create_relay(config: &Config) -> Result<RelayWithDatabase> { | |||
| 1167 | let db_path = Path::new(&config.relay_data_path); | 1181 | let db_path = Path::new(&config.relay_data_path); |
| 1168 | 1182 | ||
| 1169 | // Create database based on configuration | 1183 | // Create database based on configuration |
| 1170 | let database = match config.database_backend { | 1184 | let database: SharedDatabase = match config.database_backend { |
| 1171 | DatabaseBackend::Memory => { | 1185 | DatabaseBackend::Memory => { |
| 1172 | tracing::info!("Using in-memory database (no persistence)"); | 1186 | tracing::info!("Using in-memory database (no persistence)"); |
| 1173 | Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions { | 1187 | Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions { |
| @@ -1187,13 +1201,13 @@ pub fn create_relay(config: &Config) -> Result<RelayWithDatabase> { | |||
| 1187 | } | 1201 | } |
| 1188 | DatabaseBackend::Lmdb => { | 1202 | DatabaseBackend::Lmdb => { |
| 1189 | tracing::info!("Using LMDB backend at: {}", db_path.display()); | 1203 | tracing::info!("Using LMDB backend at: {}", db_path.display()); |
| 1190 | // TODO: Implement LMDB backend once nostr-relay-builder supports it | 1204 | // Ensure the database directory exists |
| 1191 | // For now, fall back to memory database | 1205 | std::fs::create_dir_all(db_path).map_err(|e| { |
| 1192 | tracing::warn!("LMDB backend not yet implemented, using in-memory database"); | 1206 | anyhow::anyhow!("Failed to create LMDB directory {}: {}", db_path.display(), e) |
| 1193 | Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions { | 1207 | })?; |
| 1194 | events: true, | 1208 | Arc::new(NostrLMDB::open(db_path).map_err(|e| { |
| 1195 | max_events: Some(100_000), | 1209 | anyhow::anyhow!("Failed to open LMDB database at {}: {}", db_path.display(), e) |
| 1196 | })) | 1210 | })?) |
| 1197 | } | 1211 | } |
| 1198 | }; | 1212 | }; |
| 1199 | 1213 | ||