em_ws_discovery 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/Gemfile +2 -0
 - data/History.rdoc +7 -0
 - data/README.rdoc +77 -0
 - data/Rakefile +16 -0
 - data/em_ws_discovery.gemspec +32 -0
 - data/lib/ws_discovery.rb +61 -0
 - data/lib/ws_discovery/core_ext/socket_patch.rb +16 -0
 - data/lib/ws_discovery/error.rb +4 -0
 - data/lib/ws_discovery/multicast_connection.rb +77 -0
 - data/lib/ws_discovery/network_constants.rb +13 -0
 - data/lib/ws_discovery/response.rb +104 -0
 - data/lib/ws_discovery/searcher.rb +93 -0
 - data/lib/ws_discovery/version.rb +3 -0
 - data/spec/spec_helper.rb +26 -0
 - data/spec/ws_discovery/multicast_connection_spec.rb +108 -0
 - data/spec/ws_discovery/response_spec.rb +118 -0
 - data/spec/ws_discovery/searcher_spec.rb +85 -0
 - data/spec/ws_discovery_spec.rb +43 -0
 - metadata +229 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 93d68c56aa005b016b846239e46d917572eca2ae
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a72c499cae86b83efac040c6dfbbaebc76a14643
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: bdd03e310cb58aa1559e35f0c07b688cd18b5212dd341386dddaa228388fec0ab7372af1da98fbc1a24d34cdedfdd9cf6f22546214f6ac87561a57096ba937b8
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: bdb1976aba0ec6160ff7246a5a53ceafc86bce9615b2679385b8d72345fb77c30e4c8be1bfcb6fb1694c3d74c34d45c266b46734318f1f19907d1c4e379e1e5a
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/History.rdoc
    ADDED
    
    
    
        data/README.rdoc
    ADDED
    
    | 
         @@ -0,0 +1,77 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            = ws_discovery
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            * {Homepage}[https://github.com/pelco-automation/ws-discovery]
         
     | 
| 
      
 4 
     | 
    
         
            +
            * {WS-Discovery 1.0 Specification}[http://specs.xmlsoap.org/ws/2005/04/discovery/ws-discovery.pdf]
         
     | 
| 
      
 5 
     | 
    
         
            +
            * {SOAP-over-UDP Specification}[http://specs.xmlsoap.org/ws/2004/09/soap-over-udp/soap-over-udp.pdf]
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            == Description
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            This gem aims to provide the ability to search for WS-Discovery compatible target
         
     | 
| 
      
 10 
     | 
    
         
            +
            services.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            This uses EventMachine[http://github.com/eventmachine/eventmachine], so if
         
     | 
| 
      
 13 
     | 
    
         
            +
            you're not already, getting familiar with its concepts will be helpful here.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            == Features
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            * Search for WS-Discovery compatible target services.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            == Examples
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            === WS-Discovery Searches
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            A WS-Discovery search simply sends the probe out to the multicast group and
         
     | 
| 
      
 24 
     | 
    
         
            +
            listens for responses for a given (or default of 5 seconds) amount of time.  The
         
     | 
| 
      
 25 
     | 
    
         
            +
            return from this depends on if you're running it within an EventMachine reactor
         
     | 
| 
      
 26 
     | 
    
         
            +
            or not.  If not, it returns an Array of responses as WSDiscovery::Responses.
         
     | 
| 
      
 27 
     | 
    
         
            +
            Take a look at the WSDiscovery#search docs for more on the options here.
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              require 'ws_discovery'
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              # Search for all devices (do a probe with Types left unspecified)
         
     | 
| 
      
 32 
     | 
    
         
            +
              all_devices = WSDiscovery.search                         # this is default
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              # Search for devices of a specific Type
         
     | 
| 
      
 35 
     | 
    
         
            +
              network_video_transmitters = WSDiscovery.search(
         
     | 
| 
      
 36 
     | 
    
         
            +
                env_namespaces: { "xmlns:dn" => "http://www.onvif.org/ver10/network/wsdl" },
         
     | 
| 
      
 37 
     | 
    
         
            +
                types: "dn:NetworkVideoTransmitter")
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              # These searches will return an Array of WSDiscovery::Responses.  See the
         
     | 
| 
      
 40 
     | 
    
         
            +
              # WSDiscovery::Response documentation for more information.
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            If you do the search inside of an EventMachine reactor, as the
         
     | 
| 
      
 43 
     | 
    
         
            +
            WSDiscovery::Searcher receives and parses responses, it adds them to the accessor
         
     | 
| 
      
 44 
     | 
    
         
            +
            #discovery_responses, which is an EventMachine::Channel.  This lets you subscribe
         
     | 
| 
      
 45 
     | 
    
         
            +
            to the responses and do what you want with them.
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            == Requirements
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            * Ruby
         
     | 
| 
      
 50 
     | 
    
         
            +
              * 1.9.3
         
     | 
| 
      
 51 
     | 
    
         
            +
            * Gems
         
     | 
| 
      
 52 
     | 
    
         
            +
              * builder
         
     | 
| 
      
 53 
     | 
    
         
            +
              * eventmachine
         
     | 
| 
      
 54 
     | 
    
         
            +
              * log_switch
         
     | 
| 
      
 55 
     | 
    
         
            +
              * nokogiri
         
     | 
| 
      
 56 
     | 
    
         
            +
              * nori
         
     | 
| 
      
 57 
     | 
    
         
            +
              * uuid
         
     | 
| 
      
 58 
     | 
    
         
            +
            * Gems (development)
         
     | 
| 
      
 59 
     | 
    
         
            +
              * bundler
         
     | 
| 
      
 60 
     | 
    
         
            +
              * rake
         
     | 
| 
      
 61 
     | 
    
         
            +
              * rspec
         
     | 
| 
      
 62 
     | 
    
         
            +
              * simplecov
         
     | 
| 
      
 63 
     | 
    
         
            +
              * simplecov-rcov
         
     | 
| 
      
 64 
     | 
    
         
            +
              * yard
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            == Install
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              $ gem install ws_discovery
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            == THANKS
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            The initial core of this gem came from https://github.com/turboladen/upnp due to
         
     | 
| 
      
 73 
     | 
    
         
            +
            the similarities in how SSDP and WS-Discovery searches are performed.
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            The WSDiscovery::Response class reuses parts of https://github.com/savonrb/savon.
         
     | 
| 
      
 76 
     | 
    
         
            +
            It made sense to me that WSDiscovery::Responses would behave similarly to
         
     | 
| 
      
 77 
     | 
    
         
            +
            Savon::SOAP::Responses.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'bundler/gem_tasks'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'yard'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            YARD::Rake::YardocTask.new
         
     | 
| 
      
 6 
     | 
    
         
            +
            RSpec::Core::RakeTask.new
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            RSpec::Core::RakeTask.new(:rcov) do |spec|
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.pattern = 'spec/**/*_spec.rb'
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.rcov = true
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            task default: :install
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            # Alias for rubygems-test
         
     | 
| 
      
 16 
     | 
    
         
            +
            task test: :spec
         
     | 
| 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.push File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ws_discovery/version'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 5 
     | 
    
         
            +
              s.name = "em_ws_discovery"
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.version = WSDiscovery::VERSION
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.homepage = "https://github.com/jimxl/em-ws-discovery"
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.author = "jimxl"
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.email = "tianxiaxl@gmail.com"
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.description = "ruby实现的ws_discovery, 基于ws-discovery项目"
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.summary = "ruby实现的ws_discovery, 基于ws-discovery项目"
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              s.required_rubygems_version = ">=1.8.0"
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.required_ruby_version = Gem::Requirement.new(">= 1.9.3")
         
     | 
| 
      
 15 
     | 
    
         
            +
              s.files = Dir.glob("{lib,spec}/**/*") + Dir.glob("*.rdoc") +
         
     | 
| 
      
 16 
     | 
    
         
            +
                %w(Gemfile em_ws_discovery.gemspec Rakefile)
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.require_paths = ["lib"]
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              s.add_dependency("builder")
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.add_dependency("eventmachine")
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.add_dependency("log_switch", ">=0.1.4")
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_dependency("nokogiri")
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_dependency("nori", '>=2.0.0')
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_dependency("uuid")
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              s.add_development_dependency("bundler", ">= 1.0.21")
         
     | 
| 
      
 27 
     | 
    
         
            +
              s.add_development_dependency("rake", ">= 0")
         
     | 
| 
      
 28 
     | 
    
         
            +
              s.add_development_dependency("rspec", "~> 2.6")
         
     | 
| 
      
 29 
     | 
    
         
            +
              s.add_development_dependency("simplecov", ">= 0")
         
     | 
| 
      
 30 
     | 
    
         
            +
              s.add_development_dependency("simplecov-rcov", ">= 0")
         
     | 
| 
      
 31 
     | 
    
         
            +
              s.add_development_dependency("yard", ">= 0.7.2")
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/ws_discovery.rb
    ADDED
    
    | 
         @@ -0,0 +1,61 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'ws_discovery/core_ext/socket_patch'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'eventmachine'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'ws_discovery/error'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'ws_discovery/network_constants'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'ws_discovery/searcher'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module WSDiscovery
         
     | 
| 
      
 9 
     | 
    
         
            +
              include NetworkConstants
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              DEFAULT_WAIT_TIME = 5
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              # Opens a UDP socket on 0.0.0.0, on an ephemeral port, has WSDiscovery::Searcher
         
     | 
| 
      
 14 
     | 
    
         
            +
              # build and send the search request, then receives the responses.  The search
         
     | 
| 
      
 15 
     | 
    
         
            +
              # will stop after +response_wait_time+.
         
     | 
| 
      
 16 
     | 
    
         
            +
              #
         
     | 
| 
      
 17 
     | 
    
         
            +
              # @param [Hash] options The options for the probe.
         
     | 
| 
      
 18 
     | 
    
         
            +
              # @option options [Hash<String>] :env_namespaces Additional envelope namespaces.
         
     | 
| 
      
 19 
     | 
    
         
            +
              # @option options [Hash<String>] :type_attributes Type attributes.
         
     | 
| 
      
 20 
     | 
    
         
            +
              # @option options [String] :types Types.
         
     | 
| 
      
 21 
     | 
    
         
            +
              # @option options [Hash<String>] :scope_attributes Scope attributes.
         
     | 
| 
      
 22 
     | 
    
         
            +
              # @option options [String] :scopes Scopes.
         
     | 
| 
      
 23 
     | 
    
         
            +
              # @return [Array<WSDiscovery::Response>,WSDiscovery::Searcher] Returns an
         
     | 
| 
      
 24 
     | 
    
         
            +
              #   Array of probe responses. If the reactor is already running this will return
         
     | 
| 
      
 25 
     | 
    
         
            +
              #   a WSDiscovery::Searcher which will make its accessors available so you can
         
     | 
| 
      
 26 
     | 
    
         
            +
              #   get responses in real time.
         
     | 
| 
      
 27 
     | 
    
         
            +
              def self.search(options={})
         
     | 
| 
      
 28 
     | 
    
         
            +
                response_wait_time = options[:response_wait_time] || DEFAULT_WAIT_TIME
         
     | 
| 
      
 29 
     | 
    
         
            +
                responses = []
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                multicast_searcher = proc do
         
     | 
| 
      
 32 
     | 
    
         
            +
                  EM.open_datagram_socket('0.0.0.0', 0, WSDiscovery::Searcher, options)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                if EM.reactor_running?
         
     | 
| 
      
 36 
     | 
    
         
            +
                  return multicast_searcher.call
         
     | 
| 
      
 37 
     | 
    
         
            +
                else
         
     | 
| 
      
 38 
     | 
    
         
            +
                  EM.run do
         
     | 
| 
      
 39 
     | 
    
         
            +
                    ms = multicast_searcher.call
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    ms.discovery_responses.subscribe do |notification|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      responses << notification
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    EM.add_timer(response_wait_time) { EM.stop }
         
     | 
| 
      
 46 
     | 
    
         
            +
                    trap_signals
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                responses.flatten
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              private
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              # Traps INT, TERM, and HUP signals and stops the reactor.
         
     | 
| 
      
 56 
     | 
    
         
            +
              def self.trap_signals
         
     | 
| 
      
 57 
     | 
    
         
            +
                trap('INT') { EM.stop }
         
     | 
| 
      
 58 
     | 
    
         
            +
                trap('TERM') { EM.stop }
         
     | 
| 
      
 59 
     | 
    
         
            +
                trap('HUP') { EM.stop } if RUBY_PLATFORM !~ /mswin|mingw/
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Workaround for missing constants on Windows
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Socket::Constants
         
     | 
| 
      
 5 
     | 
    
         
            +
              IP_ADD_MEMBERSHIP = 12 unless defined? IP_ADD_MEMBERSHIP
         
     | 
| 
      
 6 
     | 
    
         
            +
              IP_MULTICAST_LOOP = 11 unless defined? IP_MULTICAST_LOOP
         
     | 
| 
      
 7 
     | 
    
         
            +
              IP_MULTICAST_TTL  = 10 unless defined? IP_MULTICAST_TTL
         
     | 
| 
      
 8 
     | 
    
         
            +
              IP_TTL            =  4 unless defined? IP_TTL
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            class Socket
         
     | 
| 
      
 12 
     | 
    
         
            +
              IP_ADD_MEMBERSHIP = 12 unless defined? IP_ADD_MEMBERSHIP
         
     | 
| 
      
 13 
     | 
    
         
            +
              IP_MULTICAST_LOOP = 11 unless defined? IP_MULTICAST_LOOP
         
     | 
| 
      
 14 
     | 
    
         
            +
              IP_MULTICAST_TTL  = 10 unless defined? IP_MULTICAST_TTL
         
     | 
| 
      
 15 
     | 
    
         
            +
              IP_TTL            =  4 unless defined? IP_TTL
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,77 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'core_ext/socket_patch'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'network_constants'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'error'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'ipaddr'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'eventmachine'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module WSDiscovery
         
     | 
| 
      
 9 
     | 
    
         
            +
              class MulticastConnection < EventMachine::Connection
         
     | 
| 
      
 10 
     | 
    
         
            +
                include WSDiscovery::NetworkConstants
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                # @param [Fixnum] ttl The TTL value to use when opening the UDP socket
         
     | 
| 
      
 13 
     | 
    
         
            +
                #   required for WSDiscovery actions.
         
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize ttl=TTL
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @ttl = ttl
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @discovery_responses = EM::Channel.new
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  setup_multicast_socket
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                private
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                # Gets the IP and port from the peer that just sent data.
         
     | 
| 
      
 24 
     | 
    
         
            +
                #
         
     | 
| 
      
 25 
     | 
    
         
            +
                # @return [Array<String,Fixnum>] The IP and port.
         
     | 
| 
      
 26 
     | 
    
         
            +
                def peer_info
         
     | 
| 
      
 27 
     | 
    
         
            +
                  peer_bytes = get_peername[2, 6].unpack("nC4")
         
     | 
| 
      
 28 
     | 
    
         
            +
                  port = peer_bytes.first.to_i
         
     | 
| 
      
 29 
     | 
    
         
            +
                  ip = peer_bytes[1, 4].join(".")
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  [ip, port]
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # Sets Socket options to allow for multicasting.  If ENV["RUBY_TESTING_ENV"]
         
     | 
| 
      
 35 
     | 
    
         
            +
                # is equal to "testing", then it doesn't turn off multicast looping.
         
     | 
| 
      
 36 
     | 
    
         
            +
                def setup_multicast_socket
         
     | 
| 
      
 37 
     | 
    
         
            +
                  set_membership(IPAddr.new(MULTICAST_IP).hton + IPAddr.new('0.0.0.0').hton)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  set_multicast_ttl(@ttl)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  set_ttl(@ttl)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  unless ENV["RUBY_TESTING_ENV"] == "testing"
         
     | 
| 
      
 42 
     | 
    
         
            +
                    switch_multicast_loop :off
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # @param [String] membership The network byte ordered String that represents
         
     | 
| 
      
 47 
     | 
    
         
            +
                #   the IP(s) that should join the membership group.
         
     | 
| 
      
 48 
     | 
    
         
            +
                def set_membership(membership)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, membership)
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                # @param [Fixnum] ttl TTL to set IP_MULTICAST_TTL to.
         
     | 
| 
      
 53 
     | 
    
         
            +
                def set_multicast_ttl(ttl)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, [ttl].pack('i'))
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                # @param [Fixnum] ttl TTL to set IP_TTL to.
         
     | 
| 
      
 58 
     | 
    
         
            +
                def set_ttl(ttl)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_TTL, [ttl].pack('i'))
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                # @param [Symbol] on_off Turn on/off multicast looping.  Supply :on or :off.
         
     | 
| 
      
 63 
     | 
    
         
            +
                # @raise [WSDiscovery::Error] If invalid option is given.
         
     | 
| 
      
 64 
     | 
    
         
            +
                def switch_multicast_loop(on_off)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  hex_value = case on_off
         
     | 
| 
      
 66 
     | 
    
         
            +
                  when :on, "\001"
         
     | 
| 
      
 67 
     | 
    
         
            +
                    "\001"
         
     | 
| 
      
 68 
     | 
    
         
            +
                  when :off, "\000"
         
     | 
| 
      
 69 
     | 
    
         
            +
                    "\000"
         
     | 
| 
      
 70 
     | 
    
         
            +
                  else
         
     | 
| 
      
 71 
     | 
    
         
            +
                    raise WSDiscovery::Error, "Can't switch IP_MULTICAST_LOOP to '#{on_off}'"
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_LOOP, hex_value)
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
              end
         
     | 
