turboladen / playful

A Ruby implementation of UPnP that works with Ruby >= 1.9.x
MIT License
127 stars 18 forks source link

Resisting non fully UPNP compliant devices on the network + workaround #17

Open fondemen opened 8 years ago

fondemen commented 8 years ago

Hi there.

And thanks for this library.

I'm living on a network full of weird devices. When using this lib, while trying to discover devices, i end up with some exception such as

undefined method `[]' for nil:NilClass
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point/service.rb:147:in `block in fetch'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/deferrable.rb:151:in `set_deferred_status'
/Users/fondemen/RubymineProjects/favsync/app/cli/interpreter.rb:48:in `set_deferred_status'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point/base.rb:43:in `block in get_description'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/deferrable.rb:151:in `set_deferred_status'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/deferrable.rb:191:in `succeed'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/client.rb:113:in `unbind'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/client.rb:71:in `on_request_complete'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/http_connection.rb:137:in `block in post_init'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/http_connection.rb:152:in `<<'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/http_connection.rb:152:in `receive_data'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/http_connection.rb:23:in `receive_data'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:194:in `run_machine'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:194:in `run'

or

Hostname not supplied: '10.56.100.3'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/addressable-2.4.0/lib/addressable/uri.rb:2366:in `validate'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/addressable-2.4.0/lib/addressable/uri.rb:1348:in `port='
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/http_connection_options.rb:22:in `initialize'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/request.rb:7:in `new'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/em-http-request-1.1.5/lib/em-http/request.rb:7:in `new'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point/base.rb:17:in `get_description'
/Users/fondemen/RubymineProjects/favsync/app/cli/interpreter.rb:56:in `get_description'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point/device.rb:197:in `extract_from_ssdp_notification'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point/device.rb:135:in `fetch'
/Users/fondemen/RubymineProjects/favsync/app/cli/interpreter.rb:65:in `fetch'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point.rb:142:in `create_device'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/control_point.rb:105:in `block in ssdp_search_and_listen'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/channel.rb:48:in `block (3 levels) in push'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/channel.rb:48:in `each'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/channel.rb:48:in `block (2 levels) in push'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/channel.rb:48:in `each'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/channel.rb:48:in `block in push'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:235:in `schedule'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/em/channel.rb:48:in `push'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/playful-0.1.0.alpha.1/lib/playful/ssdp/searcher.rb:59:in `receive_data'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:194:in `run_machine'
/opt/local/lib/ruby2.3/gems/2.3.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:194:in `run'

As Playful uses EventMachine, such exception stops the machine, also for co-located programs...

I finally ended up living with this thanks to the following snippet:

module Playful
  class ControlPoint

    # Handling ill-formed descriptions
    class Base

      alias_method :org_get_description, :get_description

      def get_description(location, description_getter)
        class << description_getter

          alias_method :org_set_deferred_status, :set_deferred_status
          def set_deferred_status status, *args
            if :succeeded == status and not args.empty? and args[0].empty?
              #puts "BUG => Playfull tried to examine an empty response"
              org_set_deferred_status :failed
            else
              begin
                org_set_deferred_status status, *args
              rescue => e
                puts "Error while discovering device #{e.message}"
                puts e.backtrace
              end
            end
          end
        end
        org_get_description location, description_getter
      end
    end

    class Device
      alias_method :org_fetch, :fetch

      def fetch
        begin
          org_fetch
        rescue => e
          puts "Error while discovering device #{e.message}"
          puts e.backtrace
        end
      end
    end

    # Ignoring puts messages (sent each time network is controlled)
    def puts msg
    end
  end
end

Might be great if it could be integrated in the lib...

And again, great thanks to Ruby that makes it possible to remote-patch external libraries !

Regards.

Frédéric