feat: publish favicon.ico

This commit is contained in:
Greg Heartsfield 2023-02-16 18:03:28 -06:00
parent 7fd9b55e70
commit 3229e4192f
4 changed files with 52 additions and 0 deletions

View File

@ -16,6 +16,10 @@ description = "A newly created nostr-rs-relay.\n\nCustomize this with your own i
# Administrative contact URI # Administrative contact URI
#contact = "mailto:contact@example.com" #contact = "mailto:contact@example.com"
# Favicon location. Relative to the current directory. Assumes an
# ICO format.
#favicon = "favicon.ico"
[diagnostics] [diagnostics]
# Enable tokio tracing (for use with tokio-console) # Enable tokio tracing (for use with tokio-console)
#tracing = false #tracing = false

View File

@ -12,6 +12,7 @@ pub struct Info {
pub description: Option<String>, pub description: Option<String>,
pub pubkey: Option<String>, pub pubkey: Option<String>,
pub contact: Option<String>, pub contact: Option<String>,
pub favicon: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -218,6 +219,7 @@ impl Default for Settings {
description: None, description: None,
pubkey: None, pubkey: None,
contact: None, contact: None,
favicon: None,
}, },
diagnostics: Diagnostics { tracing: false }, diagnostics: Diagnostics { tracing: false },
database: Database { database: Database {

View File

@ -70,6 +70,8 @@ pub enum Error {
TonicError(tonic::Status), TonicError(tonic::Status),
#[error("Invalid AUTH message")] #[error("Invalid AUTH message")]
AuthFailure, AuthFailure,
#[error("I/O Error")]
IoError(std::io::Error),
#[error("Unknown/Undocumented")] #[error("Unknown/Undocumented")]
UnknownError, UnknownError,
} }
@ -145,3 +147,9 @@ impl From<tonic::Status> for Error {
Error::TonicError(r) Error::TonicError(r)
} }
} }
impl From<std::io::Error> for Error {
fn from(r: std::io::Error) -> Self {
Error::IoError(r)
}
}

View File

@ -32,6 +32,9 @@ use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::Infallible; use std::convert::Infallible;
use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
@ -62,6 +65,7 @@ async fn handle_web_request(
broadcast: Sender<Event>, broadcast: Sender<Event>,
event_tx: tokio::sync::mpsc::Sender<SubmittedEvent>, event_tx: tokio::sync::mpsc::Sender<SubmittedEvent>,
shutdown: Receiver<()>, shutdown: Receiver<()>,
favicon: Option<Vec<u8>>,
registry: Registry, registry: Registry,
metrics: NostrMetrics, metrics: NostrMetrics,
) -> Result<Response<Body>, Infallible> { ) -> Result<Response<Body>, Infallible> {
@ -189,6 +193,23 @@ async fn handle_web_request(
.body(Body::from(buffer)) .body(Body::from(buffer))
.unwrap()) .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 //handle any other url
Ok(Response::builder() Ok(Response::builder()
@ -308,6 +329,15 @@ fn create_metrics() -> (Registry, NostrMetrics) {
(registry,metrics) (registry,metrics)
} }
fn file_bytes(path: &str) -> Result<Vec<u8>> {
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. /// Start running a Nostr relay server.
pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Result<(), Error> { pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Result<(), Error> {
trace!("Config: {:?}", settings); trace!("Config: {:?}", settings);
@ -454,6 +484,12 @@ pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Resul
//let pool_monitor = pool.clone(); //let pool_monitor = pool.clone();
//tokio::spawn(async move {db::monitor_pool("reader", pool_monitor).await;}); //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 // A `Service` is needed for every connection, so this
// creates one from our `handle_request` function. // creates one from our `handle_request` function.
let make_svc = make_service_fn(|conn: &AddrStream| { 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 event = event_tx.clone();
let stop = invoke_shutdown.clone(); let stop = invoke_shutdown.clone();
let settings = settings.clone(); let settings = settings.clone();
let favicon = favicon.clone();
let registry = registry.clone(); let registry = registry.clone();
let metrics = metrics.clone(); let metrics = metrics.clone();
async move { async move {
@ -476,6 +513,7 @@ pub fn start_server(settings: &Settings, shutdown_rx: MpscReceiver<()>) -> Resul
bcast.clone(), bcast.clone(),
event.clone(), event.clone(),
stop.subscribe(), stop.subscribe(),
favicon.clone(),
registry.clone(), registry.clone(),
metrics.clone(), metrics.clone(),
) )