Giter Club home page Giter Club logo

searchlight's Introduction

License crates.io docs.rs Workflow Status

๐Ÿ“ก Searchlight

Searchlight is an mDNS server & client library designed to be simple, lightweight and easy to use, even if you just have basic knowledge about mDNS.

In layman's terms, Searchlight is a library for broadcasting and discovering "services" on a local network. This technology is part of the same technology used by Chromecast, AirDrop, Phillips Hue, and et cetera.

Searchlight is designed with user interfaces in mind. The defining feature of this library is that it keeps track of the presence of services on the network, and notifies you when they come and go, allowing you to update your user interface accordingly, providing a user experience that is responsive, intuitive and familiar to a scanning list for WiFi, Bluetooth, Chromecast, etc.

  • ๐ŸŒ IPv4 and IPv6 - Support for both IPv4 and IPv6.
  • โœจ OS support - Support for Windows, macOS and most UNIX systems.
  • ๐Ÿ“ก Broadcasting - Send out service announcements to the network and respond to discovery requests. (mDNS server)
  • ๐Ÿ‘ฝ Discovery - Discover services on the network and keep track of their presence. (mDNS client)
  • ๐Ÿงต Single threaded - Searchlight operates on just a single thread, thanks to the Tokio async runtime & task scheduler.
  • ๐Ÿคธ Flexible API - No async, no streams, no channels, no bullsh*t. Just provide an event handler function and bridge the gap between your application and Searchlight however you like.
  • ๐Ÿ‘ป Background runtime - Discovery and broadcasting can both run in the background on separate threads, providing a handle to gracefully shut down if necessary.
  • ๐Ÿ“จ UDP - All networking, including discovery and broadcasting, is connectionless and done over UDP.
  • ๐Ÿ” Loopback - Support for receiving packets sent by the same socket, intended to be used in tests.
  • ๐ŸŽฏ Interface targeting - Support for targeting specific network interface(s) for discovery and broadcasting.

Usage

Add Searchlight to your Cargo.toml file:

[dependencies]
searchlight = "0.3.2"

To learn more about how to use Searchlight, see the documentation.

Examples

๐Ÿ‘ฝ Discovery

Find all Chromecasts on the network.

use searchlight::{
    discovery::{DiscoveryBuilder, DiscoveryEvent},
    dns::{op::DnsResponse, rr::RData},
    net::IpVersion,
};

fn get_chromecast_name(dns_packet: &DnsResponse) -> String {
    dns_packet
        .additionals()
        .iter()
        .find_map(|record| {
            if let Some(RData::SRV(_)) = record.data() {
                let name = record.name().to_utf8();
                let name = name.strip_suffix('.').unwrap_or(&name);
                let name = name.strip_suffix("_googlecast._tcp.local").unwrap_or(&name);
                let name = name.strip_suffix('.').unwrap_or(&name);
                Some(name.to_string())
            } else {
                None
            }
        })
        .unwrap_or_else(|| "Unknown".into())
}

DiscoveryBuilder::new()
    .service("_googlecast._tcp.local.")
    .unwrap()
    .build(IpVersion::Both)
    .unwrap()
    .run(|event| match event {
        DiscoveryEvent::ResponderFound(responder) => {
            println!(
                "Found Chromecast {} at {}",
                get_chromecast_name(&responder.last_response),
                responder.addr.ip()
            );
        }
        DiscoveryEvent::ResponderLost(responder) => {
            println!(
                "Chromecast {} at {} has gone away",
                get_chromecast_name(&responder.last_response),
                responder.addr.ip()
            );
        }
        DiscoveryEvent::ResponseUpdate { .. } => {}
    })
    .unwrap();

๐Ÿ“ก Broadcasting

Broadcast a service on the network, and verify that it can be discovered.

use searchlight::{
    broadcast::{BroadcasterBuilder, ServiceBuilder},
    discovery::{DiscoveryBuilder, DiscoveryEvent},
    net::IpVersion,
};
use std::{
    net::{IpAddr, Ipv4Addr},
    str::FromStr,
};

let (found_tx, found_rx) = std::sync::mpsc::sync_channel(0);

