frisky 0.1.0
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/.gemtest +0 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +23 -0
- data/History.md +3 -0
- data/LICENSE.md +23 -0
- data/README.md +185 -0
- data/Rakefile +16 -0
- data/features/device_discovery.feature +9 -0
- data/features/step_definitions/.gitkeep +0 -0
- data/features/support/env.rb +21 -0
- data/features/support/world_extensions.rb +7 -0
- data/frisky.gemspec +28 -0
- data/lib/core_ext/hash_patch.rb +5 -0
- data/lib/core_ext/socket_patch.rb +16 -0
- data/lib/core_ext/to_upnp_s.rb +65 -0
- data/lib/frisky.rb +5 -0
- data/lib/frisky/logger.rb +8 -0
- data/lib/frisky/ssdp.rb +188 -0
- data/lib/frisky/ssdp/broadcast_searcher.rb +114 -0
- data/lib/frisky/ssdp/error.rb +6 -0
- data/lib/frisky/ssdp/listener.rb +38 -0
- data/lib/frisky/ssdp/multicast_connection.rb +112 -0
- data/lib/frisky/ssdp/network_constants.rb +17 -0
- data/lib/frisky/ssdp/notifier.rb +41 -0
- data/lib/frisky/ssdp/searcher.rb +87 -0
- data/lib/frisky/version.rb +3 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/search_responses.rb +134 -0
- data/spec/unit/core_ext/to_upnp_s_spec.rb +105 -0
- data/spec/unit/frisky/ssdp/listener_spec.rb +29 -0
- data/spec/unit/frisky/ssdp/multicast_connection_spec.rb +157 -0
- data/spec/unit/frisky/ssdp/notifier_spec.rb +76 -0
- data/spec/unit/frisky/ssdp/searcher_spec.rb +110 -0
- data/spec/unit/frisky/ssdp_spec.rb +214 -0
- data/tasks/search.thor +35 -0
- metadata +181 -0
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'frisky/ssdp/notifier'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Frisky::SSDP::Notifier do
         | 
| 6 | 
            +
              around(:each) do |example|
         | 
| 7 | 
            +
                EM.synchrony do
         | 
| 8 | 
            +
                  example.run
         | 
| 9 | 
            +
                  EM.stop
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              let(:nt) { 'en tee' }
         | 
| 14 | 
            +
              let(:usn) { 'you ess en' }
         | 
| 15 | 
            +
              let(:ddf_url) { 'ddf url' }
         | 
| 16 | 
            +
              let(:duration) { 567 }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              subject do
         | 
| 19 | 
            +
                Frisky::SSDP::Notifier.new(1, nt, usn, ddf_url, duration)
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              describe '#initialize' do
         | 
| 23 | 
            +
                it 'creates a notification' do
         | 
| 24 | 
            +
                  expect_any_instance_of(Frisky::SSDP::Notifier).to receive(:notification).
         | 
| 25 | 
            +
                    with(nt, usn, ddf_url, duration)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  subject
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              describe '#post_init' do
         | 
| 32 | 
            +
                context 'send_datagram returns positive value' do
         | 
| 33 | 
            +
                  before do
         | 
| 34 | 
            +
                    expect(subject).to receive(:send_datagram).and_return 1
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  it 'logs what was sent' do
         | 
| 38 | 
            +
                    expect(subject).to receive(:log).with /Sent notification/
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    subject.post_init
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                context 'send_datagram returns 0' do
         | 
| 45 | 
            +
                  before do
         | 
| 46 | 
            +
                    expect(subject).to receive(:send_datagram).and_return 0
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  it 'does not log what was sent' do
         | 
| 50 | 
            +
                    expect(subject).to_not receive(:log)
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    subject.post_init
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              describe '#notification' do
         | 
| 58 | 
            +
                before do
         | 
| 59 | 
            +
                  subject.instance_variable_set(:@os, 'my OS')
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                it 'builds the notification message' do
         | 
| 63 | 
            +
                  expect(subject.notification(nt, usn, ddf_url, duration)).to eq <<-NOTE
         | 
