libp2p / libp2p/universal-connectivity

rust-peer not working on Windows

Open
#277 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
167
Forks
75
PR merge metrics
No merged PRs in 30d

Description

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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/ui/headless.rs and reproduce cargo run on Windows, focusing first on the platform-specific signal setup in Ui::run. Then check the reported doubled key input and whether the native and browser instances connect as expected. Done means the Windows peer runs and shuts down correctly, input is not duplicated, and the two instances connect when that is the intended behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, networking, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.