| 
      
 77 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,104 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'nori'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'error'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module WSDiscovery
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              # Represents the probe response.
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Response
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                attr_accessor :response
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                # @param [String] response Text of the response to a WSDiscovery probe.
         
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(response)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @response = response
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                # Shortcut accessor for the SOAP response body Hash.
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @param [Symbol] key The key to access in the body Hash.
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @return [Hash,String] The accessed value.
         
     | 
| 
      
 21 
     | 
    
         
            +
                def [](key)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  body[key]
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                # Returns the SOAP response header as a Hash.
         
     | 
| 
      
 26 
     | 
    
         
            +
                #
         
     | 
| 
      
 27 
     | 
    
         
            +
                # @return [Hash] SOAP response header.
         
     | 
| 
      
 28 
     | 
    
         
            +
                # @raise [WSDiscovery::Error] If unable to parse response.
         
     | 
| 
      
 29 
     | 
    
         
            +
                def header
         
     | 
| 
      
 30 
     | 
    
         
            +
                  unless hash.has_key? :envelope
         
     | 
| 
      
 31 
     | 
    
         
            +
                    raise WSDiscovery::Error, "Unable to parse response body '#{to_xml}'"
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  hash[:envelope][:header]
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                # Returns the SOAP response body as a Hash.
         
     | 
