universal-connectivity icon indicating copy to clipboard operation
universal-connectivity copied to clipboard

rust-peer not working on Windows

Open Uomocosa opened this issue 7 months ago • 0 comments

Initial Problem

I've cloned the repo, and tried to run it with a simple cargo run. However on Windows, the signal_hook::iterator::Signals is not available.

I've come up with a solution, but I'm not yet too familiar with rust in general, so I'm fairly certain that there is a better solution.


What I did

I made two configurations one for #[cfg(not(windows))] and one for #[cfg(windows)]. The one for not(windows) is almost be unchanged. The windows config uses tokio::signal::windows, instead of signal_hook

Let me know how I can improve this.


Other bugs

  1. When pressing a key to write, it is doubled.
  2. If I start the cargo run on my PC, and open chrome and go to the site universal-connectivity.on-fleek.app the two instances do not recognize/connect to each other. (If I've understood correctly this should not be the case)

Changed src/ui/headless.rs file

#![allow(dead_code)]
use crate::{log::Message as LogMessage, ChatPeer, Message, Ui};
use async_trait::async_trait;
use libp2p::core::PeerId;
use std::{collections::HashSet, time::Duration};
use tokio::sync::mpsc::{self, Receiver, Sender};
use tokio_util::sync::CancellationToken;


/// A headless UI for the peer
pub struct Headless {
    // my peer id
    me: ChatPeer,
    // we receive log messages from the log thread
    from_log: Receiver<LogMessage>,
    // we send UI messages to the peer thread
    to_peer: Sender<Message>,
    // we receive UI messages from the peer thread
    from_peer: Receiver<Message>,
    // the shutdown token
    shutdown: CancellationToken,
    // the list of peers
    peers: HashSet<ChatPeer>,
}

impl Headless {
    /// Create a new UI instance
    pub fn build(
        me: PeerId,
        from_log: Receiver<LogMessage>,
        shutdown: CancellationToken,
    ) -> (Box<dyn Ui + Send>, Sender<Message>, Receiver<Message>) {
        // create a new channels for sending/receiving messages
        let (to_peer, from_ui) = mpsc::channel::<Message>(64);
        let (to_ui, from_peer) = mpsc::channel::<Message>(64);

        // create a new TUI instance
        let ui: Box<dyn Ui> = Box::new(Self {
            me: me.into(),
            from_log,
            to_peer,
            from_peer,
            shutdown,
            peers: HashSet::new(),
        });

        (ui, to_ui, from_ui)
    }
}

#[async_trait]
impl Ui for Headless {
    /// Run the UI
    async fn run(&mut self) -> anyhow::Result<()> {
        let mut signal_handle = None;
        #[cfg(not(windows))]
        {
            use signal_hook::{consts::SIGTERM, iterator::Signals};
            // Register the SIGTERM signal
            signal_handle = Some(Signals::new([SIGTERM])?);
        }
        #[cfg(windows)]
        {
            use tokio::signal::windows::{ctrl_c, ctrl_break, ctrl_close, ctrl_logoff, ctrl_shutdown};
            let mut ctrl_c_signal = ctrl_c()?;
            let mut ctrl_break_signal = ctrl_break()?;
            let mut ctrl_close_signal = ctrl_close()?;
            let mut ctrl_logoff_signal = ctrl_logoff()?;
            let mut ctrl_shutdown_signal = ctrl_shutdown()?;
            signal_handle = Some(tokio::spawn(async move {
                tokio::select! {
                    _ = ctrl_c_signal.recv() => {
                        println!("Received Ctrl+C signal.");
                    }
                    _ = ctrl_break_signal.recv() => {
                        println!("Received Ctrl+Break signal.");
                    }
                    _ = ctrl_close_signal.recv() => {
                        println!("Received Ctrl+Close signal.");
                    }
                    _ = ctrl_logoff_signal.recv() => {
                        println!("Received Ctrl+Logoff signal.");
                    }
                    _ = ctrl_shutdown_signal.recv() => {
                        println!("Received Ctrl+Shutdown signal.");
                    }
                }
            }));
        }

        println!("Headless UI started");
        println!("Press Ctrl+C to exit");
        println!("My peer id: {} ({})", self.me.id(), self.me);

        // Main loop
        'main: loop {
            // Process log messages
            if let Ok(log) = self.from_log.try_recv() {
                //TODO: remove this after [PR 5966](https://github.com/libp2p/rust-libp2p/pull/5966)
                if !log.message.starts_with("Can't send data channel") {
                    println!("{}", log.message);
                }
            }

            // Process peer messages
            if let Ok(ui_message) = self.from_peer.try_recv() {
                match ui_message {
                    Message::Chat { from, data } => {
                        let from = from.map_or("Unknown".to_string(), |peer| peer.to_string());
                        let message =
                            String::from_utf8(data).unwrap_or("Invalid UTF-8".to_string());
                        println!("{}: {}", from, message);
                    }
                    Message::AddPeer(peer) => {
                        if self.peers.insert(peer) {
                            println!(
                                "Adding peer:\n\tpeer id: {}\n\tname: {}",
                                peer.id(),
                                peer.name()
                            );
                        }
                    }
                    Message::RemovePeer(peer) => {
                        if self.peers.remove(&peer) {
                            println!("Removing peer: {peer:?}");
                        }
                    }
                    Message::Event(event) => {
                        println!("{}", event);
                    }
                    _ => {}
                }
            }

            // check if we have received the shutdown signal from the OS
            #[cfg(not(windows))]
            {   
                let signals = signal_handle.as_ref().unwrap();
                if signals.pending().next() == Some(SIGTERM) {
                    println!("Received SIGTERM, shutting down");
                    self.shutdown.cancel();
                    break 'main;
                }
            }
            #[cfg(windows)]
            {
                let handle = signal_handle.as_ref().unwrap();
                if handle.is_finished() {
                    println!("Received SIGTERM, shutting down");
                    self.shutdown.cancel();
                    break 'main;
                }
            }
            
            tokio::time::sleep(Duration::from_millis(18)).await;
        }

        Ok(())
    }
}

Uomocosa avatar May 16 '25 10:05 Uomocosa