Merge pull request #8 from scsibug/master

Fork Sync: Update from parent repository
This commit is contained in:
PascalR 2023-07-31 10:23:58 +02:00 committed by GitHub
commit cb00b825db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 59 additions and 19 deletions

View File

@ -20,6 +20,9 @@ description = "A newly created nostr-rs-relay.\n\nCustomize this with your own i
# ICO format. # ICO format.
#favicon = "favicon.ico" #favicon = "favicon.ico"
# URL of Relay's icon.
#relay_icon = "https://example.test/img.png"
[diagnostics] [diagnostics]
# Enable tokio tracing (for use with tokio-console) # Enable tokio tracing (for use with tokio-console)
#tracing = false #tracing = false

View File

@ -112,7 +112,8 @@ seen" policy.
```console ```console
PRAGMA foreign_keys = ON; PRAGMA foreign_keys = ON;
TODO!
DELETE FROM event WHERE first_seen < CAST(strftime('%s', date('now', '-30 day')) AS INT);
``` ```
### Delete Profile Events with No Recent Events ### Delete Profile Events with No Recent Events

View File

@ -20,7 +20,7 @@ pub fn main() -> Result<()> {
let _trace_sub = tracing_subscriber::fmt::try_init(); let _trace_sub = tracing_subscriber::fmt::try_init();
println!("Nostr-rs-relay Bulk Loader"); println!("Nostr-rs-relay Bulk Loader");
// check for a database file, or create one. // check for a database file, or create one.
let settings = config::Settings::new(&None); let settings = config::Settings::new(&None)?;
if !Path::new(&settings.database.data_directory).is_dir() { if !Path::new(&settings.database.data_directory).is_dir() {
info!("Database directory does not exist"); info!("Database directory does not exist");
return Err(Error::DatabaseDirError); return Err(Error::DatabaseDirError);

View File

@ -1,10 +1,8 @@
//! Configuration file and settings management //! Configuration file and settings management
use crate::payment::Processor;
use config::{Config, ConfigError, File}; use config::{Config, ConfigError, File};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use tracing::warn;
use crate::payment::Processor;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[allow(unused)] #[allow(unused)]
@ -15,6 +13,7 @@ pub struct Info {
pub pubkey: Option<String>, pub pubkey: Option<String>,
pub contact: Option<String>, pub contact: Option<String>,
pub favicon: Option<String>, pub favicon: Option<String>,
pub relay_icon: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -192,17 +191,23 @@ pub struct Settings {
} }
impl Settings { impl Settings {
#[must_use] pub fn new(config_file_name: &Option<String>) -> Result<Self, ConfigError> {
pub fn new(config_file_name: &Option<String>) -> Self {
let default_settings = Self::default(); let default_settings = Self::default();
// attempt to construct settings with file // attempt to construct settings with file
let from_file = Self::new_from_default(&default_settings, config_file_name); let from_file = Self::new_from_default(&default_settings, config_file_name);
match from_file { match from_file {
Ok(f) => f,
Err(e) => { Err(e) => {
warn!("Error reading config file ({:?})", e); // pass up the parse error if the config file was specified,
default_settings // otherwise use the default config (with a warning).
if config_file_name.is_some() {
Err(e)
} else {
eprintln!("Error reading config file ({:?})", e);
eprintln!("WARNING: Default configuration settings will be used");
Ok(default_settings)
}
} }
ok => ok,
} }
} }
@ -268,6 +273,7 @@ impl Default for Settings {
pubkey: None, pubkey: None,
contact: None, contact: None,
favicon: None, favicon: None,
relay_icon: None,
}, },
diagnostics: Diagnostics { tracing: false }, diagnostics: Diagnostics { tracing: false },
database: Database { database: Database {

View File

@ -45,6 +45,8 @@ pub struct RelayInfo {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub contact: Option<String>, pub contact: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supported_nips: Option<Vec<i64>>, pub supported_nips: Option<Vec<i64>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub software: Option<String>, pub software: Option<String>,
@ -124,6 +126,7 @@ impl From<Settings> for RelayInfo {
limitation: Some(limitations), limitation: Some(limitations),
payment_url, payment_url,
fees, fees,
icon: i.relay_icon,
} }
} }
} }

View File

@ -4,6 +4,9 @@ use console_subscriber::ConsoleLayer;
use nostr_rs_relay::cli::CLIArgs; use nostr_rs_relay::cli::CLIArgs;
use nostr_rs_relay::config; use nostr_rs_relay::config;
use nostr_rs_relay::server::start_server; use nostr_rs_relay::server::start_server;
use std::fs;
use std::path::Path;
use std::process;
use std::sync::mpsc as syncmpsc; use std::sync::mpsc as syncmpsc;
use std::sync::mpsc::{Receiver as MpscReceiver, Sender as MpscSender}; use std::sync::mpsc::{Receiver as MpscReceiver, Sender as MpscSender};
use std::thread; use std::thread;
@ -24,11 +27,35 @@ fn main() {
// get config file name from args // get config file name from args
let config_file_arg = args.config; let config_file_arg = args.config;
// Ensure the config file is readable if it was explicitly set
if let Some(config_path) = config_file_arg.as_ref() {
let path = Path::new(&config_path);
if !path.exists() {
eprintln!("Config file not found: {}", &config_path);
process::exit(1);
}
if !path.is_file() {
eprintln!("Invalid config file path: {}", &config_path);
process::exit(1);
}
if let Err(err) = fs::metadata(path) {
eprintln!("Error while accessing file metadata: {}", err);
process::exit(1);
}
if let Err(err) = fs::File::open(path) {
eprintln!("Config file is not readable: {}", err);
process::exit(1);
}
}
let mut _log_guard: Option<WorkerGuard> = None; let mut _log_guard: Option<WorkerGuard> = None;
// configure settings from the config file (defaults to config.toml) // configure settings from the config file (defaults to config.toml)
// replace default settings with those read from the config file // replace default settings with those read from the config file
let mut settings = config::Settings::new(&config_file_arg); let mut settings = config::Settings::new(&config_file_arg).unwrap_or_else(|e| {
eprintln!("Error reading config file ({:?})", e);
process::exit(1);
});
// setup tracing // setup tracing
if settings.diagnostics.tracing { if settings.diagnostics.tracing {

View File

@ -904,7 +904,7 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
} }
push_and = true; push_and = true;
query query
.push("e.created_at > ") .push("e.created_at >= ")
.push_bind(Utc.timestamp_opt(f.since.unwrap() as i64, 0).unwrap()); .push_bind(Utc.timestamp_opt(f.since.unwrap() as i64, 0).unwrap());
} }
@ -915,7 +915,7 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
} }
push_and = true; push_and = true;
query query
.push("e.created_at < ") .push("e.created_at <= ")
.push_bind(Utc.timestamp_opt(f.until.unwrap() as i64, 0).unwrap()); .push_bind(Utc.timestamp_opt(f.until.unwrap() as i64, 0).unwrap());
} }

View File

@ -1083,13 +1083,13 @@ fn query_from_filter(f: &ReqFilter) -> (String, Vec<Box<dyn ToSql>>, Option<Stri
kind_clause = String::new(); kind_clause = String::new();
}; };
if f.since.is_some() { if f.since.is_some() {
since_clause = format!("AND created_at > {}", f.since.unwrap()); since_clause = format!("AND created_at >= {}", f.since.unwrap());
} else { } else {
since_clause = String::new(); since_clause = String::new();
}; };
// Query for timestamp // Query for timestamp
if f.until.is_some() { if f.until.is_some() {
until_clause = format!("AND created_at < {}", f.until.unwrap()); until_clause = format!("AND created_at <= {}", f.until.unwrap());
} else { } else {
until_clause = String::new(); until_clause = String::new();
}; };
@ -1107,12 +1107,12 @@ fn query_from_filter(f: &ReqFilter) -> (String, Vec<Box<dyn ToSql>>, Option<Stri
} }
// Query for timestamp // Query for timestamp
if f.since.is_some() { if f.since.is_some() {
let created_clause = format!("created_at > {}", f.since.unwrap()); let created_clause = format!("created_at >= {}", f.since.unwrap());
filter_components.push(created_clause); filter_components.push(created_clause);
} }
// Query for timestamp // Query for timestamp
if f.until.is_some() { if f.until.is_some() {
let until_clause = format!("created_at < {}", f.until.unwrap()); let until_clause = format!("created_at <= {}", f.until.unwrap());
filter_components.push(until_clause); filter_components.push(until_clause);
} }
// never display hidden events // never display hidden events

View File

@ -319,8 +319,8 @@ impl ReqFilter {
pub fn interested_in_event(&self, event: &Event) -> bool { pub fn interested_in_event(&self, event: &Event) -> bool {
// self.id.as_ref().map(|v| v == &event.id).unwrap_or(true) // self.id.as_ref().map(|v| v == &event.id).unwrap_or(true)
self.ids_match(event) self.ids_match(event)
&& self.since.map_or(true, |t| event.created_at > t) && self.since.map_or(true, |t| event.created_at >= t)
&& self.until.map_or(true, |t| event.created_at < t) && self.until.map_or(true, |t| event.created_at <= t)
&& self.kind_match(event.kind) && self.kind_match(event.kind)
&& (self.authors_match(event) || self.delegated_authors_match(event)) && (self.authors_match(event) || self.delegated_authors_match(event))
&& self.tag_match(event) && self.tag_match(event)