| 
      
 38 
     | 
    
         
            +
                #
         
     | 
| 
      
 39 
     | 
    
         
            +
                # @return [Hash] SOAP response body.
         
     | 
| 
      
 40 
     | 
    
         
            +
                # @raise [WSDiscovery::Error] If unable to parse response.
         
     | 
| 
      
 41 
     | 
    
         
            +
                def body
         
     | 
| 
      
 42 
     | 
    
         
            +
                  unless hash.has_key? :envelope
         
     | 
| 
      
 43 
     | 
    
         
            +
                    raise WSDiscovery::Error, "Unable to parse response body '#{to_xml}'"
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  hash[:envelope][:body]
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                alias to_hash body
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                # Returns the complete SOAP response XML without normalization.
         
     | 
| 
      
 52 
     | 
    
         
            +
                #
         
     | 
| 
      
 53 
     | 
    
         
            +
                # @return [Hash] Complete SOAP response Hash.
         
     | 
| 
      
 54 
     | 
    
         
            +
                def hash
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @hash ||= nori.parse(to_xml)
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                # Returns the SOAP response XML.
         
     | 
| 
      
 59 
     | 
    
         
            +
                #
         
     | 
| 
      
 60 
     | 
    
         
            +
                # @return [String] Raw SOAP response XML.
         
     | 
| 
      
 61 
     | 
    
         
            +
                def to_xml
         
     | 
| 
      
 62 
     | 
    
         
            +
                  response
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                # Returns a Nokogiri::XML::Document for the SOAP response XML.
         
     | 
| 
      
 66 
     | 
    
         
            +
                #
         
     | 
| 
      
 67 
     | 
    
         
            +
                # @return [Nokogiri::XML::Document] Document for the SOAP response.
         
     | 
| 
      
 68 
     | 
    
         
            +
                def doc
         
     | 
| 
      
 69 
     | 
    
         
            +
                  @doc ||= Nokogiri::XML(to_xml)
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                # Returns an Array of Nokogiri::XML::Node objects retrieved with the given +path+.
         
     | 
| 
      
 73 
     | 
    
         
            +
                # Automatically adds all of the document's namespaces unless a +namespaces+ hash is provided.
         
     | 
| 
      
 74 
     | 
    
         
            +
                #
         
     | 
| 
      
 75 
     | 
    
         
            +
                # @param [String] path XPath to search.
         
     | 
| 
      
 76 
     | 
    
         
            +
                # @param [Hash<String>] namespaces Namespaces to append.
         
     | 
| 
      
 77 
     | 
    
         
            +
                def xpath(path, namespaces = nil)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  doc.xpath(path, namespaces || xml_namespaces)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                private
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                # XML Namespaces from the Document.
         
     | 
| 
      
 84 
     | 
    
         
            +
                #
         
     | 
| 
      
 85 
     | 
    
         
            +
                # @return [Hash] Namespaces from the Document.
         
     | 
| 
      
 86 
     | 
    
         
            +
                def xml_namespaces
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @xml_namespaces ||= doc.collect_namespaces
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                # Returns a Nori parser.
         
     | 
| 
      
 91 
     | 
    
         
            +
                #
         
     | 
| 
      
 92 
     | 
    
         
            +
                # @return [Nori] Nori parser.
         
     | 
| 
      
 93 
     | 
    
         
            +
                def nori
         
     | 
| 
      
 94 
     | 
    
         
            +
                  return @nori if @nori
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  nori_options = {
         
     | 
| 
      
 97 
     | 
    
         
            +
                    strip_namespaces: true,
         
     | 
| 
      
 98 
     | 
    
         
            +
                    convert_tags_to: lambda { |tag| tag.snakecase.to_sym }
         
     | 
| 
      
 99 
     | 
    
         
            +
                  }
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  @nori = Nori.new(nori_options)
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'multicast_connection'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'response'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'builder'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'log_switch'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'uuid'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class WSDiscovery::Searcher < WSDiscovery::MulticastConnection
         
     | 
| 
      
 8 
     | 
    
         
            +
                extend LogSwitch
         
     | 
| 
      
 9 
     | 
    
         
            +
                self.logger.datetime_format = "%Y-%m-%d %H:%M:%S "
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # @return [EventMachine::Channel] Provides subscribers with responses from
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   their search request.
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :discovery_responses
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # @param [Hash] options The options for the probe.
         
     | 
| 
      
 16 
     | 
    
         
            +
                # @option options [Hash<String>] :env_namespaces Additional envelope namespaces.
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @option options [Hash<String>] :type_attributes Type attributes.
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @option options [String] :types Types.
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @option options [Hash<String>] :scope_attributes Scope attributes.
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @option options [String] :scopes Scopes.
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @option options [Fixnum] :ttl TTL for the probe.
         
     | 
| 
      
 22 
     | 
    
         
            +
                def initialize(options={})
         
     | 
| 
      
 23 
     | 
    
         
            +
                    options[:ttl] ||= TTL
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    @search = probe(options)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    super options[:ttl]
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                # This is the callback called by EventMachine when it receives data on the
         
     | 
| 
      
 31 
     | 
    
         
            +
                # socket that's been opened for this connection.  In this case, the method
         
     | 
| 
      
 32 
     | 
    
         
            +
                # parses the probe matches into WSDiscovery::Responses and adds them to the
         
     | 
| 
      
 33 
     | 
    
         
            +
                # appropriate EventMachine::Channel (provided as accessor methods).  This
         
     | 
| 
      
 34 
     | 
    
         
            +
                # effectively means that in each Channel, you get a WSDiscovery::Response
         
     | 
| 
      
 35 
     | 
    
         
            +
                # for each response that comes in on the socket.
         
     | 
| 
      
 36 
     | 
    
         
            +
                #
         
     | 
| 
      
 37 
     | 
    
         
            +
                # @param [String] response The data received on this connection's socket.
         
     | 
| 
      
 38 
     | 
    
         
            +
                def receive_data(response)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    ip, port = peer_info
         
     | 
| 
      
 40 
     | 
    
         
            +
                    #WSDiscovery::Searcher.log "<#{self.class}> Response from #{ip}:#{port}:\n#{response}\n"
         
     | 
| 
      
 41 
     | 
    
         
            +
                    parsed_response = parse(response)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @discovery_responses << parsed_response
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # Converts the headers to a set of key-value pairs.
         
     | 
| 
      
 46 
     | 
    
         
            +
                #
         
     | 
| 
      
 47 
     | 
    
         
            +
                # @param [String] data The data to convert.
         
     | 
| 
      
 48 
     | 
    
         
            +
                # @return [WSDiscovery::Response] The converted data.
         
     | 
| 
      
 49 
     | 
    
         
            +
                def parse(data)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    WSDiscovery::Response.new(data)
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # Sends the probe that was built during init.  Logs what was sent if the
         
     | 
| 
      
 54 
     | 
    
         
            +
                # send was successful.
         
     | 
| 
      
 55 
     | 
    
         
            +
                def post_init
         
     | 
| 
      
 56 
     | 
    
         
            +
                    if send_datagram(@search, MULTICAST_IP, MULTICAST_PORT) > 0
         
     | 
| 
      
 57 
     | 
    
         
            +
                        WSDiscovery::Searcher.log("Sent datagram search:\n#{@search}")
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                # Probe for target services supporting WS-Discovery.
         
     | 
| 
      
 62 
     | 
    
         
            +
                #
         
     | 
| 
      
 63 
     | 
    
         
            +
                # @param [Hash] options The options for the probe.
         
     | 
| 
      
 64 
     | 
    
         
            +
                # @option options [Hash<String>] :env_namespaces Additional envelope namespaces.
         
     | 
| 
      
 65 
     | 
    
         
            +
                # @option options [Hash<String>] :type_attributes Type attributes.
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @option options [String] :types Types.
         
     | 
| 
      
 67 
     | 
    
         
            +
                # @option options [Hash<String>] :scope_attributes Scope attributes.
         
     | 
| 
      
 68 
     | 
    
         
            +
                # @option options [String] :scopes Scopes.
         
     | 
| 
      
 69 
     | 
    
         
            +
                # @return [String] Probe SOAP message.
         
     | 
| 
      
 70 
     | 
    
         
            +
                def probe(options={})
         
     | 
| 
      
 71 
     | 
    
         
            +
                    namespaces = {
         
     | 
| 
      
 72 
     | 
    
         
            +
                        'xmlns:a' => 'http://schemas.xmlsoap.org/ws/2004/08/addressing',
         
     | 
| 
      
 73 
     | 
    
         
            +
                        'xmlns:d' => 'http://schemas.xmlsoap.org/ws/2005/04/discovery',
         
     | 
| 
      
 74 
     | 
    
         
            +
                        'xmlns:s' => 'http://www.w3.org/2003/05/soap-envelope'
         
     | 
| 
      
 75 
     | 
    
         
            +
                    }
         
     | 
| 
      
 76 
     | 
    
         
            +
                    namespaces.merge! options[:env_namespaces] if options[:env_namespaces]
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    Builder::XmlMarkup.new.s(:Envelope, namespaces) do |xml|
         
     | 
| 
      
 79 
     | 
    
         
            +
                        xml.s(:Header) do
         
     | 
| 
      
 80 
     | 
    
         
            +
                            xml.a(:Action, 'http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe')
         
     | 
| 
      
 81 
     | 
    
         
            +
                            xml.a(:MessageID, "uuid:#{UUID.generate}")
         
     | 
| 
      
 82 
     | 
    
         
            +
                            xml.a(:To, 'urn:schemas-xmlsoap-org:ws:2005:04:discovery')
         
     | 
| 
      
 83 
     | 
    
         
            +
                        end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                        xml.s(:Body) do
         
     | 
| 
      
 86 
     | 
    
         
            +
                            xml.d(:Probe) do 
         
     | 
| 
      
 87 
     | 
    
         
            +
                                xml.d(:Types, options[:type_attributes], options[:types])
         
     | 
| 
      
 88 
     | 
    
         
            +
                                xml.d(:Scopes, options[:scope_attributes], options[:scopes])
         
     | 
| 
      
 89 
     | 
    
         
            +
                            end
         
     | 
| 
      
 90 
     | 
    
         
            +
                        end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    end
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'simplecov'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'simplecov-rcov'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class SimpleCov::Formatter::MergedFormatter
         
     | 
| 
      
 5 
     | 
    
         
            +
              def format(result)
         
     | 
| 
      
 6 
     | 
    
         
            +
                SimpleCov::Formatter::HTMLFormatter.new.format(result)
         
     | 
| 
      
 7 
     | 
    
         
            +
                SimpleCov::Formatter::RcovFormatter.new.format(result)
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            SimpleCov.start do
         
     | 
| 
      
 14 
     | 
    
         
            +
              add_filter "/spec"
         
     | 
| 
      
 15 
     | 
    
         
            +
              add_filter "/lib/deps"
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 19 
     | 
    
         
            +
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'rspec'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # Requires supporting files with custom matchers and macros, etc,
         
     | 
| 
      
 23 
     | 
    
         
            +
            # in ./support/ and its subdirectories.
         
     | 
| 
      
 24 
     | 
    
         
            +
            Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |file| require file }
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            ENV["RUBY_TESTING_ENV"] = "testing"
         
     | 
| 
         @@ -0,0 +1,108 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ws_discovery/multicast_connection'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe WSDiscovery::MulticastConnection do
         
     | 
| 
      
 5 
     | 
    
         
            +
              around(:each) do |example|
         
     | 
| 
      
 6 
     | 
    
         
            +
                EM.run do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  example.run
         
     | 
| 
      
 8 
     | 
    
         
            +
                  EM.stop
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              subject { WSDiscovery::MulticastConnection.new(1) }
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              describe "#peer_info" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                before do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:setup_multicast_socket)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  subject.stub_chain(:get_peername, :[], :unpack).and_return(%w(1234 1 2 3 4))
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                it "returns an Array with IP and port" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                  subject.send(:peer_info).should == ['1.2.3.4', 1234]
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                it "returns IP as a String" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  subject.send(:peer_info).first.should be_a String
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                it "returns port as a Fixnum" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  subject.send(:peer_info).last.should be_a Fixnum
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              describe "#setup_multicast_socket" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                before do
         
     | 
| 
      
 35 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:set_membership)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:switch_multicast_loop)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:set_multicast_ttl)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:set_ttl)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                it "adds 0.0.0.0 and 239.255.255.250 to the membership group" do
         
     | 
| 
      
 42 
     | 
    
         
            +
                  subject.should_receive(:set_membership).with(
         
     | 
| 
      
 43 
     | 
    
         
            +
                    IPAddr.new('239.255.255.250').hton + IPAddr.new('0.0.0.0').hton
         
     | 
| 
      
 44 
     | 
    
         
            +
                  )
         
     | 
| 
      
 45 
     | 
    
         
            +
                  subject.send(:setup_multicast_socket)
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                it "sets multicast TTL to 1" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                  subject.should_receive(:set_multicast_ttl).with(1)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  subject.send(:setup_multicast_socket)
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                it "sets TTL to 1" do
         
     | 
| 
      
 54 
     | 
    
         
            +
                  subject.should_receive(:set_ttl).with(1)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  subject.send(:setup_multicast_socket)
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                context "ENV['RUBY_TESTING_ENV'] != testing" do
         
     | 
| 
      
 59 
     | 
    
         
            +
                  after { ENV['RUBY_TESTING_ENV'] = "testing" }
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  it "turns multicast loop off" do
         
     | 
| 
      
 62 
     | 
    
         
            +
                    ENV['RUBY_TESTING_ENV'] = "development"
         
     | 
| 
      
 63 
     | 
    
         
            +
                    subject.should_receive(:switch_multicast_loop).with(:off)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    subject.send(:setup_multicast_socket)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              describe "#switch_multicast_loop" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                before do
         
     | 
| 
      
 71 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:setup_multicast_socket)
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                it "passes '\\001' to the socket option call when param == :on" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                  subject.should_receive(:set_sock_opt).with(
         
     | 
| 
      
 76 
     | 
    
         
            +
                    0, Socket::IP_MULTICAST_LOOP, "\001"
         
     | 
| 
      
 77 
     | 
    
         
            +
                  )
         
     | 
| 
      
 78 
     | 
    
         
            +
                  subject.send(:switch_multicast_loop, :on)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                it "passes '\\001' to the socket option call when param == '\\001'" do
         
     | 
| 
      
 82 
     | 
    
         
            +
                  subject.should_receive(:set_sock_opt).with(
         
     | 
| 
      
 83 
     | 
    
         
            +
                    0, Socket::IP_MULTICAST_LOOP, "\001"
         
     | 
| 
      
 84 
     | 
    
         
            +
                  )
         
     | 
| 
      
 85 
     | 
    
         
            +
                  subject.send(:switch_multicast_loop,"\001")
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                it "passes '\\000' to the socket option call when param == :off" do
         
     | 
| 
      
 89 
     | 
    
         
            +
                  subject.should_receive(:set_sock_opt).with(
         
     | 
| 
      
 90 
     | 
    
         
            +
                    0, Socket::IP_MULTICAST_LOOP, "\000"
         
     | 
| 
      
 91 
     | 
    
         
            +
                  )
         
     | 
| 
      
 92 
     | 
    
         
            +
                  subject.send(:switch_multicast_loop,:off)
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                it "passes '\\000' to the socket option call when param == '\\000'" do
         
     | 
| 
      
 96 
     | 
    
         
            +
                  subject.should_receive(:set_sock_opt).with(
         
     | 
| 
      
 97 
     | 
    
         
            +
                    0, Socket::IP_MULTICAST_LOOP, "\000"
         
     | 
| 
      
 98 
     | 
    
         
            +
                  )
         
     | 
| 
      
 99 
     | 
    
         
            +
                  subject.send(:switch_multicast_loop,"\000")
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                it "raises when not :on, :off, '\\000', or '\\001'" do
         
     | 
| 
      
 103 
     | 
    
         
            +
                  expect { subject.send(:switch_multicast_loop, 12312312) }.
         
     | 
| 
      
 104 
     | 
    
         
            +
                    to raise_error(WSDiscovery::Error)
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
              end
         
     | 
| 
      
 107 
     | 
    
         
            +
            end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,118 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ws_discovery/response'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe WSDiscovery::Response do
         
     | 
| 
      
 5 
     | 
    
         
            +
              let(:probe_response) do
         
     | 
| 
      
 6 
     | 
    
         
            +
                <<-PROBE
         
     | 
| 
      
 7 
     | 
    
         
            +
                  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
         
     | 
| 
      
 8 
     | 
    
         
            +
                    xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
         
     | 
| 
      
 9 
     | 
    
         
            +
                    xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery">
         
     | 
| 
      
 10 
     | 
    
         
            +
                    <s:Header>
         
     | 
| 
      
 11 
     | 
    
         
            +
                      <a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
         
     | 
| 
      
 12 
     | 
    
         
            +
                      <a:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</a:Action>
         
     | 
| 
      
 13 
     | 
    
         
            +
                      <a:MessageID>urn:uuid:18523f7e-7a54-d92d-a18d-e7165bec8e7e</a:MessageID>
         
     | 
| 
      
 14 
     | 
    
         
            +
                      <a:RelatesTo>uuid:7dbdede0-0f2b-0130-5861-002564b29b24</a:RelatesTo>
         
     | 
| 
      
 15 
     | 
    
         
            +
                      <d:AppSequence MessageNumber="42" InstanceId="2"/>
         
     | 
| 
      
 16 
     | 
    
         
            +
                    </s:Header>
         
     | 
| 
      
 17 
     | 
    
         
            +
                    <s:Body>
         
     | 
| 
      
 18 
     | 
    
         
            +
                      <d:ProbeMatches>
         
     | 
| 
      
 19 
     | 
    
         
            +
                        <d:ProbeMatch>
         
     | 
| 
      
 20 
     | 
    
         
            +
                          <a:EndpointReference>
         
     | 
| 
      
 21 
     | 
    
         
            +
                            <a:Address>urn:uuid:0b679890-fc54-14ba-d428-f73b3e7c2400</a:Address>
         
     | 
| 
      
 22 
     | 
    
         
            +
                          </a:EndpointReference>
         
     | 
| 
      
 23 
     | 
    
         
            +
                          <d:Types xmlns:dn="http://www.onvif.org/ver10/network/wsdl">dn:NetworkVideoTransmitter</d:Types>
         
     | 
| 
      
 24 
     | 
    
         
            +
                          <d:Scopes>onvif://www.onvif.org/Profile/Streaming onvif://www.onvif.org/hardware/NET5404T onvif://www.onvif.org/type/ptz onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/location/country/usa onvif://www.onvif.org/name/NET5404T-ABEPZH7</d:Scopes>
         
     | 
| 
      
 25 
     | 
    
         
            +
                          <d:XAddrs>http://10.221.222.74/onvif/device_service</d:XAddrs>
         
     | 
| 
      
 26 
     | 
    
         
            +
                          <d:MetadataVersion>1</d:MetadataVersion>
         
     | 
| 
      
 27 
     | 
    
         
            +
                        </d:ProbeMatch>
         
     | 
| 
      
 28 
     | 
    
         
            +
                      </d:ProbeMatches>
         
     | 
| 
      
 29 
     | 
    
         
            +
                    </s:Body>
         
     | 
| 
      
 30 
     | 
    
         
            +
                  </s:Envelope>
         
     | 
| 
      
 31 
     | 
    
         
            +
                PROBE
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              let(:probe_body_hash) do
         
     | 
| 
      
 35 
     | 
    
         
            +
                { probe_matches: {
         
     | 
| 
      
 36 
     | 
    
         
            +
                  probe_match: {
         
     | 
| 
      
 37 
     | 
    
         
            +
                    endpoint_reference: {
         
     | 
| 
      
 38 
     | 
    
         
            +
                      address: "urn:uuid:0b679890-fc54-14ba-d428-f73b3e7c2400" },
         
     | 
| 
      
 39 
     | 
    
         
            +
                    types: "dn:NetworkVideoTransmitter",
         
     | 
| 
      
 40 
     | 
    
         
            +
                    scopes: "onvif://www.onvif.org/Profile/Streaming onvif://www.onvif.org/hardware/NET5404T onvif://www.onvif.org/type/ptz onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/location/country/usa onvif://www.onvif.org/name/NET5404T-ABEPZH7",
         
     | 
| 
      
 41 
     | 
    
         
            +
                    x_addrs: "http://10.221.222.74/onvif/device_service",
         
     | 
| 
      
 42 
     | 
    
         
            +
                    metadata_version: "1" } } }
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              let(:probe_header_hash) do
         
     | 
| 
      
 46 
     | 
    
         
            +
                { to: "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous",
         
     | 
| 
      
 47 
     | 
    
         
            +
                  action: "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches",
         
     | 
| 
      
 48 
     | 
    
         
            +
                  message_id: "urn:uuid:18523f7e-7a54-d92d-a18d-e7165bec8e7e",
         
     | 
| 
      
 49 
     | 
    
         
            +
                  relates_to: "uuid:7dbdede0-0f2b-0130-5861-002564b29b24",
         
     | 
| 
      
 50 
     | 
    
         
            +
                  app_sequence: {
         
     | 
| 
      
 51 
     | 
    
         
            +
                    :@message_number => "42",
         
     | 
| 
      
 52 
     | 
    
         
            +
                    :@instance_id => "2" } }
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              let(:probe_full_hash) do
         
     | 
