mirror of
https://github.com/scsibug/nostr-rs-relay.git
synced 2024-11-09 21:29:06 -05:00
feat: implementation of proposed NIP-11 (server metadata)
This commit is contained in:
parent
19637d612e
commit
d3da4eb009
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1097,6 +1097,7 @@ version = "1.0.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde 1.0.131",
|
"serde 1.0.131",
|
||||||
|
|
|
@ -17,7 +17,7 @@ config = { version = "0.11", features = ["toml"] }
|
||||||
bitcoin_hashes = { version = "^0.9", features = ["serde"] }
|
bitcoin_hashes = { version = "^0.9", features = ["serde"] }
|
||||||
secp256k1 = {git = "https://github.com/rust-bitcoin/rust-secp256k1.git", rev = "50034ccb18fdd84904ab3aa6c84a12fcced33209", features = ["rand", "rand-std", "serde", "bitcoin_hashes"] }
|
secp256k1 = {git = "https://github.com/rust-bitcoin/rust-secp256k1.git", rev = "50034ccb18fdd84904ab3aa6c84a12fcced33209", features = ["rand", "rand-std", "serde", "bitcoin_hashes"] }
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = "^1.0"
|
serde_json = {version = "^1.0", features = ["preserve_order"]}
|
||||||
hex = "^0.4"
|
hex = "^0.4"
|
||||||
rusqlite = "^0.26"
|
rusqlite = "^0.26"
|
||||||
lazy_static = "^1.4"
|
lazy_static = "^1.4"
|
||||||
|
|
12
config.toml
12
config.toml
|
@ -1,4 +1,16 @@
|
||||||
# Nostr-rs-relay configuration
|
# Nostr-rs-relay configuration
|
||||||
|
|
||||||
|
[info]
|
||||||
|
# Relay information for clients. Put your unique server name here.
|
||||||
|
name = "nostr-rs-relay"
|
||||||
|
# Description
|
||||||
|
description = "A newly created nostr-rs-relay.\n\nCustomize this with your own info."
|
||||||
|
# Administrative contact pubkey
|
||||||
|
#pubkey = "0c2d168a4ae8ca58c9f1ab237b5df682599c6c7ab74307ea8b05684b60405d41"
|
||||||
|
|
||||||
|
# Administrative contact email
|
||||||
|
#email = "contact@example.com"
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# Directory for SQLite files. Defaults to the current directory. Can
|
# Directory for SQLite files. Defaults to the current directory. Can
|
||||||
# also be specified (and overriden) with the "--db dirname" command
|
# also be specified (and overriden) with the "--db dirname" command
|
||||||
|
|
|
@ -8,6 +8,16 @@ lazy_static! {
|
||||||
pub static ref SETTINGS: RwLock<Settings> = RwLock::new(Settings::default());
|
pub static ref SETTINGS: RwLock<Settings> = RwLock::new(Settings::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub struct Info {
|
||||||
|
pub name: Option<String>,
|
||||||
|
#[serde(rename = "description")]
|
||||||
|
pub descr: Option<String>,
|
||||||
|
pub pubkey: Option<String>,
|
||||||
|
pub email: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
|
@ -52,6 +62,7 @@ pub struct Limits {
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
|
pub info: Info,
|
||||||
pub database: Database,
|
pub database: Database,
|
||||||
pub network: Network,
|
pub network: Network,
|
||||||
pub limits: Limits,
|
pub limits: Limits,
|
||||||
|
@ -89,6 +100,12 @@ impl Settings {
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Settings {
|
Settings {
|
||||||
|
info: Info {
|
||||||
|
name: Some("Unnamed nostr-rs-relay".to_owned()),
|
||||||
|
descr: None,
|
||||||
|
pubkey: None,
|
||||||
|
email: None,
|
||||||
|
},
|
||||||
database: Database {
|
database: Database {
|
||||||
data_directory: ".".to_owned(),
|
data_directory: ".".to_owned(),
|
||||||
},
|
},
|
||||||
|
|
61
src/info.rs
Normal file
61
src/info.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
use crate::config;
|
||||||
|
/// Relay Info
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::value::Value;
|
||||||
|
|
||||||
|
const CARGO_PKG_VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub struct RelayInfo {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub name: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub descr: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub pubkey: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub email: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub supported_nips: Option<Vec<String>>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub software: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub version: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RelayInfo {
|
||||||
|
fn default() -> Self {
|
||||||
|
RelayInfo {
|
||||||
|
name: None,
|
||||||
|
descr: None,
|
||||||
|
pubkey: None,
|
||||||
|
email: None,
|
||||||
|
supported_nips: Some(vec!["NIP-01".to_owned()]),
|
||||||
|
software: Some("https://git.sr.ht/~gheartsfield/nostr-rs-relay".to_owned()),
|
||||||
|
version: CARGO_PKG_VERSION.map(|x| x.to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert an Info struct into Relay Info json string
|
||||||
|
pub fn relay_info_json(info: &config::Info) -> String {
|
||||||
|
// get a default RelayInfo
|
||||||
|
let mut r = RelayInfo::default();
|
||||||
|
// update fields from Info, if present
|
||||||
|
r.name = info.name.clone();
|
||||||
|
r.descr = info.descr.clone();
|
||||||
|
r.pubkey = info.pubkey.clone();
|
||||||
|
r.email = info.email.clone();
|
||||||
|
r.to_json()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelayInfo {
|
||||||
|
pub fn to_json(self) -> String {
|
||||||
|
// create the info ARRAY
|
||||||
|
let mut info_arr: Vec<Value> = vec![];
|
||||||
|
info_arr.push(Value::String("NOSTR_SERVER_INFO".to_owned()));
|
||||||
|
info_arr.push(serde_json::to_value(&self).unwrap());
|
||||||
|
serde_json::to_string_pretty(&info_arr).unwrap()
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,5 +4,6 @@ pub mod conn;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
|
pub mod info;
|
||||||
pub mod protostream;
|
pub mod protostream;
|
||||||
pub mod subscription;
|
pub mod subscription;
|
||||||
|
|
29
src/main.rs
29
src/main.rs
|
@ -1,6 +1,7 @@
|
||||||
//! Server process
|
//! Server process
|
||||||
use futures::SinkExt;
|
use futures::SinkExt;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use hyper::header::ACCEPT;
|
||||||
use hyper::service::{make_service_fn, service_fn};
|
use hyper::service::{make_service_fn, service_fn};
|
||||||
use hyper::upgrade::Upgraded;
|
use hyper::upgrade::Upgraded;
|
||||||
use hyper::{
|
use hyper::{
|
||||||
|
@ -13,6 +14,7 @@ use nostr_rs_relay::conn;
|
||||||
use nostr_rs_relay::db;
|
use nostr_rs_relay::db;
|
||||||
use nostr_rs_relay::error::{Error, Result};
|
use nostr_rs_relay::error::{Error, Result};
|
||||||
use nostr_rs_relay::event::Event;
|
use nostr_rs_relay::event::Event;
|
||||||
|
use nostr_rs_relay::info::relay_info_json;
|
||||||
use nostr_rs_relay::protostream;
|
use nostr_rs_relay::protostream;
|
||||||
use nostr_rs_relay::protostream::NostrMessage::*;
|
use nostr_rs_relay::protostream::NostrMessage::*;
|
||||||
use nostr_rs_relay::protostream::NostrResponse::*;
|
use nostr_rs_relay::protostream::NostrResponse::*;
|
||||||
|
@ -47,7 +49,7 @@ async fn handle_web_request(
|
||||||
request.uri().path(),
|
request.uri().path(),
|
||||||
request.headers().contains_key(header::UPGRADE),
|
request.headers().contains_key(header::UPGRADE),
|
||||||
) {
|
) {
|
||||||
//if the request is ws_echo and the request headers contains an Upgrade key
|
// Request for / as websocket
|
||||||
("/", true) => {
|
("/", true) => {
|
||||||
debug!("websocket with upgrade request");
|
debug!("websocket with upgrade request");
|
||||||
//assume request is a handshake, so create the handshake response
|
//assume request is a handshake, so create the handshake response
|
||||||
|
@ -96,11 +98,30 @@ async fn handle_web_request(
|
||||||
};
|
};
|
||||||
Ok::<_, Infallible>(response)
|
Ok::<_, Infallible>(response)
|
||||||
}
|
}
|
||||||
|
// Request for Relay info
|
||||||
("/", false) => {
|
("/", false) => {
|
||||||
// handle request at root with no upgrade header
|
// handle request at root with no upgrade header
|
||||||
Ok(Response::new(Body::from(
|
// Check if this is a nostr server info request
|
||||||
"This is a Nostr relay.\n".to_string(),
|
let accept_header = &request.headers().get(ACCEPT);
|
||||||
)))
|
// check if application/nostr+json is included
|
||||||
|
if let Some(media_types) = accept_header {
|
||||||
|
if let Ok(mt_str) = media_types.to_str() {
|
||||||
|
if mt_str.contains("application/nostr+json") {
|
||||||
|
let config = config::SETTINGS.read().unwrap();
|
||||||
|
// build a relay info response
|
||||||
|
debug!("Responding to server info request");
|
||||||
|
let b = Body::from(relay_info_json(&config.info));
|
||||||
|
return Ok(Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("Content-Type", "application/nostr+json")
|
||||||
|
.body(b)
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(Response::new(Body::from(
|
||||||
|
"Please use a Nostr client to connect.",
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
//handle any other url
|
//handle any other url
|
||||||
|
|
Loading…
Reference in New Issue
Block a user