refactor: improve relay management code structure (#220)

This commit is contained in:
XIAO YU
2024-06-29 09:41:16 +09:00
committed by GitHub
parent 5c9b599b1e
commit 968b1ada94
2 changed files with 64 additions and 56 deletions

View File

@@ -1,12 +1,11 @@
use std::{
fs,
io::{self, BufRead, Write},
};
use crate::Nostr; use crate::Nostr;
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use serde::Serialize; use serde::Serialize;
use specta::Type; use specta::Type;
use std::{
fs::OpenOptions,
io::{self, BufRead, Write},
};
use tauri::{path::BaseDirectory, Manager, State}; use tauri::{path::BaseDirectory, Manager, State};
#[derive(Serialize, Type)] #[derive(Serialize, Type)]
@@ -22,13 +21,16 @@ pub struct Relays {
pub async fn get_relays(state: State<'_, Nostr>) -> Result<Relays, String> { pub async fn get_relays(state: State<'_, Nostr>) -> Result<Relays, String> {
let client = &state.client; let client = &state.client;
// Get connected relays let connected_relays = client
let list = client.relays().await; .relays()
let connected_relays: Vec<String> = list.into_keys().map(|url| url.to_string()).collect(); .await
.into_keys()
.map(|url| url.to_string())
.collect::<Vec<_>>();
// Get NIP-65 relay list
let signer = client.signer().await.map_err(|e| e.to_string())?; let signer = client.signer().await.map_err(|e| e.to_string())?;
let public_key = signer.public_key().await.map_err(|e| e.to_string())?; let public_key = signer.public_key().await.map_err(|e| e.to_string())?;
let filter = Filter::new() let filter = Filter::new()
.author(public_key) .author(public_key)
.kind(Kind::RelayList) .kind(Kind::RelayList)
@@ -38,22 +40,35 @@ pub async fn get_relays(state: State<'_, Nostr>) -> Result<Relays, String> {
Ok(events) => { Ok(events) => {
if let Some(event) = events.first() { if let Some(event) = events.first() {
let nip65_list = nip65::extract_relay_list(event); let nip65_list = nip65::extract_relay_list(event);
let read: Vec<String> = nip65_list let read = nip65_list
.clone() .iter()
.into_iter() .filter_map(|(url, meta)| {
.filter(|i| matches!(&i.1, Some(y) if *y == RelayMetadata::Read)) if let Some(RelayMetadata::Read) = meta {
.map(|(url, _)| url.to_string()) Some(url.to_string())
} else {
None
}
})
.collect(); .collect();
let write: Vec<String> = nip65_list let write = nip65_list
.clone() .iter()
.into_iter() .filter_map(|(url, meta)| {
.filter(|i| matches!(&i.1, Some(y) if *y == RelayMetadata::Write)) if let Some(RelayMetadata::Write) = meta {
.map(|(url, _)| url.to_string()) Some(url.to_string())
} else {
None
}
})
.collect(); .collect();
let both: Vec<String> = nip65_list let both = nip65_list
.into_iter() .iter()
.filter(|i| i.1.is_none()) .filter_map(|(url, meta)| {
.map(|(url, _)| url.to_string()) if meta.is_none() {
Some(url.to_string())
} else {
None
}
})
.collect(); .collect();
Ok(Relays { Ok(Relays {
@@ -79,31 +94,30 @@ pub async fn get_relays(state: State<'_, Nostr>) -> Result<Relays, String> {
#[specta::specta] #[specta::specta]
pub async fn connect_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool, String> { pub async fn connect_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client; let client = &state.client;
match client.add_relay(relay).await { let status = client.add_relay(relay).await.map_err(|e| e.to_string())?;
Ok(status) => { if status {
if status { println!("Connecting to relay: {}", relay);
println!("connecting to relay: {}", relay); client
let _ = client.connect_relay(relay).await; .connect_relay(relay)
Ok(true) .await
} else { .map_err(|e| e.to_string())?;
Ok(false)
}
}
Err(e) => Err(e.to_string()),
} }
Ok(status)
} }
#[tauri::command] #[tauri::command]
#[specta::specta] #[specta::specta]
pub async fn remove_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool, String> { pub async fn remove_relay(relay: &str, state: State<'_, Nostr>) -> Result<bool, String> {
let client = &state.client; let client = &state.client;
match client.remove_relay(relay).await { client
Ok(_) => { .remove_relay(relay)
let _ = client.disconnect_relay(relay).await; .await
Ok(true) .map_err(|e| e.to_string())?;
} client
Err(e) => Err(e.to_string()), .disconnect_relay(relay)
} .await
.map_err(|e| e.to_string())?;
Ok(true)
} }
#[tauri::command] #[tauri::command]
@@ -115,15 +129,12 @@ pub fn get_bootstrap_relays(app: tauri::AppHandle) -> Result<Vec<String>, String
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let file = std::fs::File::open(relays_path).map_err(|e| e.to_string())?; let file = std::fs::File::open(relays_path).map_err(|e| e.to_string())?;
let lines = io::BufReader::new(file).lines(); let reader = io::BufReader::new(file);
let mut relays = Vec::new(); reader
.lines()
for line in lines.map_while(Result::ok) { .collect::<Result<Vec<String>, io::Error>>()
relays.push(line.to_string()) .map_err(|e| e.to_string())
}
Ok(relays)
} }
#[tauri::command] #[tauri::command]
@@ -134,13 +145,10 @@ pub fn save_bootstrap_relays(relays: &str, app: tauri::AppHandle) -> Result<(),
.resolve("resources/relays.txt", BaseDirectory::Resource) .resolve("resources/relays.txt", BaseDirectory::Resource)
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let mut file = fs::OpenOptions::new() let mut file = OpenOptions::new()
.write(true) .write(true)
.open(relays_path) .open(relays_path)
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
match file.write_all(relays.as_bytes()) { file.write_all(relays.as_bytes()).map_err(|e| e.to_string())
Ok(_) => Ok(()),
Err(e) => Err(e.to_string()),
}
} }

View File

@@ -2,8 +2,8 @@ use std::collections::HashSet;
use std::str::FromStr; use std::str::FromStr;
use linkify::LinkFinder; use linkify::LinkFinder;
use nostr_sdk::{Alphabet, Event, EventId, FromBech32, PublicKey, SingleLetterTag, Tag, TagKind};
use nostr_sdk::prelude::Nip19Event; use nostr_sdk::prelude::Nip19Event;
use nostr_sdk::{Alphabet, Event, EventId, FromBech32, PublicKey, SingleLetterTag, Tag, TagKind};
use reqwest::Client; use reqwest::Client;
use serde::Serialize; use serde::Serialize;
use specta::Type; use specta::Type;
@@ -47,7 +47,7 @@ const IMAGES: [&str; 7] = ["jpg", "jpeg", "gif", "png", "webp", "avif", "tiff"];
const VIDEOS: [&str; 5] = ["mp4", "mov", "avi", "webm", "mkv"]; const VIDEOS: [&str; 5] = ["mp4", "mov", "avi", "webm", "mkv"];
pub fn get_latest_event(events: &[Event]) -> Option<&Event> { pub fn get_latest_event(events: &[Event]) -> Option<&Event> {
events.iter().max_by_key(|event| event.created_at()) events.iter().next()
} }
pub fn dedup_event(events: &[Event]) -> Vec<Event> { pub fn dedup_event(events: &[Event]) -> Vec<Event> {