| 
      
 56 
     | 
    
         
            +
                { envelope: { header: probe_header_hash, body: probe_body_hash,
         
     | 
| 
      
 57 
     | 
    
         
            +
                  :"@xmlns:s" => "http://www.w3.org/2003/05/soap-envelope",
         
     | 
| 
      
 58 
     | 
    
         
            +
                  :"@xmlns:a" => "http://schemas.xmlsoap.org/ws/2004/08/addressing",
         
     | 
| 
      
 59 
     | 
    
         
            +
                  :"@xmlns:d" => "http://schemas.xmlsoap.org/ws/2005/04/discovery" } }
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              subject { WSDiscovery::Response.new(probe_response) }
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              describe "#[]" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                it "should return the SOAP response body as a Hash" do
         
     | 
| 
      
 66 
     | 
    
         
            +
                  subject[:probe_matches].should == probe_body_hash[:probe_matches]
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                it "should throw an exception when the response body isn't parsable" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                  expect { WSDiscovery::Response.new('').body }.to raise_error WSDiscovery::Error
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              describe "#header" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                it "should return the SOAP response header as a Hash" do
         
     | 
| 
      
 76 
     | 
    
         
            +
                  subject.header[:app_sequence].should == probe_header_hash[:app_sequence]
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                it "should throw an exception when the response header isn't parsable" do
         
     | 
| 
      
 80 
     | 
    
         
            +
                  expect { WSDiscovery::Response.new('').header }.to raise_error WSDiscovery::Error
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
              %w(body to_hash).each do |method|
         
     | 
| 
      
 85 
     | 
    
         
            +
                describe "##{method}" do
         
     | 
| 
      
 86 
     | 
    
         
            +
                  it "should return the SOAP response body as a Hash" do
         
     | 
| 
      
 87 
     | 
    
         
            +
                    subject.send(method)[:probe_matches].should == probe_body_hash[:probe_matches]
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              describe "#hash" do
         
     | 
| 
      
 93 
     | 
    
         
            +
                it "should return the complete SOAP response XML as a Hash" do
         
     | 
| 
      
 94 
     | 
    
         
            +
                  subject.hash.should == probe_full_hash
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              describe "#to_xml" do
         
     | 
| 
      
 99 
     | 
    
         
            +
                it "should return the raw SOAP response body" do
         
     | 
| 
      
 100 
     | 
    
         
            +
                  subject.to_xml.should == probe_response
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              describe "#doc" do
         
     | 
| 
      
 105 
     | 
    
         
            +
                it "returns a Nokogiri::XML::Document for the SOAP response XML" do
         
     | 
| 
      
 106 
     | 
    
         
            +
                  subject.doc.should be_a(Nokogiri::XML::Document)
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
              describe "#xpath" do
         
     | 
| 
      
 111 
     | 
    
         
            +
                it "permits XPath access to elements in the request" do
         
     | 
| 
      
 112 
     | 
    
         
            +
                  subject.xpath("//a:Address").first.inner_text.
         
     | 
| 
      
 113 
     | 
    
         
            +
                    should == "urn:uuid:0b679890-fc54-14ba-d428-f73b3e7c2400"
         
     | 
| 
      
 114 
     | 
    
         
            +
                  subject.xpath("//d:ProbeMatch/d:XAddrs").first.inner_text.
         
     | 
| 
      
 115 
     | 
    
         
            +
                    should == "http://10.221.222.74/onvif/device_service"
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,85 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ws_discovery/searcher'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe WSDiscovery::Searcher do
         
     | 
| 
      
 5 
     | 
    
         
            +
              let(:default_probe) do
         
     | 
| 
      
 6 
     | 
    
         
            +
                "<s:Envelope xmlns:a=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" " +
         
     | 
| 
      
 7 
     | 
    
         
            +
                  "xmlns:d=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" xmlns:s=\"h" +
         
     | 
| 
      
 8 
     | 
    
         
            +
                  "ttp://www.w3.org/2003/05/soap-envelope\"><s:Header><a:Action>http://sch" +
         
     | 
| 
      
 9 
     | 
    
         
            +
                  "emas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action><a:MessageID>uuid" +
         
     | 
| 
      
 10 
     | 
    
         
            +
                  ":a-uuid</a:MessageID><a:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery" +
         
     | 
| 
      
 11 
     | 
    
         
            +
                  "</a:To></s:Header><s:Body><d:Types/><d:Scopes/></s:Body></s:Envelope>"
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              around(:each) do |example|
         
     | 
| 
      
 15 
     | 
    
         
            +
                EM.run do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  example.run
         
     | 
| 
      
 17 
     | 
    
         
            +
                  EM.stop
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              before do
         
     | 
| 
      
 22 
     | 
    
         
            +
                WSDiscovery::Searcher.log = false
         
     | 
| 
      
 23 
     | 
    
         
            +
                WSDiscovery::MulticastConnection.any_instance.stub(:setup_multicast_socket)
         
     | 
| 
      
 24 
     | 
    
         
            +
                UUID.stub(:generate).and_return('a-uuid')
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              subject do
         
     | 
| 
      
 28 
     | 
    
         
            +
                WSDiscovery::Searcher.new(1)
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              describe "#initialize" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                it "does a #probe" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                  WSDiscovery::Searcher.any_instance.should_receive(:probe)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  subject
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              describe "#receive_data" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                let(:parsed_response) do
         
     | 
| 
      
 41 
     | 
    
         
            +
                  double 'parsed response'
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                it "takes a response and adds it to the list of responses" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  response = double 'response'
         
     | 
| 
      
 46 
     | 
    
         
            +
                  subject.stub(:peer_info).and_return(['0.0.0.0', 4567])
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  subject.should_receive(:parse).with(response).exactly(1).times.
         
     | 
| 
      
 49 
     | 
    
         
            +
                    and_return(parsed_response)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  subject.instance_variable_get(:@discovery_responses).should_receive(:<<).
         
     | 
| 
      
 51 
     | 
    
         
            +
                    with(parsed_response)
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  subject.receive_data(response)
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              describe "#parse" do
         
     | 
| 
      
 58 
     | 
    
         
            +
                before do
         
     | 
| 
      
 59 
     | 
    
         
            +
                  WSDiscovery::MulticastConnection.any_instance.stub(:setup_multicast_socket)
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                it "turns probe matches into WSDiscovery::Responses" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                  result = subject.parse "<Envelope />"
         
     | 
| 
      
 64 
     | 
    
         
            +
                  result.should be_a WSDiscovery::Response
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              describe "#post_init" do
         
     | 
| 
      
 69 
     | 
    
         
            +
                before { WSDiscovery::Searcher.any_instance.stub(:m_search).and_return("hi") }
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                it "sends a probe as a datagram over 239.255.255.250:3702" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                  subject.should_receive(:send_datagram).
         
     | 
| 
      
 73 
     | 
    
         
            +
                    with(default_probe, '239.255.255.250', 3702).
         
     | 
| 
      
 74 
     | 
    
         
            +
                    and_return 0
         
     | 
| 
      
 75 
     | 
    
         
            +
                  subject.post_init
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              describe "#probe" do
         
     | 
| 
      
 80 
     | 
    
         
            +
                it "builds the MSEARCH string using the given parameters" do
         
     | 
