From 3229e4192fbd6f1190dfe21a95191306ae660bf7 Mon Sep 17 00:00:00 2001 From: Greg Heartsfield Date: Thu, 16 Feb 2023 18:03:28 -0600 Subject: [PATCH] feat: publish favicon.ico --- config.toml | 4 ++++ src/config.rs | 2 ++ src/error.rs | 8 ++++++++ src/server.rs | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/config.toml b/config.toml index f49290a..c0237f6 100644 --- a/config.toml +++ b/config.toml @@ -16,6 +16,10 @@ description = "A newly created nostr-rs-relay.\n\nCustomize this with your own i # Administrative contact URI #contact = "mailto:contact@example.com" +# Favicon location. Relative to the current directory. Assumes an +# ICO format. +#favicon = "favicon.ico" + [diagnostics] # Enable tokio tracing (for use with tokio-console) #tracing = false diff --git a/src/config.rs b/src/config.rs index e41305c..784723b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,7 @@ pub struct Info { pub description: Option, pub pubkey: Option, pub contact: Option, + pub favicon: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -218,6 +219,7 @@ impl Default for Settings { description: None, pubkey: None, contact: None, + favicon: None, }, diagnostics: Diagnostics { tracing: false }, database: Database { diff --git a/src/error.rs b/src/error.rs index ebefbd9..790486f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -70,6 +70,8 @@ pub enum Error { TonicError(tonic::Status), #[error("Invalid AUTH message")] AuthFailure, + #[error("I/O Error")] + IoError(std::io::Error), #[error("Unknown/Undocumented")] UnknownError, } @@ -145,3 +147,9 @@ impl From for Error { Error::TonicError(r) } } + +impl From for Error { + fn from(r: std::io::Error) -> Self { + Error::IoError(r) + } +} diff --git a/src/server.rs b/src/server.rs index c3ad8ed..a884e73 100644 --- a/src/server.rs +++ b/src/server.rs @@ -32,6 +32,9 @@ use serde::{Deserialize, Serialize}; use serde_json::json; use std::collections::HashMap; use std::convert::Infallible; +use std::fs::File; +use std::io::BufReader; +use std::io::Read; use std::net::SocketAddr; use std::path::Path; use std::sync::Arc; @@ -62,6 +65,7 @@ async fn handle_web_request( broadcast: Sender, event_tx: tokio::sync::mpsc::Sender, shutdown: Receiver<()>, + favicon: Option>, registry: Registry, metrics: NostrMetrics, ) -> Result, Infallible> { @@ -189,6 +193,23 @@ async fn handle_web_request( .body(Body::from(buffer)) .unwrap()) } + ("/favicon.ico", false) => { + if let Some(favicon_bytes) = favicon { + info!("returning favicon"); + Ok(Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "image/x-icon") + // 1 month cache + .header("Cache-Control", "public, max-age=2419200") + .body(Body::from(favicon_bytes)) + .unwrap()) + } else { + Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("")) + .unwrap()) + } + } (_, _) => { //handle any other url Ok(Response::builder() @@ -308,6 +329,15 @@ fn create_metrics() -> (Registry, NostrMetrics) { (registry,metrics) } +fn file_bytes(path: &str) -> Result> { + let f = File::open(path)?; + let mut reader = BufReader::new(f); + let mut buffer = Vec::new(); + // Read file into vector. + reader.read_to_end(&mut buffer)?; + Ok(buffer) +} + /// Start running a Nostr relay server. pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Result<(), Error> { trace!("Config: {:?}", settings); @@ -454,6 +484,12 @@ pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Resul //let pool_monitor = pool.clone(); //tokio::spawn(async move {db::monitor_pool("reader", pool_monitor).await;}); + // Read in the favicon if it exists + let favicon = settings.info.favicon.as_ref().and_then(|x| { + info!("reading favicon..."); + file_bytes(x).ok() + }); + // A `Service` is needed for every connection, so this // creates one from our `handle_request` function. let make_svc = make_service_fn(|conn: &AddrStream| { @@ -463,6 +499,7 @@ pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Resul let event = event_tx.clone(); let stop = invoke_shutdown.clone(); let settings = settings.clone(); + let favicon = favicon.clone(); let registry = registry.clone(); let metrics = metrics.clone(); async move { @@ -476,6 +513,7 @@ pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Resul bcast.clone(), event.clone(), stop.subscribe(), + favicon.clone(), registry.clone(), metrics.clone(), )