let broadcaster = BroadcasterBuilder::new()
    .loopback()
    .add_service(
        ServiceBuilder::new("_searchlight._udp.local.", "HELLO-WORLD", 1234)
            .unwrap()
            .add_ip_address(IpAddr::V4(Ipv4Addr::from_str("192.168.1.69").unwrap()))
            .add_txt_truncated("key=value")
            .add_txt_truncated("key2=value2")
            .build()
            .unwrap(),
    )
    .build(IpVersion::V4)
    .unwrap()
    .run_in_background();

let discovery = DiscoveryBuilder::new()
    .loopback()
    .service("_searchlight._udp.local.")
    .unwrap()
    .build(IpVersion::V4)
    .unwrap()
    .run_in_background(move |event| {
        if let DiscoveryEvent::ResponderFound(responder) = event {
            found_tx.try_send(responder).ok();
        }
    });

println!("Waiting for discovery to find responder...");

println!("{:#?}", found_rx.recv().unwrap());

println!("Shutting down...");

broadcaster.shutdown().unwrap();
discovery.shutdown().unwrap();

println!("Done!");

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the MIT license, shall be dual licensed as above, without any additional terms or conditions.

searchlight's People

Contributors

williamvenner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

searchlight's Issues

MacOS <-> Linux not discovering each other.

Hello, and thanks for that library! I use it for device discovery in Capyloon (in https://github.com/capyloon/api-daemon/blob/main/services/dweb/src/mdns.rs) and it works great overall!

Discovery works as expected among Linux peers and with Android based devices. However I can't manage MacOS devices to see Linux ones and to be discovered.

When running dns-sd -B _services._dns-sd._udp my service doesn't show up, but I can see devices listed when querying for the service itself. In searchlight, no event is getting triggered:

capyloon/searchlight (master)> dns-sd -B _services._dns-sd._udp
Browsing for _services._dns-sd._udp
DATE: ---Tue 11 Apr 2023---
15:39:48.237  ...STARTING...
Timestamp     A/R    Flags  if Domain               Service Type         Instance Name
15:39:48.238  Add        3  12 .                    _tcp.local.          _printer
15:39:48.238  Add        3  12 .                    _tcp.local.          _pdl-datastream
15:39:48.238  Add        3  12 .                    _tcp.local.          _http
15:39:48.238  Add        3  12 .                    _tcp.local.          _scanner
15:39:48.238  Add        3  12 .                    _tcp.local.          _ipp
15:39:48.238  Add        3  12 .                    _tcp.local.          _ipps
15:39:48.238  Add        3  12 .                    _tcp.local.          _privet
15:39:48.238  Add        3  12 .                    _tcp.local.          _uscan
15:39:48.238  Add        3  12 .                    _tcp.local.          _uscans
15:39:48.238  Add        2  12 .                    _tcp.local.          _androidtvremote2
15:39:48.427  Add        3  12 .                    _tcp.local.          _spotify-connect
15:39:48.427  Add        2  12 .                    _tcp.local.          _sonos
15:39:49.417  Add        2  12 .                    _udp.local.          _p2p
15:39:49.427  Add        2  12 .                    _tcp.local.          _googlecast

^C
capyloon/searchlight (master)> dns-sd -B _capyloon._tcp
Browsing for _capyloon._tcp
DATE: ---Tue 11 Apr 2023---
15:40:09.164  ...STARTING...
Timestamp     A/R    Flags  if Domain               Service Type         Instance Name
15:40:09.165  Add        3  12 local.               _capyloon._tcp.      capyloon-8e9aaf127aebe67eb7e75cacf81a1eba
15:40:09.165  Add        3  12 local.               _capyloon._tcp.      capyloon-b338c0ec4de99ff41a016944988af4c2
15:40:09.165  Add        2  12 local.               _capyloon._tcp.      capyloon-f3272b79d0b70cab2f67dabfd7f2c1d0

Any hint about what could be missing is welcome!

Executable not working

Problem: when I run with cargo run, it works fine, but when I try to run it with the executables in the target directory (both release and debug), it stucks at Waiting for discovery to find responder...

Note: nothing special going on, I am just using the broadcast.rs example.

Pls help, thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.