Skip to content

Instantly share code, notes, and snippets.

@fdstevex
Created May 15, 2016 02:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fdstevex/8d92ebac3a9c93e8d8c18d2743ac1c71 to your computer and use it in GitHub Desktop.
Save fdstevex/8d92ebac3a9c93e8d8c18d2743ac1c71 to your computer and use it in GitHub Desktop.
Swift command-line script to find Bonjour services on your local network.
#!/usr/bin/swift
// Swift script to search for Bonjour services on the local network.
// Found services are printed to the console.
import Foundation
import CoreFoundation
// Inner search, finds services of a particular type
class ServicesDiscoverer : NSObject, NSNetServiceBrowserDelegate {
let browser = NSNetServiceBrowser()
let service: NSNetService
let allServicesDiscoverer: AllServicesDiscoverer
// Save the list of services until we have them all before printing
var serviceNames = Array<String>()
init(service: NSNetService, allServicesDiscoverer: AllServicesDiscoverer) {
self.service = service
self.allServicesDiscoverer = allServicesDiscoverer
super.init()
browser.delegate = self
}
func start() {
let parts = service.type.componentsSeparatedByString(".")
let type = "\(service.name).\(parts[0])."
browser.searchForServicesOfType(type, inDomain: "local.")
}
func netServiceBrowser(browser: NSNetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
self.allServicesDiscoverer.removeDiscoverer(self);
}
func netServiceBrowserDidStopSearch(browser: NSNetServiceBrowser) {
self.allServicesDiscoverer.removeDiscoverer(self);
}
func netServiceBrowser(browser: NSNetServiceBrowser, didFindService service: NSNetService, moreComing: Bool) {
serviceNames.append(service.name)
if (!moreComing) {
NSOperationQueue.mainQueue().addOperationWithBlock {
for name in self.serviceNames {
print("\(self.service.name) \(self.service.type) \"\(name)\"")
}
print("")
self.allServicesDiscoverer.removeDiscoverer(self);
}
}
}
}
// Outer search, searches for all the types of services available, and uses
// ServicesDiscoverer to search for instances of those services.
class AllServicesDiscoverer : NSObject, NSNetServiceBrowserDelegate, NSNetServiceDelegate {
let browser = NSNetServiceBrowser()
var serviceDiscoverers = Set<ServicesDiscoverer>()
var searchComplete = false
func start() {
browser.delegate = self
browser.searchForServicesOfType("_services._dns-sd._udp.", inDomain: "local.")
}
func removeDiscoverer(discoverer: ServicesDiscoverer) {
serviceDiscoverers.remove(discoverer)
if (searchComplete && serviceDiscoverers.isEmpty) {
exit(0)
}
}
func netServiceBrowser(browser: NSNetServiceBrowser, didFindService service: NSNetService, moreComing: Bool) {
let serviceDiscoverer = ServicesDiscoverer(service:service, allServicesDiscoverer: self)
serviceDiscoverers.insert(serviceDiscoverer)
serviceDiscoverer.start()
if (!moreComing) {
searchComplete = true
}
}
}
// Start the search
let serviceDiscoverer = AllServicesDiscoverer()
serviceDiscoverer.start()
// The search is asynchronous, so run the run loop and let the end of the search exit the process.
NSRunLoop.currentRunLoop().run()
@mendirattanishant
Copy link

Updated to Swift 5:

class ServicesDiscoverer : NSObject, NetServiceBrowserDelegate {
    let browser = NetServiceBrowser()
    let service: NetService
    let allServicesDiscoverer: AllServicesDiscoverer
    
    // Save the list of services until we have them all before printing
    var serviceNames = Array<String>()
    
    init(service: NetService, allServicesDiscoverer: AllServicesDiscoverer) {
        self.service = service
        self.allServicesDiscoverer = allServicesDiscoverer
        super.init()
        browser.delegate = self
    }

    func start() {
        let parts = service.type.components(separatedBy: ".")
        let type = "\(service.name).\(parts[0])."
        browser.searchForServices(ofType: type, inDomain: "local.")
    }

    func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
        self.allServicesDiscoverer.removeDiscoverer(discoverer: self);
    }
    
    func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
        self.allServicesDiscoverer.removeDiscoverer(discoverer: self);
    }

    func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
        serviceNames.append(service.name)
        if (!moreComing) {
            OperationQueue.main.addOperation {
                for name in self.serviceNames {
                    print("\(self.service.name) \(self.service.type) \"\(name)\"")
                }
                print("")
                
                self.allServicesDiscoverer.removeDiscoverer(discoverer: self);
            }
        }
    }
}

// Outer search, searches for all the types of services available, and uses
// ServicesDiscoverer to search for instances of those services.
class AllServicesDiscoverer : NSObject, NetServiceBrowserDelegate, NetServiceDelegate {
    
    let browser = NetServiceBrowser()
    var serviceDiscoverers = Set<ServicesDiscoverer>()
    var searchComplete = false
    
    func start() {
        browser.delegate = self
        browser.searchForServices(ofType: "_services._dns-sd._udp.", inDomain: "local.")
    }
    
    func removeDiscoverer(discoverer: ServicesDiscoverer) {
        serviceDiscoverers.remove(discoverer)

        if (searchComplete && serviceDiscoverers.isEmpty) {
            exit(0)
        }
    }
    
    func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
        let serviceDiscoverer = ServicesDiscoverer(service:service, allServicesDiscoverer: self)
        serviceDiscoverers.insert(serviceDiscoverer)
        serviceDiscoverer.start()
        
        if (!moreComing) {
            searchComplete = true
        }
    }
}

 // Start the search
let serviceDiscoverer = AllServicesDiscoverer()
serviceDiscoverer.start()

// The search is asynchronous, so run the run loop and let the end of the search exit the process.
RunLoop.current.run()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment