Skip to content

Commit

Permalink
fix: better handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodylow committed May 27, 2024
1 parent 18afb7e commit 0aede79
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 49 deletions.
113 changes: 64 additions & 49 deletions fedimint-nwc/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,91 +1,106 @@
use anyhow::Result;
use clap::Parser;
use nostr_sdk::{JsonUtil, Kind, RelayPoolNotification};
use tokio::{pin, task};
use tracing::{error, info};

pub mod config;
pub mod database;
pub mod nwc;
pub mod server;
pub mod services;

pub mod state;
use axum::Router;
use state::AppState;
use tower_http::services::ServeDir;

use crate::config::Cli;
use crate::server::run_server;
use crate::state::AppState;

/// Fedimint Nostr Wallet Connect
/// A nostr wallet connect implementation on top of a multimint client
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
dotenv::dotenv().ok();

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

// Connect to the relay pool and broadcast the nwc info event on startup
state.nostr_service.connect().await;
state.nostr_service.broadcast_info_event().await?;

let server = Router::new().nest_service("/", ServeDir::new("frontend/assets"));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();

// Spawn a new Tokio task for the server
let server_task = task::spawn(async move {
axum::serve(listener, server).await.unwrap();
let server_handle = tokio::spawn(async {
match run_server().await {
Ok(_) => info!("Server ran successfully."),
Err(e) => {
error!("Server failed to run: {}", e);
std::process::exit(1);
}
}
});

// Wait for the server task to complete if necessary
server_task.await?;
let ctrl_c = tokio::signal::ctrl_c();
tokio::pin!(ctrl_c);

// Start the event loop
event_loop(state.clone()).await?;
tokio::select! {
_ = &mut ctrl_c => {
info!("Ctrl+C received. Shutting down...");
},
_ = event_loop(state.clone()) => {
info!("Event loop exited unexpectedly.");
},
_ = server_handle => {
info!("Server task exited unexpectedly.");
}
}

Ok(())
shutdown(state).await
}

/// Event loop that listens for nostr wallet connect events and handles them
async fn event_loop(state: AppState) -> Result<()> {
// Handle ctrl+c to gracefully shutdown the event loop
let ctrl_c = tokio::signal::ctrl_c();
pin!(ctrl_c);

let mut notifications = state.nostr_service.notifications();
info!("Listening for events...");
loop {
tokio::select! {
_ = &mut ctrl_c => {
info!("Ctrl+C received. Waiting for active requests to complete...");
state.wait_for_active_requests().await;
info!("All active requests completed.");
break;
},
notification = notifications.recv() => {
if let Ok(notification) = notification {
if let RelayPoolNotification::Event { event, .. } = notification {
// Only handle nwc events
if event.kind == Kind::WalletConnectRequest
&& event.pubkey == state.nostr_service.user_keys().public_key()
&& event.verify().is_ok() {
info!("Received event: {}", event.as_json());
state.handle_event(*event).await
} else {
error!("Invalid nwc event: {}", event.as_json());
}
} else if let RelayPoolNotification::Shutdown = notification {
info!("Relay pool shutdown");
break;
} else {
error!("Unhandled relay pool notification: {notification:?}");
}
handle_notification(notification, &state).await?;
}
}
}
}
}

async fn handle_notification(notification: RelayPoolNotification, state: &AppState) -> Result<()> {
match notification {
RelayPoolNotification::Event { event, .. } => {
if event.kind == Kind::WalletConnectRequest
&& event.pubkey == state.nostr_service.user_keys().public_key()
&& event.verify().is_ok()
{
info!("Received event: {}", event.as_json());
state.handle_event(*event).await;
} else {
error!("Invalid nwc event: {}", event.as_json());
}
Ok(())
}
RelayPoolNotification::Shutdown => {
info!("Relay pool shutdown");
Err(anyhow::anyhow!("Relay pool shutdown"))
}
_ => {
error!("Unhandled relay pool notification: {notification:?}");
Ok(())
}
}
}

async fn shutdown(state: AppState) -> Result<()> {
info!("Shutting down services and server...");
state.wait_for_active_requests().await;
info!("All active requests completed.");
state.nostr_service.disconnect().await?;
info!("Services disconnected.");
Ok(())
}

fn init_logging_and_env() -> Result<()> {
tracing_subscriber::fmt::init();
dotenv::dotenv().ok();
Ok(())
}
14 changes: 14 additions & 0 deletions fedimint-nwc/src/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use axum::Router;
use tokio::net::TcpListener;
use tower_http::services::ServeDir;
use tracing::error;

pub async fn run_server() -> Result<(), anyhow::Error> {
let server = Router::new().nest_service("/", ServeDir::new("frontend/assets"));
let listener = TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, server).await.map_err(|e| {
error!("Server failed to run: {}", e);
e
})?;
Ok(())
}

0 comments on commit 0aede79

Please sign in to comment.