Created
October 14, 2010 09:24
-
-
Save millenomi/625930 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env ruby | |
| require 'osx/cocoa' | |
| require 'optparse' | |
| include OSX | |
| $service_name = nil | |
| $service_port = nil | |
| $service_type = nil | |
| $service_txt = {} | |
| target_plist_file = nil | |
| $avail_debug = false | |
| def log(s) | |
| $stderr.puts s if $avail_debug | |
| end | |
| OptionParser.new do |o| | |
| o.on('-s', '--service TYPE', 'The Bonjour service type to publish.') do |name| | |
| $service_type = name | |
| end | |
| o.on('-n', '--name NAME', 'The name of the service. If unspecified, uses hostname') do |name| | |
| $service_name = name | |
| end | |
| o.on('-p', '--port NAME', 'The port to publish.') do |port| | |
| $service_port = port.to_i | |
| end | |
| o.on('-t', '--txt VAL', 'The value to add to the service data dictionary. VAL is of the form "key=value". Strings will be encoded as UTF-8.') do |val| | |
| split = val.split('=') | |
| key = split[0] | |
| split.delete_at 0 | |
| value = split.join('=') | |
| $service_txt[key] = value | |
| end | |
| o.on('-P', '--launchd-plist FILE', 'If specified, does not run. Instead, produces a launchd plist file that runs this copy of $0 with the same parameters you passed in.') do |file| | |
| target_plist_file = file | |
| end | |
| o.on('-D', '--debug', 'Shows debug output.') do | |
| $avail_debug = true | |
| end | |
| o.on('--http PATH', 'Shorthand that registers a HTTP service on the given port. You can still provide a name with -n and a port with -p.') do |path| | |
| $service_type = '_http._tcp.' | |
| $service_txt['path'] = path | |
| end | |
| end.parse! | |
| raise "You must specify both service type and port!" unless $service_type and $service_port | |
| if target_plist_file | |
| label = File.basename(target_plist_file, '.plist') | |
| args = [ | |
| File.expand_path(__FILE__), | |
| '-s', $service_type, | |
| '-p', $service_port.to_s | |
| ] | |
| if $service_name | |
| args << '-n' | |
| args << $service_name | |
| end | |
| $service_txt.each do |key, value| | |
| args << '-t' | |
| args << "#{key}=#{value}" | |
| end | |
| if $avail_debug | |
| args << '--debug' | |
| end | |
| plist = { | |
| 'Label' => label, | |
| 'ProgramArguments' => args, | |
| 'KeepAlive' => true, | |
| 'RunAtLoad' => true, | |
| } | |
| saved = NSDictionary.dictionaryWithDictionary(plist).writeToFile_atomically(target_plist_file, true) | |
| if saved | |
| exit 1 | |
| else | |
| exit 0 | |
| end | |
| end | |
| unless $service_name | |
| $service_name = NSHost.currentHost.name | |
| end | |
| class Publisher < NSObject | |
| def initialize() | |
| @running = true | |
| @services = {} | |
| @domains = [] | |
| @browser = NSNetServiceBrowser.alloc.init | |
| @browser.setDelegate self | |
| @browser.searchForRegistrationDomains | |
| log "Will start looking for domains." | |
| end | |
| def netServiceBrowser_didFindDomain_moreComing(browser, domain, coming) | |
| log "Domain found: #{domain}" | |
| return if @domains.include? domain | |
| domain = domain.to_s | |
| @domains << domain | |
| s = NSNetService.alloc.initWithDomain_type_name_port_(domain, $service_type, $service_name, $service_port) | |
| s.TXTRecordData = NSNetService.dataFromTXTRecordDictionary($service_txt) | |
| log "Created service: #{s}" | |
| s.setDelegate self | |
| @services[domain.to_s] = s | |
| log "Services now: #{@services.inspect}" | |
| s.publish | |
| end | |
| def netServiceBrowser_didRemoveDomain_moreComing(browser, domain, coming) | |
| domain = domain.to_s | |
| @domains.delete domain | |
| @services[domain].setDelegate nil | |
| @services[domain].stop | |
| @services.delete domain | |
| end | |
| def netServiceWillPublish(service) | |
| log "About to publish service: #{service}" | |
| end | |
| def netServiceDidPublish(service) | |
| log "Did publish service: #{service}" | |
| end | |
| def netService_didNotPublish(service, error) | |
| log "Did not publish #{service}, because: #{error}" | |
| @services[service.domain.to_s] = nil | |
| end | |
| def running | |
| @running | |
| end | |
| def stop_asap | |
| @running = false | |
| end | |
| def stop | |
| @services.each do |domain, service| | |
| service.setDelegate nil | |
| service.stop | |
| end | |
| @services = nil | |
| @domains = nil | |
| @browser.stop | |
| @browser.setDelegate nil | |
| @browser = nil | |
| end | |
| end | |
| publisher = Publisher.new | |
| trap "SIGTERM" do | |
| publisher.stop_asap | |
| end | |
| while publisher.running | |
| begin | |
| NSRunLoop.currentRunLoop.runUntilDate NSDate.dateWithTimeIntervalSinceNow(2) | |
| rescue Interrupt | |
| publisher.stop_asap | |
| end | |
| end | |
| publisher.stop |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment