1
0
mirror of https://github.com/scsibug/nostr-rs-relay.git synced 2025-03-16 18:10:28 -04:00

482 lines
19 KiB
Rust
Raw Normal View History

2021-12-11 21:43:41 -06:00
//! Event persistence and querying
use crate::config::Settings;
use crate::error::{Error, Result};
use crate::event::Event;
2023-02-25 14:49:35 -06:00
use crate::nauthz;
use crate::notice::Notice;
use crate::payment::PaymentMessage;
2023-02-08 10:55:17 -05:00
use crate::repo::postgres::{PostgresPool, PostgresRepo};
use crate::repo::sqlite::SqliteRepo;
use crate::repo::NostrRepo;
use crate::server::NostrMetrics;
use governor::clock::Clock;
use governor::{Quota, RateLimiter};
improvement: upgrade multiple dependencies Adding addr2line v0.20.0 Updating aes v0.8.2 -> v0.8.3 Adding ahash v0.8.3 Updating aho-corasick v0.7.20 -> v1.0.2 Adding allocator-api2 v0.2.16 Adding android-tzdata v0.1.1 Adding anstream v0.3.2 Adding anstyle v1.0.1 Adding anstyle-parse v0.2.1 Adding anstyle-query v1.0.0 Adding anstyle-wincon v1.0.1 Updating anyhow v1.0.69 -> v1.0.72 Updating async-channel v1.8.0 -> v1.9.0 Updating async-executor v1.5.0 -> v1.5.1 Updating async-io v1.12.0 -> v1.13.0 Updating async-lock v2.6.0 -> v2.7.0 Updating async-stream v0.3.3 -> v0.3.5 Updating async-stream-impl v0.3.3 -> v0.3.5 Updating async-task v4.3.0 -> v4.4.0 Updating async-trait v0.1.64 -> v0.1.72 Updating atomic-waker v1.1.0 -> v1.1.1 Updating axum v0.6.6 -> v0.6.20 Updating axum-core v0.3.2 -> v0.3.4 Adding backtrace v0.3.68 Updating base64 v0.21.0 -> v0.21.2 Adding bitflags v2.3.3 Updating block-buffer v0.10.3 -> v0.10.4 Updating block-padding v0.3.2 -> v0.3.3 Updating blocking v1.3.0 -> v1.3.1 Updating bumpalo v3.12.0 -> v3.13.0 Updating cc v1.0.79 -> v1.0.81 Updating chrono v0.4.23 -> v0.4.26 Updating cipher v0.4.3 -> v0.4.4 Updating clap v4.1.4 -> v4.3.19 Adding clap_builder v4.3.19 Updating clap_derive v4.1.0 -> v4.3.12 Updating clap_lex v0.3.1 -> v0.5.0 Removing codespan-reporting v0.11.1 Adding colorchoice v1.0.0 Updating concurrent-queue v2.1.0 -> v2.2.0 Updating console v0.15.5 -> v0.15.7 Updating console-api v0.4.0 -> v0.5.0 Updating console-subscriber v0.1.8 -> v0.1.10 Updating const_format v0.2.30 -> v0.2.31 Updating const_format_proc_macros v0.2.29 -> v0.2.31 Updating core-foundation-sys v0.8.3 -> v0.8.4 Updating cpufeatures v0.2.5 -> v0.2.9 Updating crossbeam-channel v0.5.6 -> v0.5.8 Updating crossbeam-utils v0.8.14 -> v0.8.16 Removing ctor v0.1.26 Removing cxx v1.0.90 Removing cxx-build v1.0.90 Removing cxxbridge-flags v1.0.90 Removing cxxbridge-macro v1.0.90 Updating dashmap v5.4.0 -> v5.5.0 Adding deranged v0.3.7 Updating digest v0.10.6 -> v0.10.7 Updating dotenvy v0.15.6 -> v0.15.7 Updating either v1.8.1 -> v1.9.0 Adding equivalent v1.0.1 Updating errno v0.2.8 -> v0.3.2 Removing fastrand v1.8.0 Adding fastrand v1.9.0 Adding fastrand v2.0.0 Updating flate2 v1.0.25 -> v1.0.26 Updating form_urlencoded v1.1.0 -> v1.2.0 Updating futures v0.3.26 -> v0.3.28 Updating futures-channel v0.3.26 -> v0.3.28 Updating futures-core v0.3.26 -> v0.3.28 Updating futures-executor v0.3.26 -> v0.3.28 Updating futures-io v0.3.26 -> v0.3.28 Updating futures-lite v1.12.0 -> v1.13.0 Updating futures-macro v0.3.26 -> v0.3.28 Updating futures-sink v0.3.26 -> v0.3.28 Updating futures-task v0.3.26 -> v0.3.28 Updating futures-util v0.3.26 -> v0.3.28 Updating generic-array v0.14.6 -> v0.14.7 Updating getrandom v0.2.8 -> v0.2.10 Adding gimli v0.27.3 Updating h2 v0.3.15 -> v0.3.20 Adding hashbrown v0.14.0 Updating hashlink v0.8.1 -> v0.8.3 Removing hermit-abi v0.2.6 Removing hermit-abi v0.3.1 Adding hermit-abi v0.3.2 Updating http v0.2.8 -> v0.2.9 Removing http-range-header v0.3.0 Updating hyper v0.14.24 -> v0.14.27 Updating iana-time-zone v0.1.53 -> v0.1.57 Updating iana-time-zone-haiku v0.1.1 -> v0.1.2 Updating idna v0.3.0 -> v0.4.0 Removing indexmap v1.9.2 Adding indexmap v1.9.3 Adding indexmap v2.0.0 Updating indicatif v0.17.3 -> v0.17.6 Updating io-lifetimes v1.0.5 -> v1.0.11 Updating is-terminal v0.4.3 -> v0.4.9 Updating itoa v1.0.5 -> v1.0.9 Updating js-sys v0.3.61 -> v0.3.64 Updating libc v0.2.139 -> v0.2.147 Removing link-cplusplus v1.0.8 Removing linux-raw-sys v0.1.4 Adding linux-raw-sys v0.3.8 Adding linux-raw-sys v0.4.5 Updating lock_api v0.4.9 -> v0.4.10 Updating log v0.4.17 -> v0.4.19 Updating matchit v0.7.0 -> v0.7.2 Updating mime v0.3.16 -> v0.3.17 Updating miniz_oxide v0.6.2 -> v0.7.1 Updating mio v0.8.5 -> v0.8.8 Updating nostr v0.18.0 -> v0.18.1 Updating nostr-rs-relay v0.8.9 -> v0.8.10 Updating num-traits v0.2.15 -> v0.2.16 Updating num_cpus v1.15.0 -> v1.16.0 Adding object v0.31.1 Updating once_cell v1.17.0 -> v1.18.0 Updating openssl v0.10.45 -> v0.10.55 Updating openssl-macros v0.1.0 -> v0.1.1 Updating openssl-sys v0.9.80 -> v0.9.90 Removing os_str_bytes v6.4.1 Updating parking v2.0.0 -> v2.1.0 Updating parking_lot_core v0.9.7 -> v0.9.8 Updating paste v1.0.11 -> v1.0.14 Updating percent-encoding v2.2.0 -> v2.3.0 Updating pest v2.5.5 -> v2.7.2 Updating pest_derive v2.5.5 -> v2.7.2 Updating pest_generator v2.5.5 -> v2.7.2 Updating pest_meta v2.5.5 -> v2.7.2 Updating pin-project v1.0.12 -> v1.1.2 Updating pin-project-internal v1.0.12 -> v1.1.2 Updating pin-project-lite v0.2.9 -> v0.2.10 Updating pkg-config v0.3.26 -> v0.3.27 Updating polling v2.5.2 -> v2.8.0 Updating portable-atomic v0.3.19 -> v1.4.2 Updating prettyplease v0.1.23 -> v0.1.25 Removing proc-macro-error v1.0.4 Removing proc-macro-error-attr v1.0.4 Updating proc-macro2 v1.0.51 -> v1.0.66 Updating prost v0.11.6 -> v0.11.9 Updating prost-build v0.11.6 -> v0.11.9 Updating prost-derive v0.11.6 -> v0.11.9 Updating prost-types v0.11.6 -> v0.11.9 Updating quote v1.0.23 -> v1.0.32 Updating raw-cpuid v10.6.1 -> v10.7.0 Adding redox_syscall v0.3.5 Updating regex v1.7.1 -> v1.9.1 Adding regex-automata v0.3.4 Removing regex-syntax v0.6.28 Adding regex-syntax v0.6.29 Adding regex-syntax v0.7.4 Removing remove_dir_all v0.5.3 Adding rustc-demangle v0.1.23 Removing rustix v0.36.8 Adding rustix v0.37.23 Adding rustix v0.38.6 Updating rustls-pemfile v1.0.2 -> v1.0.3 Updating rustversion v1.0.11 -> v1.0.14 Updating ryu v1.0.12 -> v1.0.15 Updating schannel v0.1.21 -> v0.1.22 Updating scheduled-thread-pool v0.2.6 -> v0.2.7 Updating scopeguard v1.1.0 -> v1.2.0 Removing scratch v1.0.3 Updating security-framework v2.8.2 -> v2.9.2 Updating security-framework-sys v2.8.0 -> v2.9.1 Updating serde v1.0.152 -> v1.0.181 Updating serde_derive v1.0.152 -> v1.0.181 Updating serde_json v1.0.93 -> v1.0.104 Updating sha2 v0.10.6 -> v0.10.7 Updating slab v0.4.7 -> v0.4.8 Updating smallvec v1.10.0 -> v1.11.0 Updating socket2 v0.4.7 -> v0.4.9 Updating sqlx v0.6.2 -> v0.6.3 Updating sqlx-core v0.6.2 -> v0.6.3 Updating sqlx-macros v0.6.2 -> v0.6.3 Updating sqlx-rt v0.6.2 -> v0.6.3 Updating stringprep v0.1.2 -> v0.1.3 Updating subtle v2.4.1 -> v2.5.0 Removing syn v1.0.107 Adding syn v1.0.109 Adding syn v2.0.28 Updating tempfile v3.3.0 -> v3.7.0 Removing termcolor v1.2.0 Updating thiserror v1.0.38 -> v1.0.44 Updating thiserror-impl v1.0.38 -> v1.0.44 Updating tikv-jemalloc-sys v0.5.3+5.3.0-patched -> v0.5.4+5.3.0-patched Updating tikv-jemallocator v0.5.0 -> v0.5.4 Updating time v0.3.20 -> v0.3.25 Updating time-core v0.1.0 -> v0.1.1 Updating time-macros v0.2.8 -> v0.2.11 Updating tokio v1.25.0 -> v1.29.1 Updating tokio-macros v1.8.2 -> v2.1.0 Updating tokio-stream v0.1.11 -> v0.1.14 Updating tokio-util v0.7.7 -> v0.7.8 Adding tonic v0.9.2 Removing tower-http v0.3.5 Updating tracing-attributes v0.1.23 -> v0.1.26 Updating tracing-core v0.1.30 -> v0.1.31 Updating tracing-subscriber v0.3.16 -> v0.3.17 Updating ucd-trie v0.1.5 -> v0.1.6 Updating unicode-bidi v0.3.10 -> v0.3.13 Updating unicode-ident v1.0.6 -> v1.0.11 Updating url v2.3.1 -> v2.4.0 Adding utf8parse v0.2.1 Updating uuid v1.3.0 -> v1.4.1 Updating value-bag v1.0.0-alpha.9 -> v1.4.1 Updating want v0.3.0 -> v0.3.1 Updating wasm-bindgen v0.2.84 -> v0.2.87 Updating wasm-bindgen-backend v0.2.84 -> v0.2.87 Updating wasm-bindgen-futures v0.4.34 -> v0.4.37 Updating wasm-bindgen-macro v0.2.84 -> v0.2.87 Updating wasm-bindgen-macro-support v0.2.84 -> v0.2.87 Updating wasm-bindgen-shared v0.2.84 -> v0.2.87 Updating web-sys v0.3.61 -> v0.3.64 Removing wepoll-ffi v0.1.2 Updating whoami v1.3.0 -> v1.4.1 Removing winapi-util v0.1.5 Adding windows v0.48.0 Updating windows-sys v0.42.0 -> v0.48.0 Removing windows-targets v0.42.1 Adding windows-targets v0.42.2 Adding windows-targets v0.48.1 Removing windows_aarch64_gnullvm v0.42.1 Adding windows_aarch64_gnullvm v0.42.2 Adding windows_aarch64_gnullvm v0.48.0 Removing windows_aarch64_msvc v0.42.1 Adding windows_aarch64_msvc v0.42.2 Adding windows_aarch64_msvc v0.48.0 Removing windows_i686_gnu v0.42.1 Adding windows_i686_gnu v0.42.2 Adding windows_i686_gnu v0.48.0 Removing windows_i686_msvc v0.42.1 Adding windows_i686_msvc v0.42.2 Adding windows_i686_msvc v0.48.0 Removing windows_x86_64_gnu v0.42.1 Adding windows_x86_64_gnu v0.42.2 Adding windows_x86_64_gnu v0.48.0 Removing windows_x86_64_gnullvm v0.42.1 Adding windows_x86_64_gnullvm v0.42.2 Adding windows_x86_64_gnullvm v0.48.0 Removing windows_x86_64_msvc v0.42.1 Adding windows_x86_64_msvc v0.42.2 Adding windows_x86_64_msvc v0.48.0
2023-08-05 11:37:23 -05:00
use log::LevelFilter;
2023-03-02 16:16:21 -05:00
use nostr::key::FromPkStr;
use nostr::key::Keys;
use r2d2;
use sqlx::pool::PoolOptions;
use sqlx::postgres::PgConnectOptions;
use sqlx::ConnectOptions;
2023-02-08 10:55:17 -05:00
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
2022-09-28 07:19:59 -05:00
use tracing::{debug, info, trace, warn};
pub type SqlitePool = r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>;
pub type PooledConnection = r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
/// Events submitted from a client, with a return channel for notices
pub struct SubmittedEvent {
pub event: Event,
pub notice_tx: tokio::sync::mpsc::Sender<Notice>,
pub source_ip: String,
pub origin: Option<String>,
pub user_agent: Option<String>,
pub auth_pubkey: Option<Vec<u8>>,
}
2021-12-11 21:43:41 -06:00
/// Database file
pub const DB_FILE: &str = "nostr.db";
/// Build repo
2022-09-24 09:19:16 -05:00
/// # Panics
///
/// Will panic if the pool could not be created.
pub async fn build_repo(settings: &Settings, metrics: NostrMetrics) -> Arc<dyn NostrRepo> {
match settings.database.engine.as_str() {
2023-07-03 10:31:22 -05:00
"sqlite" => Arc::new(build_sqlite_pool(settings, metrics).await),
"postgres" => Arc::new(build_postgres_pool(settings, metrics).await),
_ => panic!("Unknown database engine"),
}
}
async fn build_sqlite_pool(settings: &Settings, metrics: NostrMetrics) -> SqliteRepo {
let repo = SqliteRepo::new(settings, metrics);
repo.start().await.ok();
repo.migrate_up().await.ok();
repo
}
async fn build_postgres_pool(settings: &Settings, metrics: NostrMetrics) -> PostgresRepo {
let mut options: PgConnectOptions = settings.database.connection.as_str().parse().unwrap();
options.log_statements(LevelFilter::Debug);
options.log_slow_statements(LevelFilter::Warn, Duration::from_secs(60));
let pool: PostgresPool = PoolOptions::new()
.max_connections(settings.database.max_conn)
.min_connections(settings.database.min_conn)
.idle_timeout(Duration::from_secs(60))
.connect_with(options)
.await
.unwrap();
let write_pool: PostgresPool = match &settings.database.connection_write {
Some(cfg_write) => {
let mut options_write: PgConnectOptions = cfg_write.as_str().parse().unwrap();
options_write.log_statements(LevelFilter::Debug);
options_write.log_slow_statements(LevelFilter::Warn, Duration::from_secs(60));
PoolOptions::new()
.max_connections(settings.database.max_conn)
.min_connections(settings.database.min_conn)
.idle_timeout(Duration::from_secs(60))
.connect_with(options_write)
.await
.unwrap()
}
None => pool.clone(),
};
let repo = PostgresRepo::new(pool, write_pool, metrics);
// Panic on migration failure
let version = repo.migrate_up().await.unwrap();
info!("Postgres migration completed, at v{}", version);
// startup scheduled tasks
repo.start().await.ok();
2023-01-24 08:04:37 -06:00
repo
}
/// Spawn a database writer that persists events to the `SQLite` store.
pub async fn db_writer(
repo: Arc<dyn NostrRepo>,
settings: Settings,
mut event_rx: tokio::sync::mpsc::Receiver<SubmittedEvent>,
bcast_tx: tokio::sync::broadcast::Sender<Event>,
metadata_tx: tokio::sync::broadcast::Sender<Event>,
payment_tx: tokio::sync::broadcast::Sender<PaymentMessage>,
mut shutdown: tokio::sync::broadcast::Receiver<()>,
) -> Result<()> {
// are we performing NIP-05 checking?
let nip05_active = settings.verified_users.is_active();
// are we requriing NIP-05 user verification?
let nip05_enabled = settings.verified_users.is_enabled();
let pay_to_relay_enabled = settings.pay_to_relay.enabled;
let cost_per_event = settings.pay_to_relay.cost_per_event;
debug!("Pay to relay: {}", pay_to_relay_enabled);
//upgrade_db(&mut pool.get()?)?;
// Make a copy of the whitelist
let whitelist = &settings.authorization.pubkey_whitelist.clone();
// get rate limit settings
let rps_setting = settings.limits.messages_per_sec;
let mut most_recent_rate_limit = Instant::now();
let mut lim_opt = None;
let clock = governor::clock::QuantaClock::default();
if let Some(rps) = rps_setting {
if rps > 0 {
info!("Enabling rate limits for event creation ({}/sec)", rps);
let quota = core::num::NonZeroU32::new(rps * 60).unwrap();
lim_opt = Some(RateLimiter::direct(Quota::per_minute(quota)));
}
}
// create a client if GRPC is enabled.
// Check with externalized event admitter service, if one is defined.
let mut grpc_client = if let Some(svr) = settings.grpc.event_admission_server {
Some(nauthz::EventAuthzService::connect(&svr).await)
} else {
None
};
//let gprc_client = settings.grpc.event_admission_server.map(|s| {
2023-02-25 14:49:35 -06:00
// event_admitter_connect(&s);
// });
loop {
if shutdown.try_recv().is_ok() {
info!("shutting down database writer");
break;
}
// call blocking read on channel
let next_event = event_rx.recv().await;
// if the channel has closed, we will never get work
if next_event.is_none() {
break;
}
// track if an event write occurred; this is used to
// update the rate limiter
let mut event_write = false;
let subm_event = next_event.unwrap();
let event = subm_event.event;
let notice_tx = subm_event.notice_tx;
// Check that event kind isn't blacklisted
let kinds_blacklist = &settings.limits.event_kind_blacklist.clone();
if let Some(event_kind_blacklist) = kinds_blacklist {
if event_kind_blacklist.contains(&event.kind) {
debug!(
"rejecting event: {}, blacklisted kind: {}",
&event.get_event_id_prefix(),
2023-01-22 10:06:44 -06:00
&event.kind
);
notice_tx
2023-02-08 10:55:17 -05:00
.try_send(Notice::blocked(event.id, "event kind is blocked by relay"))
2023-02-25 10:20:53 -06:00
.ok();
continue;
}
}
// Check that event kind isn't allowlisted
let kinds_allowlist = &settings.limits.event_kind_allowlist.clone();
if let Some(event_kind_allowlist) = kinds_allowlist {
if !event_kind_allowlist.contains(&event.kind) {
debug!(
"rejecting event: {}, allowlist kind: {}",
&event.get_event_id_prefix(),
&event.kind
);
notice_tx
2023-02-25 14:49:35 -06:00
.try_send(Notice::blocked(event.id, "event kind is blocked by relay"))
.ok();
continue;
}
}
// Set to none until balance is got from db
// Will stay none if user in whitelisted and does not have to pay to post
// When pay to relay is enabled the whitelist is not a list of who can post
// It is a list of who can post for free
let mut user_balance: Option<u64> = None;
if !pay_to_relay_enabled {
// check if this event is authorized.
if let Some(allowed_addrs) = whitelist {
// TODO: incorporate delegated pubkeys
// if the event address is not in allowed_addrs.
if !allowed_addrs.contains(&event.pubkey) {
debug!(
"rejecting event: {}, unauthorized author",
event.get_event_id_prefix()
);
notice_tx
.try_send(Notice::blocked(
event.id,
"pubkey is not allowed to publish to this relay",
))
.ok();
continue;
}
}
} else {
// If the user is on whitelist there is no need to check if the user is admitted or has balance to post
if whitelist.is_none()
|| (whitelist.is_some() && !whitelist.as_ref().unwrap().contains(&event.pubkey))
{
let key = Keys::from_pk_str(&event.pubkey).unwrap();
match repo.get_account_balance(&key).await {
Ok((user_admitted, balance)) => {
// Checks to make sure user is admitted
if !user_admitted {
debug!("user: {}, is not admitted", &event.pubkey);
// If the user is in DB but not admitted
// Send meeage to payment thread to check if outstanding invoice has been paid
payment_tx
.send(PaymentMessage::CheckAccount(event.pubkey))
.ok();
notice_tx
.try_send(Notice::blocked(event.id, "User is not admitted"))
.ok();
continue;
}
// Checks that user has enough balance to post
// TODO: this should send an invoice to user to top up
if balance < cost_per_event {
debug!("user: {}, does not have a balance", &event.pubkey,);
notice_tx
.try_send(Notice::blocked(event.id, "Insufficient balance"))
.ok();
continue;
}
user_balance = Some(balance);
debug!("User balance: {:?}", user_balance);
}
Err(
Error::SqlError(rusqlite::Error::QueryReturnedNoRows)
| Error::SqlxError(sqlx::Error::RowNotFound),
) => {
// User does not exist
info!("Unregistered user");
if settings.pay_to_relay.sign_ups && settings.pay_to_relay.direct_message {
payment_tx
.send(PaymentMessage::NewAccount(event.pubkey))
.ok();
}
let msg = "Pubkey not registered";
notice_tx.try_send(Notice::error(event.id, msg)).ok();
continue;
}
Err(err) => {
warn!("Error checking admission status: {:?}", err);
let msg = "relay experienced an error checking your admission status";
notice_tx.try_send(Notice::error(event.id, msg)).ok();
// Other error
continue;
}
}
}
}
// send any metadata events to the NIP-05 verifier
if nip05_active && event.is_kind_metadata() {
// we are sending this prior to even deciding if we
// persist it. this allows the nip05 module to
// inspect it, update if necessary, or persist a new
// event and broadcast it itself.
metadata_tx.send(event.clone()).ok();
}
// get a validation result for use in verification and GPRC
let validation = if nip05_active {
Some(repo.get_latest_user_verification(&event.pubkey).await)
} else {
None
};
2023-01-22 10:06:44 -06:00
// check for NIP-05 verification
if nip05_enabled && validation.is_some() {
match validation.as_ref().unwrap() {
2023-01-22 10:06:44 -06:00
Ok(uv) => {
if uv.is_valid(&settings.verified_users) {
info!(
"new event from verified author ({:?},{:?})",
uv.name.to_string(),
event.get_author_prefix()
);
} else {
info!(
"rejecting event, author ({:?} / {:?}) verification invalid (expired/wrong domain)",
uv.name.to_string(),
event.get_author_prefix()
);
notice_tx
.try_send(Notice::blocked(
event.id,
2023-01-22 10:06:44 -06:00
"NIP-05 verification is no longer valid (expired/wrong domain)",
))
.ok();
continue;
}
2023-01-22 10:06:44 -06:00
}
2023-03-02 16:16:21 -05:00
Err(
Error::SqlError(rusqlite::Error::QueryReturnedNoRows)
| Error::SqlxError(sqlx::Error::RowNotFound),
) => {
2023-01-22 10:06:44 -06:00
debug!(
"no verification records found for pubkey: {:?}",
event.get_author_prefix()
);
notice_tx
.try_send(Notice::blocked(
event.id,
"NIP-05 verification needed to publish events",
))
.ok();
continue;
}
Err(e) => {
warn!("checking nip05 verification status failed: {:?}", e);
continue;
}
}
2023-01-22 10:06:44 -06:00
}
// nip05 address
2023-02-25 14:49:35 -06:00
let nip05_address: Option<crate::nip05::Nip05Name> =
validation.and_then(|x| x.ok().map(|y| y.name));
// GRPC check
if let Some(ref mut c) = grpc_client {
trace!("checking if grpc permits");
let grpc_start = Instant::now();
2023-02-25 14:49:35 -06:00
let decision_res = c
.admit_event(
&event,
&subm_event.source_ip,
subm_event.origin,
subm_event.user_agent,
nip05_address,
subm_event.auth_pubkey,
)
.await;
match decision_res {
Ok(decision) => {
if !decision.permitted() {
// GPRC returned a decision to reject this event
2023-02-25 14:49:35 -06:00
info!(
"GRPC rejected event: {:?} (kind: {}) from: {:?} in: {:?} (IP: {:?})",
event.get_event_id_prefix(),
event.kind,
event.get_author_prefix(),
grpc_start.elapsed(),
subm_event.source_ip
);
notice_tx
.try_send(Notice::blocked(
event.id,
2023-07-03 10:31:22 -05:00
&decision.message().unwrap_or_default(),
2023-02-25 14:49:35 -06:00
))
.ok();
continue;
}
2023-02-25 14:49:35 -06:00
}
Err(e) => {
warn!("GRPC server error: {:?}", e);
}
}
}
2023-01-22 10:06:44 -06:00
// TODO: cache recent list of authors to remove a DB call.
let start = Instant::now();
2023-01-24 08:04:42 -06:00
if event.is_ephemeral() {
bcast_tx.send(event.clone()).ok();
2023-01-24 08:04:42 -06:00
debug!(
"published ephemeral event: {:?} from: {:?} in: {:?}",
event.get_event_id_prefix(),
event.get_author_prefix(),
start.elapsed()
);
event_write = true;
// send OK message
notice_tx.try_send(Notice::saved(event.id)).ok();
} else {
match repo.write_event(&event).await {
Ok(updated) => {
if updated == 0 {
trace!("ignoring duplicate or deleted event");
notice_tx.try_send(Notice::duplicate(event.id)).ok();
} else {
info!(
"persisted event: {:?} (kind: {}) from: {:?} in: {:?} (IP: {:?})",
event.get_event_id_prefix(),
2023-01-22 10:06:44 -06:00
event.kind,
event.get_author_prefix(),
start.elapsed(),
subm_event.source_ip,
);
event_write = true;
// send this out to all clients
bcast_tx.send(event.clone()).ok();
notice_tx.try_send(Notice::saved(event.id)).ok();
}
}
Err(err) => {
warn!("event insert failed: {:?}", err);
let msg = "relay experienced an error trying to publish the latest event";
notice_tx.try_send(Notice::error(event.id, msg)).ok();
}
}
}
// use rate limit, if defined, and if an event was actually written.
if event_write {
// If pay to relay is diabaled or the cost per event is 0
// No need to update user balance
if pay_to_relay_enabled && cost_per_event > 0 {
// If the user balance is some, user was not on whitelist
// Their balance should be reduced by the cost per event
if let Some(_balance) = user_balance {
let pubkey = Keys::from_pk_str(&event.pubkey)?;
repo.update_account_balance(&pubkey, false, cost_per_event)
.await?;
}
}
if let Some(ref lim) = lim_opt {
if let Err(n) = lim.check() {
let wait_for = n.wait_time_from(clock.now());
// check if we have recently logged rate
// limits, but print out a message only once
// per second.
if most_recent_rate_limit.elapsed().as_secs() > 10 {
warn!(
"rate limit reached for event creation (sleep for {:?}) (suppressing future messages for 10 seconds)",
wait_for
);
// reset last rate limit message
most_recent_rate_limit = Instant::now();
}
// block event writes, allowing them to queue up
thread::sleep(wait_for);
continue;
}
}
}
}
info!("database connection closed");
Ok(())
}
2022-02-12 09:29:35 -06:00
/// Serialized event associated with a specific subscription request.
2022-09-24 08:30:22 -05:00
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct QueryResult {
2021-12-11 21:43:41 -06:00
/// Subscription identifier
pub sub_id: String,
2021-12-11 21:43:41 -06:00
/// Serialized event
pub event: String,
}