| 64 | 
            +
            NOTIFY * HTTP/1.1\r
         | 
| 65 | 
            +
            HOST: 239.255.255.250:1900\r
         | 
| 66 | 
            +
            CACHE-CONTROL: max-age=567\r
         | 
| 67 | 
            +
            LOCATION: ddf url\r
         | 
| 68 | 
            +
            NT: en tee\r
         | 
| 69 | 
            +
            NTS: ssdp:alive\r
         | 
| 70 | 
            +
            SERVER: my OS UPnP/1.0 Frisky/#{Frisky::VERSION}\r
         | 
| 71 | 
            +
            USN: you ess en\r
         | 
| 72 | 
            +
            \r
         | 
| 73 | 
            +
                  NOTE
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| @@ -0,0 +1,110 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'frisky/ssdp/searcher'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Frisky::SSDP::Searcher do
         | 
| 6 | 
            +
              around(:each) do |example|
         | 
| 7 | 
            +
                EM.synchrony do
         | 
| 8 | 
            +
                  example.run
         | 
| 9 | 
            +
                  EM.stop
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              before do
         | 
| 14 | 
            +
                Frisky.logging_enabled = false
         | 
| 15 | 
            +
                allow_any_instance_of(Frisky::SSDP::MulticastConnection).to receive(:setup_multicast_socket)
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              subject do
         | 
| 19 | 
            +
                Frisky::SSDP::Searcher.new(1, 'ssdp:all', {})
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              it 'lets you read its responses' do
         | 
| 23 | 
            +
                responses = double 'responses'
         | 
| 24 | 
            +
                subject.instance_variable_set(:@discovery_responses, responses)
         | 
| 25 | 
            +
                expect(subject.discovery_responses).to eq responses
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              describe '#initialize' do
         | 
| 29 | 
            +
                it 'does an #m_search' do
         | 
| 30 | 
            +
                  expect_any_instance_of(Frisky::SSDP::Searcher).to receive(:m_search).and_return(<<-MSEARCH
         | 
| 31 | 
            +
            M-SEARCH * HTTP/1.1\r
         | 
| 32 | 
            +
            HOST: 239.255.255.250:1900\r
         | 
| 33 | 
            +
            MAN: "ssdp:discover"\r
         | 
| 34 | 
            +
            MX: 5\r
         | 
| 35 | 
            +
            ST: ssdp:all\r
         | 
| 36 | 
            +
            \r
         | 
| 37 | 
            +
                  MSEARCH
         | 
| 38 | 
            +
                  )
         | 
| 39 | 
            +
                  subject
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              describe '#receive_data' do
         | 
| 44 | 
            +
                let(:parsed_response) do
         | 
| 45 | 
            +
                  parsed_response = double 'parsed response'
         | 
| 46 | 
            +
                  expect(parsed_response).to receive(:has_key?).with(:nts).and_return false
         | 
| 47 | 
            +
                  expect(parsed_response).to receive(:[]).and_return false
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  parsed_response
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                it 'takes a response and adds it to the list of responses' do
         | 
| 53 | 
            +
                  response = double 'response'
         | 
| 54 | 
            +
                  allow(subject).to receive(:peer_info).and_return(['0.0.0.0', 4567])
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  expect(subject).to receive(:parse).with(response).exactly(1).times.
         | 
| 57 | 
            +
                    and_return(parsed_response)
         | 
| 58 | 
            +
                  expect(subject.instance_variable_get(:@discovery_responses)).to receive(:<<).
         | 
| 59 | 
            +
                    with(parsed_response)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  subject.receive_data(response)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              describe '#post_init' do
         | 
| 66 | 
            +
                before { allow_any_instance_of(Frisky::SSDP::Searcher).to receive(:m_search).and_return('hi') }
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                it 'sends an M-SEARCH as a datagram over 239.255.255.250:1900' do
         | 
| 69 | 
            +
                  m_search_count_times = subject.instance_variable_get(:@m_search_count)
         | 
| 70 | 
            +
                  expect(subject).to receive(:send_datagram).
         | 
| 71 | 
            +
                    with('hi', '239.255.255.250', 1900).
         | 
