Skip to content

Commit

Permalink
refactor: managers and services
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodylow committed May 25, 2024
1 parent b4140cf commit 636860f
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 199 deletions.
10 changes: 6 additions & 4 deletions fedimint-nwc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use tokio::sync::oneshot;
use tracing::{debug, info};

pub mod config;
pub mod managers;
pub mod nwc;
pub mod services;
pub mod state;

use state::AppState;
Expand All @@ -21,7 +23,7 @@ async fn main() -> Result<()> {
dotenv::dotenv().ok();

let cli = Cli::parse();
let state = state::init(cli).await?;
let state = AppState::new(cli).await?;

// Shutdown signal handler
let (tx, rx) = oneshot::channel::<()>();
Expand Down Expand Up @@ -61,7 +63,7 @@ async fn handle_signals(tx: oneshot::Sender<()>) -> Result<()> {
}

async fn event_loop(state: AppState) -> Result<()> {
state.nostr_client.connect().await;
state.nostr_service.connect().await;
loop {
info!("Listening for events...");
let (tx, _) = tokio::sync::watch::channel(());
Expand All @@ -70,7 +72,7 @@ async fn event_loop(state: AppState) -> Result<()> {
let _ = tx.send(());
});

let mut notifications = state.nostr_client.notifications();
let mut notifications = state.nostr_service.notifications();
while let Ok(notification) = notifications.recv().await {
match notification {
RelayPoolNotification::Event { event, .. } => state.handle_event(*event).await,
Expand All @@ -82,6 +84,6 @@ async fn event_loop(state: AppState) -> Result<()> {
}
}

state.nostr_client.disconnect().await?;
state.nostr_service.disconnect().await?;
}
}
64 changes: 64 additions & 0 deletions fedimint-nwc/src/managers/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::fs::{create_dir_all, File};
use std::io::{BufReader, Write};
use std::path::Path;

use anyhow::{Context, Result};
use nostr_sdk::secp256k1::SecretKey;
use nostr_sdk::Keys;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct KeyManager {
server_key: SecretKey,
user_key: SecretKey,
#[serde(default)]
pub sent_info: bool,
}

impl KeyManager {
pub fn new(keys_file: &str) -> Result<Self> {
let path = Path::new(keys_file);
match File::open(path) {
Ok(file) => {
let reader = BufReader::new(file);
serde_json::from_reader(reader).context("Failed to parse JSON")
}
Err(_) => {
let keys = Self::generate()?;
Self::write_keys(&keys, path)?;
Ok(keys)
}
}
}

fn generate() -> Result<Self> {
let server_keys = Keys::generate();
let server_key = server_keys.secret_key()?;
let user_keys = Keys::generate();
let user_key = user_keys.secret_key()?;
Ok(Self {
server_key: **server_key,
user_key: **user_key,
sent_info: false,
})
}

fn write_keys(keys: &Self, path: &Path) -> Result<()> {
let json_str = serde_json::to_string(keys).context("Failed to serialize data")?;
if let Some(parent) = path.parent() {
create_dir_all(parent).context("Failed to create directory")?;
}
let mut file = File::create(path).context("Failed to create file")?;
file.write_all(json_str.as_bytes())
.context("Failed to write to file")?;
Ok(())
}

pub fn server_keys(&self) -> Keys {
Keys::new(self.server_key.into())
}

pub fn user_keys(&self) -> Keys {
Keys::new(self.user_key.into())
}
}
3 changes: 3 additions & 0 deletions fedimint-nwc/src/managers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod key;

pub use key::KeyManager;
2 changes: 1 addition & 1 deletion fedimint-nwc/src/nwc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use nostr_sdk::nips::nip47::Method;
use nostr::nips::nip47::Method;
use nostr_sdk::Event;

use crate::state::AppState;
Expand Down
5 changes: 5 additions & 0 deletions fedimint-nwc/src/services/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod multimint;
pub mod nostr;

pub use multimint::MultiMintService;
pub use nostr::NostrService;
40 changes: 40 additions & 0 deletions fedimint-nwc/src/services/multimint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::path::PathBuf;
use std::str::FromStr;

use anyhow::Result;
use multimint::fedimint_core::api::InviteCode;
use multimint::MultiMint;

#[derive(Debug, Clone)]
pub struct MultiMintService {
multimint: MultiMint,
}

impl MultiMintService {
pub async fn new(db_path: PathBuf) -> Result<Self> {
let clients = MultiMint::new(db_path).await?;
clients.update_gateway_caches().await?;
Ok(Self { multimint: clients })
}

pub async fn init_multimint(
&mut self,
invite_code: &str,
manual_secret: Option<String>,
) -> Result<()> {
match InviteCode::from_str(invite_code) {
Ok(invite_code) => {
let federation_id = self
.multimint
.register_new(invite_code, manual_secret)
.await?;
tracing::info!("Created client for federation id: {:?}", federation_id);
Ok(())
}
Err(e) => {
tracing::error!("Invalid federation invite code: {}", e);
Err(e.into())
}
}
}
}
62 changes: 62 additions & 0 deletions fedimint-nwc/src/services/nostr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use anyhow::Result;
use nostr_sdk::{Client, EventBuilder, EventId, Kind, RelayPoolNotification};
use tokio::sync::broadcast::Receiver;

use crate::managers::key::KeyManager;
use crate::nwc::METHODS;

#[derive(Debug, Clone)]
pub struct NostrService {
client: Client,
}

impl NostrService {
pub async fn new(key_manager: &KeyManager, relays: &str) -> Result<Self> {
let client = Client::new(&key_manager.server_keys());
Self::add_relays(&client, relays).await?;
Ok(Self { client })
}

async fn add_relays(client: &Client, relays: &str) -> Result<()> {
let lines = relays.split(',').collect::<Vec<_>>();
let relays = lines
.iter()
.map(|line| line.trim())
.filter(|line| !line.is_empty())
.map(|line| line.to_string())
.collect::<Vec<_>>();
for relay in relays {
client.add_relay(relay).await?;
}
Ok(())
}

pub async fn broadcast_info_event(&self, keys: &KeyManager) -> Result<EventId> {
let content = METHODS
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(" ");
let info = EventBuilder::new(Kind::WalletConnectInfo, content, [])
.to_event(&keys.server_keys())?;
self.client
.send_event(info)
.await
.map_err(|e| anyhow::anyhow!("Failed to send event: {}", e))
}

pub async fn connect(&self) -> () {
self.client.connect().await
}

pub async fn disconnect(&self) -> Result<()> {
self.client
.disconnect()
.await
.map_err(|e| anyhow::anyhow!("Failed to disconnect: {}", e))
}

pub fn notifications(&self) -> Receiver<RelayPoolNotification> {
self.client.notifications()
}
}
Loading

0 comments on commit 636860f

Please sign in to comment.