| 
      
 81 
     | 
    
         
            +
                  subject.probe.should == default_probe
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
            end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ws_discovery'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe WSDiscovery do
         
     | 
| 
      
 5 
     | 
    
         
            +
              subject { WSDiscovery }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              describe '.search' do
         
     | 
| 
      
 8 
     | 
    
         
            +
                let(:multicast_searcher) do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  searcher = double "WSDiscovery::Searcher"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  searcher.stub_chain(:discovery_responses, :subscribe).and_yield(%w[one two])
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  searcher
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                before do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  EM.stub(:run).and_yield
         
     | 
| 
      
 17 
     | 
    
         
            +
                  EM.stub(:add_timer)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  EM.stub(:open_datagram_socket).and_return multicast_searcher
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                context "reactor is already running" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  it "returns a WSDiscovery::Searcher" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    EM.stub(:reactor_running?).and_return true
         
     | 
| 
      
 24 
     | 
    
         
            +
                    subject.search.should == multicast_searcher
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                context "reactor is not already running" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  it "returns an Array of responses" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                    EM.stub(:add_shutdown_hook).and_yield
         
     | 
| 
      
 31 
     | 
    
         
            +
                    subject.search.should == %w[one two]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  it "opens a UDP socket on '0.0.0.0', port 0" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                    EM.stub(:add_shutdown_hook)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    EM.should_receive(:open_datagram_socket).with('0.0.0.0', 0,
         
     | 
| 
      
 37 
     | 
    
         
            +
                      WSDiscovery::Searcher, {})
         
     | 
| 
      
 38 
     | 
    
         
            +
                    subject.search
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,229 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: em_ws_discovery
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.2
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - jimxl
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2013-07-02 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: builder
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: eventmachine
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: log_switch
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: 0.1.4
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: 0.1.4
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: nokogiri
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 70 
     | 
    
         
            +
              name: nori
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 75 
     | 
    
         
            +
                    version: 2.0.0
         
     | 
| 
      
 76 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 77 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 79 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 80 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 81 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 82 
     | 
    
         
            +
                    version: 2.0.0
         
     | 
| 
      
 83 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 84 
     | 
    
         
            +
              name: uuid
         
     | 
| 
      
 85 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 86 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 87 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 88 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 89 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 90 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 91 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 92 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 93 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 94 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 95 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 96 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 97 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 98 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 99 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 100 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 101 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 102 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 103 
     | 
    
         
            +
                    version: 1.0.21
         
     | 
| 
      
 104 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 105 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 106 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 107 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 108 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 109 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 110 
     | 
    
         
            +
                    version: 1.0.21
         
     | 
| 
      
 111 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 112 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 113 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 114 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 115 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 116 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 117 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 118 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 119 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 120 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 121 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 122 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 123 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 124 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 125 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 126 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 127 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 128 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 129 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 130 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 131 
     | 
    
         
            +
                    version: '2.6'
         
     | 
| 
      
 132 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 133 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 134 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 135 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 136 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 137 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 138 
     | 
    
         
            +
                    version: '2.6'
         
     | 
| 
      
 139 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 140 
     | 
    
         
            +
              name: simplecov
         
     | 
| 
      
 141 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 142 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 143 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 144 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 145 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 146 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 147 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 148 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 149 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 150 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 151 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 152 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 153 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 154 
     | 
    
         
            +
              name: simplecov-rcov
         
     | 
| 
      
 155 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 156 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 157 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 158 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 159 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 160 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 161 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 162 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 163 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 164 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 165 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 166 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 167 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 168 
     | 
    
         
            +
              name: yard
         
     | 
| 
      
 169 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 170 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 171 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 172 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 173 
     | 
    
         
            +
                    version: 0.7.2
         
     | 
| 
      
 174 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 175 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 176 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 177 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 178 
     | 
    
         
            +
                - - '>='
         
     | 
| 
      
 179 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 180 
     | 
    
         
            +
                    version: 0.7.2
         
     | 
| 
      
 181 
     | 
    
         
            +
            description: ruby实现的ws_discovery, 基于ws-discovery项目
         
     | 
| 
      
 182 
     | 
    
         
            +
            email: tianxiaxl@gmail.com
         
     | 
| 
      
 183 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 184 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 185 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 186 
     | 
    
         
            +
            files:
         
     | 
| 
      
 187 
     | 
    
         
            +
            - lib/ws_discovery.rb
         
     | 
| 
      
 188 
     | 
    
         
            +
            - lib/ws_discovery/error.rb
         
     | 
| 
      
 189 
     | 
    
         
            +
            - lib/ws_discovery/multicast_connection.rb
         
     | 
| 
      
 190 
     | 
    
         
            +
            - lib/ws_discovery/searcher.rb
         
     | 
| 
      
 191 
     | 
    
         
            +
            - lib/ws_discovery/network_constants.rb
         
     | 
| 
      
 192 
     | 
    
         
            +
            - lib/ws_discovery/version.rb
         
     | 
| 
      
 193 
     | 
    
         
            +
            - lib/ws_discovery/response.rb
         
     | 
| 
      
 194 
     | 
    
         
            +
            - lib/ws_discovery/core_ext/socket_patch.rb
         
     | 
| 
      
 195 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 196 
     | 
    
         
            +
            - spec/ws_discovery_spec.rb
         
     | 
| 
      
 197 
     | 
    
         
            +
            - spec/ws_discovery/multicast_connection_spec.rb
         
     | 
| 
      
 198 
     | 
    
         
            +
            - spec/ws_discovery/searcher_spec.rb
         
     | 
| 
      
 199 
     | 
    
         
            +
            - spec/ws_discovery/response_spec.rb
         
     | 
| 
      
 200 
     | 
    
         
            +
            - History.rdoc
         
     | 
| 
      
 201 
     | 
    
         
            +
            - README.rdoc
         
     | 
| 
      
 202 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 203 
     | 
    
         
            +
            - em_ws_discovery.gemspec
         
     | 
| 
      
 204 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 205 
     | 
    
         
            +
            homepage: https://github.com/jimxl/em-ws-discovery
         
     | 
| 
      
 206 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 207 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 208 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 209 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 210 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 211 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 212 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 213 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 214 
     | 
    
         
            +
              - - '>='
         
     | 
| 
      
 215 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 216 
     | 
    
         
            +
                  version: 1.9.3
         
     | 
| 
      
 217 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 218 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 219 
     | 
    
         
            +
              - - '>='
         
     | 
| 
      
 220 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 221 
     | 
    
         
            +
                  version: 1.8.0
         
     | 
| 
      
 222 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 223 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 224 
     | 
    
         
            +
            rubygems_version: 2.0.3
         
     | 
| 
      
 225 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 226 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 227 
     | 
    
         
            +
            summary: ruby实现的ws_discovery, 基于ws-discovery项目
         
     | 
| 
      
 228 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 229 
     | 
    
         
            +
            has_rdoc: 
         
     |