| 72 | 
            +
                    exactly(m_search_count_times).times.
         | 
| 73 | 
            +
                    and_return 0
         | 
| 74 | 
            +
                  subject.post_init
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              describe '#m_search' do
         | 
| 79 | 
            +
                it 'builds the MSEARCH string using the given parameters' do
         | 
| 80 | 
            +
                  expect(subject.m_search('ssdp:all', 10)).to eq <<-MSEARCH
         | 
| 81 | 
            +
            M-SEARCH * HTTP/1.1\r
         | 
| 82 | 
            +
            HOST: 239.255.255.250:1900\r
         | 
| 83 | 
            +
            MAN: "ssdp:discover"\r
         | 
| 84 | 
            +
            MX: 10\r
         | 
| 85 | 
            +
            ST: ssdp:all\r
         | 
| 86 | 
            +
            \r
         | 
| 87 | 
            +
                  MSEARCH
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                it 'uses 239.255.255.250 as the HOST IP' do
         | 
| 91 | 
            +
                  expect(subject.m_search('ssdp:all', 10)).to match(/HOST: 239.255.255.250/m)
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                it 'uses 1900 as the HOST port' do
         | 
| 95 | 
            +
                  expect(subject.m_search('ssdp:all', 10)).to match(/HOST:.*1900/m)
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                it 'lets you search for undefined search target types' do
         | 
| 99 | 
            +
                  expect(subject.m_search('spaceship', 10)).to eq <<-MSEARCH
         | 
| 100 | 
            +
            M-SEARCH * HTTP/1.1\r
         | 
| 101 | 
            +
            HOST: 239.255.255.250:1900\r
         | 
| 102 | 
            +
            MAN: "ssdp:discover"\r
         | 
| 103 | 
            +
            MX: 10\r
         | 
| 104 | 
            +
            ST: spaceship\r
         | 
| 105 | 
            +
            \r
         | 
| 106 | 
            +
                  MSEARCH
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
            end
         | 
| 110 | 
            +
             | 
| @@ -0,0 +1,214 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'frisky/ssdp'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Frisky::SSDP do
         | 
| 6 | 
            +
              subject { Frisky::SSDP }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              describe '.listen' do
         | 
| 9 | 
            +
                let(:listener) do
         | 
| 10 | 
            +
                  searcher = double 'Frisky::SSDP::Listener'
         | 
| 11 | 
            +
                  searcher.stub_chain(:alive_notifications, :pop).and_yield(%w[one two])
         | 
| 12 | 
            +
                  searcher.stub_chain(:byebye_notifications, :pop).and_yield(%w[three four])
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  searcher
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                before do
         | 
| 18 | 
            +
                  allow(EM).to receive(:run).and_yield
         | 
| 19 | 
            +
                  allow(EM).to receive(:add_timer)
         | 
| 20 | 
            +
                  allow(EM).to receive(:open_datagram_socket).and_return listener
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                context 'reactor is already running' do
         | 
| 24 | 
            +
                  it 'returns a Frisky::SSDP::Listener' do
         | 
| 25 | 
            +
                    allow(EM).to receive(:reactor_running?).and_return true
         | 
| 26 | 
            +
                    expect(subject.listen).to eq listener
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                context 'reactor is not already running' do
         | 
| 31 | 
            +
                  it 'returns a Hash of available and byebye responses' do
         | 
| 32 | 
            +
                    allow(EM).to receive(:add_shutdown_hook).and_yield
         | 
| 33 | 
            +
                    expect(subject.listen).to eq({
         | 
| 34 | 
            +
                      alive_notifications: %w[one two],
         | 
| 35 | 
            +
                      byebye_notifications: %w[three four]
         | 
| 36 | 
            +
                    })
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  it 'opens a UDP socket on 239.255.255.250, port 1900' do
         | 
| 40 | 
            +
                    allow(EM).to receive(:add_shutdown_hook)
         | 
| 41 | 
            +
                    expect(EM).to receive(:open_datagram_socket).with('239.255.255.250', 1900,
         | 
| 42 | 
            +
                      Frisky::SSDP::Listener, 4)
         | 
