Skip to content

rust-peer not working on Windows #277

@Uomocosa

Description

@Uomocosa

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(())
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions