由于github老被墙,原来使用github备份/同步文档效率太低了, 打算写一个局域网内多端文件自动同步的小工具。其中有个环节需要结点之间能自动发现局域网其他结点。所以打算使用mdns现实服务自动发现的功能。
Cargo.toml
[package]
name = "airsync"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-std = { version = "1.12", features = ["attributes"] }
async-trait = "0.1"
env_logger = "0.10.0"
futures = "0.3.28"
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
libp2p = { version = "0.52", features = [
"async-std",
"mdns",
"tokio",
"noise",
"macros",
"tcp",
"yamux",
"quic",
"cbor",
"request-response",
] }
main.rs
use std::{error::Error};
use futures::future::Either;
use futures::StreamExt;
use libp2p::{core::upgrade::Version, identity, noise, swarm::{SwarmBuilder, SwarmEvent}, tcp, yamux, PeerId, Transport, Multiaddr, mdns, quic, request_response, StreamProtocol};
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::OrTransport;
use libp2p::request_response::{Message, ProtocolSupport};
use libp2p::swarm::NetworkBehaviour;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct FileRequest(String);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct FileResponse(Vec<u8>);
#[derive(NetworkBehaviour)]
struct NodeBehaviour {
mdns: mdns::async_io::Behaviour, // 结点发现
handler: request_response::cbor::Behaviour<FileRequest, FileResponse>, // 数据传输
keep_live: libp2p::swarm::keep_alive::Behaviour, // 心跳
}
#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
// key
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let tcp_transport = tcp::async_io::Transport::new(tcp::Config::default().nodelay(true))
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key).unwrap())
.multiplex(yamux::Config::default())
.boxed();
let quic_transport = quic::async_std::Transport::new(quic::Config::new(&local_key));
let transport = OrTransport::new(quic_transport, tcp_transport)
.map(|either_output, _| match either_output {
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
})
.boxed();
let mdns = mdns::async_io::Behaviour::new(mdns::Config::default(), local_peer_id).unwrap();
let request_handler = request_response::cbor::Behaviour::new([(StreamProtocol::new("/file-exchange/1"), ProtocolSupport::Full, )], request_response::Config::default());
let behaviour = NodeBehaviour { mdns, handler: request_handler, keep_live: libp2p::swarm::keep_alive::Behaviour::default() };
let mut swarm = SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id).build();
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
swarm.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?;
loop {
match swarm.select_next_some().await {
SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"),
SwarmEvent::Behaviour(NodeBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => {
for peer in list {
let mut peer_id = peer.0;
println!("mDNS discovered a new peer: {peer_id}");
// 测试发用文本
let req = { "Hi".to_string() };
swarm.behaviour_mut().handler.send_request(&mut peer_id, FileRequest(req));
}
}
SwarmEvent::Behaviour(NodeBehaviourEvent::Mdns(mdns::Event::Expired(list))) => {
for peer in list {
let peer_id = peer.0;
println!("mDNS discover peer has expired: {peer_id}");
}
}
SwarmEvent::Behaviour(NodeBehaviourEvent::Handler(request_response::Event::Message { message, .. }, )) => {
match message {
Message::Request { request, channel, .. } => {
println!("Message:{:?}", request);
}
Message::Response {request_id, response}=>{
}
}
}
_ => {}
}
}
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。