| 43 | 
            +
                    subject.listen
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              describe '.search' do
         | 
| 49 | 
            +
                let(:multicast_searcher) do
         | 
| 50 | 
            +
                  searcher = double 'Frisky::SSDP::Searcher'
         | 
| 51 | 
            +
                  searcher.stub_chain(:discovery_responses, :subscribe).and_yield(%w[one two])
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  searcher
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                let(:broadcast_searcher) do
         | 
| 57 | 
            +
                  searcher = double 'Frisky::SSDP::BroadcastSearcher'
         | 
| 58 | 
            +
                  searcher.stub_chain(:discovery_responses, :subscribe).and_yield(%w[three four])
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  searcher
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                before do
         | 
| 64 | 
            +
                  allow(EM).to receive(:run).and_yield
         | 
| 65 | 
            +
                  allow(EM).to receive(:add_timer)
         | 
| 66 | 
            +
                  allow(EM).to receive(:open_datagram_socket).and_return multicast_searcher
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                context 'when search_target is not a String' do
         | 
| 70 | 
            +
                  it 'calls #to_upnp_s on search_target' do
         | 
| 71 | 
            +
                    search_target = double('search_target')
         | 
| 72 | 
            +
                    expect(search_target).to receive(:to_upnp_s)
         | 
| 73 | 
            +
                    subject.search(search_target)
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                context 'when search_target is a String' do
         | 
| 78 | 
            +
                  it 'calls #to_upnp_s on search_target but does not alter it' do
         | 
| 79 | 
            +
                    search_target = "I'm a string"
         | 
| 80 | 
            +
                    expect(search_target).to receive(:to_upnp_s).and_call_original
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    expect(EM).to receive(:open_datagram_socket).with('0.0.0.0', 0,
         | 
| 83 | 
            +
                      Frisky::SSDP::Searcher, "I'm a string", {})
         | 
| 84 | 
            +
                    subject.search(search_target)
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                context 'reactor is already running' do
         | 
| 89 | 
            +
                  it 'returns a Frisky::SSDP::Searcher' do
         | 
| 90 | 
            +
                    allow(EM).to receive(:reactor_running?).and_return true
         | 
| 91 | 
            +
                    expect(subject.search).to eq multicast_searcher
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                context 'reactor is not already running' do
         | 
| 96 | 
            +
                  context 'options hash includes do_broadcast_search' do
         | 
| 97 | 
            +
                    before do
         | 
| 98 | 
            +
                      allow(EM).to receive(:open_datagram_socket).
         | 
| 99 | 
            +
                        and_return(multicast_searcher, broadcast_searcher)
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    it 'returns an Array of responses' do
         | 
| 103 | 
            +
                      allow(EM).to receive(:add_shutdown_hook).and_yield
         | 
| 104 | 
            +
                      expect(subject.search(:all, do_broadcast_search: true)).to eq %w[one two three four]
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                    it 'opens 2 UDP sockets on 0.0.0.0, port 0' do
         | 
| 108 | 
            +
                      allow(EM).to receive(:add_shutdown_hook)
         | 
| 109 | 
            +
                      expect(EM).to receive(:open_datagram_socket).with('0.0.0.0', 0, Frisky::SSDP::Searcher,
         | 
| 110 | 
            +
                        'ssdp:all', {})
         | 
| 111 | 
            +
                      expect(EM).to receive(:open_datagram_socket).with('0.0.0.0', 0, Frisky::SSDP::BroadcastSearcher,
         | 
| 112 | 
            +
                        'ssdp:all', 5, 4)
         | 
| 113 | 
            +
                      subject.search(:all, do_broadcast_search: true)
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  context 'options hash does not include do_broadcast_search' do
         | 
| 118 | 
            +
                    it 'returns an Array of responses' do
         | 
| 119 | 
            +
                      allow(EM).to receive(:add_shutdown_hook).and_yield
         | 
| 120 | 
            +
                      expect(subject.search).to eq %w[one two]
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                    it 'opens a UDP socket on 0.0.0.0, port 0' do
         | 
| 124 | 
            +
                      allow(EM).to receive(:add_shutdown_hook)
         | 
| 125 | 
            +
                      expect(EM).to receive(:open_datagram_socket).with('0.0.0.0', 0, Frisky::SSDP::Searcher,
         | 
| 126 | 
            +
                        'ssdp:all', {})
         | 
| 127 | 
            +
                      subject.search
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
              describe '.notify' do
         | 
| 134 | 
            +
                pending 'Implementation of UPnP Devices'
         | 
| 135 | 
            +
              end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              describe '.send_notification' do
         | 
| 138 | 
            +
                pending 'Implementation of UPnP Devices'
         | 
| 139 | 
            +
              end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            =begin
         | 
| 142 | 
            +
                context 'by default' do
         | 
| 143 | 
            +
                  it "searches for 'ssdp:all'" do
         | 
| 144 | 
            +
                    pending
         | 
| 145 | 
            +
                  end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                  it 'waits for 5 seconds for responses' do
         | 
| 148 | 
            +
                    before = Time.now
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                    SSDP.search
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                    after = Time.now
         | 
| 153 | 
            +
                    (after - before).should < 5.1
         | 
| 154 | 
            +
                    (after - before).should > 5.0
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                context "finds 'upnp:rootdevice's" do
         | 
| 159 | 
            +
                  it "by using the spec's string 'upnp:rootdevice'" do
         | 
| 160 | 
            +
                    SSDP.search('upnp:rootdevice').should == [
         | 
| 161 | 
            +
                      {
         | 
| 162 | 
            +
                        :cache_control=>'max-age=1200',
         | 
| 163 | 
            +
                        :date=>'Mon, 26 Sep 2011 06:40:19 GMT',
         | 
| 164 | 
            +
                        :location=>'http://192.168.10.3:5001/description/fetch',
         | 
| 165 | 
            +
                        :server=>'Linux-i386-2.6.38-10-generic-pae, UPnP/1.0, PMS/1.25.1',
         | 
| 166 | 
            +
                        :st=>'upnp:rootdevice',
         | 
| 167 | 
            +
                        :ext=>'',
         | 
| 168 | 
            +
                        :usn=>'uuid:3c202906-992d-3f0f-b94c-90e1902a136d::upnp:rootdevice',
         | 
| 169 | 
            +
                        :content_length=>'0'
         | 
| 170 | 
            +
                      }
         | 
| 171 | 
            +
                    ]
         | 
| 172 | 
            +
                  end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                  it 'by using :root' do
         | 
| 175 | 
            +
                    pending
         | 
| 176 | 
            +
                  end
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                it 'can wait for user-defined seconds for responses' do
         | 
| 180 | 
            +
                  before = Time.now
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                  SSDP.search(:all, 1)
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                  after = Time.now
         | 
| 185 | 
            +
                  (after - before).should < 1.1
         | 
| 186 | 
            +
                  (after - before).should > 1.0
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                it 'finds a device by its URN' do
         | 
| 190 | 
            +
                  pending
         | 
| 191 | 
            +
                end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                it 'finds a device by its UUID' do
         | 
| 194 | 
            +
                  pending
         | 
| 195 | 
            +
                end
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                it 'finds a device by its UPnP device type' do
         | 
| 198 | 
            +
                  pending
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                it 'finds a device by its UPnP device type using a non-standard domain name' do
         | 
| 202 | 
            +
                  pending
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                it 'finds a service by its UPnP service type' do
         | 
| 206 | 
            +
                  pending
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                it 'find a service by its UPnP service type using a non-standard domain name' do
         | 
| 210 | 
            +
                  pending
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
            =end
         | 
| 213 | 
            +
            end
         | 
| 214 | 
            +
             | 
    
        data/tasks/search.thor
    ADDED
    
    | @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require 'pp'
         | 
| 2 | 
            +
            require File.expand_path(File.dirname(__FILE__)+ '/../lib/frisky/ssdp')
         | 
| 3 | 
            +
            require File.expand_path(File.dirname(__FILE__)+ '/../lib/frisky/logger')
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Frisky
         | 
| 6 | 
            +
              class Ssdp < Thor
         | 
| 7 | 
            +
                #---------------------------------------------------------------------------
         | 
| 8 | 
            +
                # search
         | 
| 9 | 
            +
                #---------------------------------------------------------------------------
         | 
| 10 | 
            +
                desc 'search TARGET', 'Searches for devices of type TARGET'
         | 
| 11 | 
            +
                method_option :response_wait_time, default: 5
         | 
| 12 | 
            +
                method_option :ttl, default: 4
         | 
| 13 | 
            +
                method_option :do_broadcast_search, type: :boolean
         | 
| 14 | 
            +
                method_option :log, type: :boolean
         | 
| 15 | 
            +
                def search(target='upnp:rootdevice')
         | 
| 16 | 
            +
                  ::Frisky.logging_enabled = options[:log]
         | 
| 17 | 
            +
                  time_before = Time.now
         | 
| 18 | 
            +
                  results     = ::Frisky::SSDP.search(target, options.dup)
         | 
| 19 | 
            +
                                .map { |r| r[:location] }
         | 
| 20 | 
            +
                                .sort
         | 
| 21 | 
            +
                  unique      = results.uniq
         | 
| 22 | 
            +
                  time_after  = Time.now
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  puts <<-RESULTS
         | 
| 25 | 
            +
            size: #{results.size}
         | 
| 26 | 
            +
            locations: #{results.join("\n           ")}
         | 
| 27 | 
            +
            unique size: #{unique.size}
         | 
| 28 | 
            +
            unique locations: #{unique.join("\n                  ")}
         | 
| 29 | 
            +
            search duration: #{time_after - time_before}
         | 
| 30 | 
            +
                  RESULTS
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  results
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,181 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: frisky
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Jon Frisby
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2015-09-13 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: eventmachine
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: 1.0.0
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: 1.0.0
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: em-http-request
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - ">="
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: 1.0.2
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - ">="
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: 1.0.2
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: em-synchrony
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: nori
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: 2.0.2
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: 2.0.2
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: log_switch
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - "~>"
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: 1.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: 1.0.0
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: savon
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - "~>"
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '2.0'
         | 
| 90 | 
            +
              type: :runtime
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - "~>"
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '2.0'
         | 
| 97 | 
            +
            description: |-
         | 
| 98 | 
            +
              frisky provides the tools you need to build an app that runs
         | 
| 99 | 
            +
              in a UPnP environment.
         | 
| 100 | 
            +
            email: jfrisby@mrjoy.com
         | 
| 101 | 
            +
            executables: []
         | 
| 102 | 
            +
            extensions: []
         | 
| 103 | 
            +
            extra_rdoc_files:
         | 
| 104 | 
            +
            - History.md
         | 
| 105 | 
            +
            - README.md
         | 
| 106 | 
            +
            - LICENSE.md
         | 
| 107 | 
            +
            files:
         | 
| 108 | 
            +
            - ".gemtest"
         | 
| 109 | 
            +
            - ".gitignore"
         | 
| 110 | 
            +
            - ".rspec"
         | 
| 111 | 
            +
            - ".travis.yml"
         | 
| 112 | 
            +
            - Gemfile
         | 
| 113 | 
            +
            - History.md
         | 
| 114 | 
            +
            - LICENSE.md
         | 
| 115 | 
            +
            - README.md
         | 
| 116 | 
            +
            - Rakefile
         | 
| 117 | 
            +
            - features/device_discovery.feature
         | 
| 118 | 
            +
            - features/step_definitions/.gitkeep
         | 
| 119 | 
            +
            - features/support/env.rb
         | 
| 120 | 
            +
            - features/support/world_extensions.rb
         | 
| 121 | 
            +
            - frisky.gemspec
         | 
| 122 | 
            +
            - lib/core_ext/hash_patch.rb
         | 
| 123 | 
            +
            - lib/core_ext/socket_patch.rb
         | 
| 124 | 
            +
            - lib/core_ext/to_upnp_s.rb
         | 
| 125 | 
            +
            - lib/frisky.rb
         | 
| 126 | 
            +
            - lib/frisky/logger.rb
         | 
| 127 | 
            +
            - lib/frisky/ssdp.rb
         | 
| 128 | 
            +
            - lib/frisky/ssdp/broadcast_searcher.rb
         | 
| 129 | 
            +
            - lib/frisky/ssdp/error.rb
         | 
| 130 | 
            +
            - lib/frisky/ssdp/listener.rb
         | 
| 131 | 
            +
            - lib/frisky/ssdp/multicast_connection.rb
         | 
| 132 | 
            +
            - lib/frisky/ssdp/network_constants.rb
         | 
| 133 | 
            +
            - lib/frisky/ssdp/notifier.rb
         | 
| 134 | 
            +
            - lib/frisky/ssdp/searcher.rb
         | 
| 135 | 
            +
            - lib/frisky/version.rb
         | 
| 136 | 
            +
            - spec/spec_helper.rb
         | 
| 137 | 
            +
            - spec/support/search_responses.rb
         | 
| 138 | 
            +
            - spec/unit/core_ext/to_upnp_s_spec.rb
         | 
| 139 | 
            +
            - spec/unit/frisky/ssdp/listener_spec.rb
         | 
| 140 | 
            +
            - spec/unit/frisky/ssdp/multicast_connection_spec.rb
         | 
| 141 | 
            +
            - spec/unit/frisky/ssdp/notifier_spec.rb
         | 
| 142 | 
            +
            - spec/unit/frisky/ssdp/searcher_spec.rb
         | 
| 143 | 
            +
            - spec/unit/frisky/ssdp_spec.rb
         | 
| 144 | 
            +
            - tasks/search.thor
         | 
| 145 | 
            +
            homepage: http://github.com/MrJoy/frisky
         | 
| 146 | 
            +
            licenses: []
         | 
| 147 | 
            +
            metadata: {}
         | 
| 148 | 
            +
            post_install_message: 
         | 
| 149 | 
            +
            rdoc_options: []
         | 
| 150 | 
            +
            require_paths:
         | 
| 151 | 
            +
            - lib
         | 
| 152 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 153 | 
            +
              requirements:
         | 
| 154 | 
            +
              - - ">="
         | 
| 155 | 
            +
                - !ruby/object:Gem::Version
         | 
| 156 | 
            +
                  version: 1.9.1
         | 
| 157 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 158 | 
            +
              requirements:
         | 
| 159 | 
            +
              - - ">="
         | 
| 160 | 
            +
                - !ruby/object:Gem::Version
         | 
| 161 | 
            +
                  version: '0'
         | 
| 162 | 
            +
            requirements: []
         | 
| 163 | 
            +
            rubyforge_project: 
         | 
| 164 | 
            +
            rubygems_version: 2.4.5.1
         | 
| 165 | 
            +
            signing_key: 
         | 
| 166 | 
            +
            specification_version: 4
         | 
| 167 | 
            +
            summary: Use me to build a UPnP app!
         | 
| 168 | 
            +
            test_files:
         | 
| 169 | 
            +
            - features/device_discovery.feature
         | 
| 170 | 
            +
            - features/step_definitions/.gitkeep
         | 
| 171 | 
            +
            - features/support/env.rb
         | 
| 172 | 
            +
            - features/support/world_extensions.rb
         | 
| 173 | 
            +
            - spec/spec_helper.rb
         | 
| 174 | 
            +
            - spec/support/search_responses.rb
         | 
| 175 | 
            +
            - spec/unit/core_ext/to_upnp_s_spec.rb
         | 
| 176 | 
            +
            - spec/unit/frisky/ssdp/listener_spec.rb
         | 
| 177 | 
            +
            - spec/unit/frisky/ssdp/multicast_connection_spec.rb
         | 
| 178 | 
            +
            - spec/unit/frisky/ssdp/notifier_spec.rb
         | 
| 179 | 
            +
            - spec/unit/frisky/ssdp/searcher_spec.rb
         | 
| 180 | 
            +
            - spec/unit/frisky/ssdp_spec.rb
         | 
| 181 | 
            +
            has_rdoc: 
         |