druzy-upnp 1.0.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05af46c9b98de0c1073ad74433e387c9616252f0
4
- data.tar.gz: 2b98f3eefbe44f41b9e158bf82d21f2de30e5f9b
3
+ metadata.gz: ef31e12c2747c77a8519f682a898a87e9e6939c7
4
+ data.tar.gz: 63cb56202abc50e9d400c5d1089301ce0544a9dc
5
5
  SHA512:
6
- metadata.gz: 0c6f0f5a91514c5199a1927fb19e79da36ecc887ace1e340a4e276e8ecea1d862d95049b25cc0621c31cb613ca31cdac675907d2f19019145c03d22632cd7bb4
7
- data.tar.gz: 1694f9edf91260a4d5e145ed1a392560015f02a8949468cae629f66d770af45af600e4d0ae320f3ed4b596ddb16315765d33670b39d589f344af115edacd97e0
6
+ metadata.gz: 6f6592b21116bb309bfc171de869568f5f2dee96a9a6e674ca6c861ab3e9aa0899c5945f748680000ed81eb42dd6292b52e790364be6e6aa5bdcd1a54478bf99
7
+ data.tar.gz: 9edf72a244a19276b51cdbd00a0fb7e6e4ca3c1f0903e98d42c48bc9208645302a786ae41c87ce0589004df73e778ad020d5e1fae2f4bd3cd8ee43cd9244a473
@@ -1,195 +1,65 @@
1
- require 'core_ext/socket_patch'
2
- require 'eventmachine'
3
- require 'em-synchrony'
4
- require 'core_ext/to_upnp_s'
5
- require_relative 'ssdp/error'
6
- require_relative 'ssdp/network_constants'
7
- require_relative 'ssdp/listener'
8
- require_relative 'ssdp/searcher'
9
- require_relative 'ssdp/notifier'
1
+ require_relative 'upnp_device'
2
+ require_relative 'version'
10
3
 
11
- require_relative 'ssdp/broadcast_searcher'
4
+ require 'socket'
5
+ require 'timeout'
12
6
 
13
7
  module Druzy
14
8
  module Upnp
15
-
16
- # This is the main class for doing SSDP stuff. You can have a look at child
17
- # classes, but you'll probably want to just use these methods here.
18
- #
19
- # SSDP is "Simple Service Discovery Protocol", which lets you find and learn
20
- # about UPnP devices on your network. Of the six "steps" of UPnP (given in
21
- # the UPnP spec--that's counting step 0), SSDP is what provides step 1, or the
22
- # "discovery" step.
23
- #
24
- # Before you can do anything with any of the UPnP devices on your network, you
25
- # need to +search+ your network to see what devices are available. Once you've
26
- # found what's available, you can then decide device(s) you'd like to control
27
- # (that's where Control Points come in; take a look at Playful::ControlPoint).
28
- # After searching, you should then +listen+ to the activity on your network.
29
- # New devices on your network may come online (via +ssdp:alive+) and devices
30
- # that you care about may go offline (via +ssdp:byebye+), in which case you
31
- # probably shouldn't try to talk to them anymore.
32
- #
33
- # @todo Add docs for Playful::Device perspective.
34
- class SSDP
35
- include NetworkConstants
36
-
37
- # Opens a multicast UDP socket on 239.255.255.250:1900 and listens for
38
- # alive and byebye notifications from devices.
39
- #
40
- # @param [Fixnum] ttl The TTL to use on the UDP socket.
41
- #
42
- # @return [Hash<Array>,Playful::SSDP::Listener] If the EventMachine reactor is
43
- # _not_ running, it returns two key/value pairs--one for
44
- # alive_notifications, one for byebye_notifications. If the reactor _is_
45
- # running, it returns a Playful::SSDP::Listener so that that object can be
46
- # used however desired. The latter method is used in Playful::ControlPoints
47
- # so that an object of that type can keep track of devices it cares about.
48
- def self.listen(ttl=TTL)
49
- alive_notifications = Set.new
50
- byebye_notifications = Set.new
51
-
52
- listener = proc do
53
- l = EM.open_datagram_socket(MULTICAST_IP, MULTICAST_PORT,
54
- Playful::SSDP::Listener, ttl)
55
- i = 0
56
- EM.add_periodic_timer(5) { i += 5; Playful.log "Listening for #{i}\n" }
57
- l
58
- end
59
-
60
- if EM.reactor_running?
61
- return listener.call
62
- else
63
- EM.synchrony do
64
- l = listener.call
65
-
66
- alive_getter = Proc.new do |notification|
67
- alive_notifications << notification
68
- EM.next_tick { l.alive_notifications.pop(&live_getter) }
69
- end
70
- l.alive_notifications.pop(&alive_getter)
71
-
72
- byebye_getter = Proc.new do |notification|
73
- byebye_notifications << notification
74
- EM.next_tick { l.byebye_notifications.pop(&byebye_getter) }
75
- end
76
- l.byebye_notifications.pop(&byebye_getter)
77
-
78
- trap_signals
79
- end
80
- end
81
-
82
- {
83
- alive_notifications: alive_notifications.to_a.flatten,
84
- byebye_notifications: byebye_notifications.to_a.flatten
85
- }
9
+
10
+ class Ssdp
11
+ @@port = 1900
12
+ @@host = "239.255.255.250"
13
+
14
+ def initialize
15
+
86
16
  end
87
-
88
- # Opens a UDP socket on 0.0.0.0, on an ephemeral port, has Druzy::Upnp::SSDP::Searcher
89
- # build and send the search request, then receives the responses. The search
90
- # will stop after +response_wait_time+.
91
- #
92
- # @param [String] search_target
93
- #
94
- # @param [Hash] options
95
- #
96
- # @option options [Fixnum] response_wait_time
97
- # @option options [Fixnum] ttl
98
- # @option options [Fixnum] m_search_count
99
- # @option options [Boolean] do_broadcast_search Tells the search call to also send
100
- # a M-SEARCH over 255.255.255.255. This is *NOT* part of the UPnP spec;
101
- # it's merely a hack for working with some types of devices that don't
102
- # properly implement the UPnP spec.
103
- #
104
- # @return [Array<Hash>,Playful::SSDP::Searcher] Returns a Hash that represents
105
- # the headers from the M-SEARCH response. Each one of these can be passed
106
- # in to Playful::ControlPoint::Device.new to download the device's
107
- # description file, parse it, and interact with the device's devices
108
- # and/or services. If the reactor is already running this will return a
109
- # a Playful::SSDP::Searcher which will make its accessors available so you
110
- # can get responses in real time.
111
- def self.search(search_target=:all, options = {})
112
- response_wait_time = options[:response_wait_time] || 5
113
- ttl = options[:ttl] || TTL
114
- do_broadcast_search = options[:do_broadcast_search]
115
-
116
- searcher_options = options
117
- searcher_options.delete :do_broadcast_search
118
-
119
- responses = []
120
- search_target = search_target.to_upnp_s
121
-
122
- multicast_searcher = proc do
123
- EM.open_datagram_socket('0.0.0.0', 0, Druzy::Upnp::SSDP::Searcher,
124
- search_target, searcher_options)
125
- end
126
-
127
- broadcast_searcher = proc do
128
- EM.open_datagram_socket('0.0.0.0', 0, Druzy::Upnp::SSDP::BroadcastSearcher,
129
- search_target, response_wait_time, ttl)
130
- end
131
-
132
- if EM.reactor_running?
133
- return multicast_searcher.call
134
- else
135
- EM.synchrony do
136
- ms = multicast_searcher.call
137
-
138
- ms.discovery_responses.subscribe do |notification|
139
- responses << notification
140
- end
141
-
142
- if do_broadcast_search
143
- bs = broadcast_searcher.call
144
-
145
- bs.discovery_responses.subscribe do |notification|
146
- responses << notification
17
+
18
+ #search only device (not service)
19
+ def search(st = "ssdp:all", delay = 10)
20
+ message = <<-MESSAGE
21
+ M-SEARCH * HTTP/1.1\r
22
+ HOST: #{@@host}:#{@@port}\r
23
+ MAN: "ssdp:discover"\r
24
+ MX: #{delay}\r
25
+ ST: #{st}\r
26
+ USER-AGENT: #{RbConfig::CONFIG["host_os"]}/ UPnP/1.1 ruby-druzy-upnp/#{Druzy::Upnp::VERSION}\r
27
+ MESSAGE
28
+
29
+ s = UDPSocket.new
30
+ s.send(message,0,@@host,@@port)
31
+ devices = []
32
+ begin
33
+ Timeout::timeout(delay) do
34
+ loop do
35
+ message = s.recv(4196)
36
+ location = message.split("\n").reject{|line| line==nil || line["LOCATION"]==nil}.first
37
+ location = location[location.index(" ")+1..location.size-2]
38
+ if !devices.include?(location)
39
+ devices << location
40
+ if block_given?
41
+ yield UpnpDevice.new(:location => location)
42
+ end
147
43
  end
148
44
  end
149
-
150
- EM.add_timer(response_wait_time) { EM.stop }
151
- trap_signals
152
45
  end
46
+ rescue
47
+
48
+ ensure
49
+ s.close
153
50
  end
154
-
155
- responses.flatten
156
- end
157
-
158
- # @todo This is for Playful::Devices, which aren't implemented yet, and thus
159
- # this may not be working.
160
- def self.notify(notification_type, usn, ddf_url, valid_for_duration=1800)
161
- responses = []
162
- notification_type = notification_type.to_upnp_s
163
-
164
- EM.synchrony do
165
- s = send_notification(notification_type, usn, ddf_url, valid_for_duration)
166
- EM.add_shutdown_hook { responses = s.discovery_responses }
167
-
168
- EM.add_periodic_timer(valid_for_duration) do
169
- s = send_notification(notification_type, usn, ddf_url, valid_for_duration)
170
- end
171
-
172
- trap_signals
173
- end
174
-
175
- responses
176
- end
177
-
178
- # @todo This is for Playful::Devices, which aren't implemented yet, and thus
179
- # this may not be working.
180
- def self.send_notification(notification_type, usn, ddf_url, valid_for_duration)
181
- EM.open_datagram_socket('0.0.0.0', 0, Druzy::Upnp::SSDP::Notifier, notification_type,
182
- usn, ddf_url, valid_for_duration)
183
- end
184
-
185
- private
186
-
187
- # Traps INT, TERM, and HUP signals and stops the reactor.
188
- def self.trap_signals
189
- trap('INT') { EM.stop }
190
- trap('TERM') { EM.stop }
191
- trap('HUP') { EM.stop } if RUBY_PLATFORM !~ /mswin|mingw/
51
+
192
52
  end
53
+
193
54
  end
55
+
56
+ end
57
+ end
58
+
59
+ if $0 == __FILE__
60
+ Druzy::Upnp::Ssdp.new.search("urn:schemas-upnp-org:device:MediaRenderer:1") do |device|
61
+ puts device.device_type
62
+ connection_id, av_transport_id, rcs_id = device.ConnectionManager.PrepareForConnection("RemoteProtocolInfo" => "http-get:*:video/mp4:*", "PeerConnectionManager" => "/", "PeerConnectionID" => -1, "Direction" => "Output").values
63
+ puts av_transport_id.to_s
194
64
  end
195
65
  end
@@ -0,0 +1,73 @@
1
+ require_relative 'upnp_service'
2
+
3
+ require 'net/http'
4
+ require 'nokogiri'
5
+
6
+ module Druzy
7
+ module Upnp
8
+
9
+ class UpnpDevice
10
+
11
+ attr_reader :url_base, :device_type, :friendly_name, :manufacturer, :manufacturer_url, :model_description
12
+ attr_reader :model_name, :model_number, :model_url, :serial_number, :udn, :upc, :icon_list, :service_list
13
+ attr_reader :device_list
14
+
15
+ def initialize(args)
16
+
17
+ if args[:ssdp_message] != nil
18
+
19
+ mess = args[:ssdp_message]
20
+ location=mess.split("\n").reject{|line| line==nil || line["LOCATION"]==nil}.first
21
+ initialize(:location => location[location.index(" ")+1..location.size-2])
22
+
23
+ elsif args[:location] != nil
24
+
25
+ uri = URI(args[:location])
26
+ xml=Net::HTTP.get(uri)
27
+ xml_nok = Nokogiri::XML(xml)
28
+ xml_nok.remove_namespaces!
29
+ initialize(:uri => uri, :xml => Nokogiri::XML(xml_nok.xpath('root/device').to_s))
30
+
31
+ else
32
+
33
+ uri = args[:uri]
34
+ xml_nok = args[:xml]
35
+ #puts xml_nok
36
+ @url_base = uri.scheme+'://'+uri.host+":"+uri.port.to_s
37
+ @device_type = xml_nok.xpath('device/deviceType').text
38
+ @friendly_name = xml_nok.xpath('device/friendlyName').text
39
+ @manufacturer = xml_nok.xpath('device/manufacturer').text
40
+ @manufacturer_url = xml_nok.xpath('device/manufacturerURL').text
41
+ @model_description = xml_nok.xpath('device/modelDescription').text
42
+ @model_name = xml_nok.xpath('device/modelName').text
43
+ @model_number = xml_nok.xpath('device/modelNumber').text
44
+ @model_url = xml_nok.xpath('device/modelURL').text
45
+ @serial_number = xml_nok.xpath('device/serialNumber').text
46
+ @udn = xml_nok.xpath('device/UDN').text
47
+ @upc = xml_nok.xpath('device/UPC').text
48
+ @icon_list = xml_nok.xpath('device/iconList/icon/url').to_a.collect{|el| @url_base+el.text}
49
+ @service_list = xml_nok.xpath('device/serviceList/service').to_a.collect{|el| UpnpService.new(
50
+ :service_type => el.xpath("serviceType").text,
51
+ :service_id => el.xpath("serviceId").text,
52
+ :location => @url_base+el.xpath("SCPDURL").text,
53
+ :control_url => @url_base+el.xpath("controlURL").text,
54
+ :event_sub_url => @url_base+el.xpath("eventSubURL").text
55
+ )}
56
+ @service_list.each do |service|
57
+ method_name = service.service_id[service.service_id.rindex(':')+1..-1]
58
+ define_singleton_method(method_name.to_sym) do
59
+ return service
60
+ end
61
+ end
62
+
63
+ @device_list = xml_nok.xpath('device/deviceList/device').to_a.collect{|el|
64
+ UpnpDevice.new(
65
+ :uri => uri,
66
+ :xml => Nokogiri::XML(el.to_s)
67
+ )}
68
+
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,74 @@
1
+ require 'net/http'
2
+ require 'nokogiri'
3
+ require 'uri'
4
+
5
+ module Druzy
6
+ module Upnp
7
+ class UpnpService
8
+
9
+ attr_reader :service_type, :service_id, :location, :control_url, :event_sub_url
10
+
11
+ def initialize(args)
12
+
13
+ @service_type = args[:service_type]
14
+ @service_id = args[:service_id]
15
+ @location = args[:location]
16
+ @control_url = args[:control_url]
17
+ @event_sub_url = args[:event_sub_url]
18
+
19
+ uri = URI(@location)
20
+ xml=Net::HTTP.get(uri)
21
+ xml_nok = Nokogiri::XML(xml)
22
+ xml_nok.remove_namespaces!
23
+ xml_nok.xpath('scpd/actionList/action').to_a.each do |el|
24
+
25
+ action_name = el.xpath('name').text
26
+ define_singleton_method(action_name.to_sym) do |arguments={}|
27
+ message = <<-MESSAGE
28
+ <?xml version="1.0"?>
29
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
30
+ <s:Body>
31
+ <u:#{action_name} xmlns:u="#{@service_type}">
32
+ MESSAGE
33
+
34
+ arguments.each do |cle, valeur|
35
+ message.concat <<-MESSAGE
36
+ <#{cle.to_s}>#{valeur.to_s}</#{cle.to_s}>
37
+ MESSAGE
38
+ end
39
+
40
+ message.concat <<-MESSAGE
41
+ </u:#{action_name}>
42
+ </s:Body>
43
+ </s:Envelope>
44
+ MESSAGE
45
+
46
+ header = {
47
+ "HOST" => uri.host.to_s+':'+uri.port.to_s,
48
+ "CONTENT-LENGTH" => message.size.to_s,
49
+ "CONTENT-TYPE" => 'text/xml; charset="utf-8"',
50
+ "SOAPACTION" => @service_type.to_s+"#"+action_name.to_s
51
+ }
52
+
53
+ http = Net::HTTP.new(uri.host,uri.port)
54
+ request = Net::HTTP::Post.new(uri.request_uri,header)
55
+ request.body = message
56
+ response = http.request(request)
57
+ xml = Nokogiri.XML(response.body)
58
+ xml.remove_namespaces!
59
+
60
+ result = {}
61
+ puts "avant hash"
62
+ xml.xpath("Envelope/Body/"+action_name.to_s+"Response").children.each do |child|
63
+ result[child.name.to_s] = child.text
64
+ end
65
+
66
+ return result
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,5 +1,5 @@
1
1
  module Druzy
2
2
  module Upnp
3
- VERSION = '1.0.0'
3
+ VERSION = "2.0.0"
4
4
  end
5
- end
5
+ end
metadata CHANGED
@@ -1,239 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: druzy-upnp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Le Greneur
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-22 00:00:00.000000000 Z
11
+ date: 2016-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: eventmachine
14
+ name: nokogiri
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.0.0
19
+ version: 1.6.7.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
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: savon
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.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'
26
+ version: 1.6.7.2
83
27
  - !ruby/object:Gem::Dependency
84
28
  name: bundler
85
29
  requirement: !ruby/object:Gem::Requirement
86
30
  requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
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: cucumber
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 1.0.0
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.0
111
- - !ruby/object:Gem::Dependency
112
- name: em-websocket
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
31
+ - - "~>"
116
32
  - !ruby/object:Gem::Version
117
- version: 0.3.6
33
+ version: '1.11'
118
34
  type: :development
119
35
  prerelease: false
120
36
  version_requirements: !ruby/object:Gem::Requirement
121
37
  requirements:
122
- - - ">="
38
+ - - "~>"
123
39
  - !ruby/object:Gem::Version
124
- version: 0.3.6
40
+ version: '1.11'
125
41
  - !ruby/object:Gem::Dependency
126
42
  name: rake
127
43
  requirement: !ruby/object:Gem::Requirement
128
44
  requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: rspec
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: 3.0.0.beta
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: 3.0.0.beta
153
- - !ruby/object:Gem::Dependency
154
- name: simplecov
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: 0.4.2
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: 0.4.2
167
- - !ruby/object:Gem::Dependency
168
- name: thin
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
- - !ruby/object:Gem::Dependency
182
- name: thor
183
- requirement: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - ">="
186
- - !ruby/object:Gem::Version
187
- version: 0.1.6
188
- type: :development
189
- prerelease: false
190
- version_requirements: !ruby/object:Gem::Requirement
191
- requirements:
192
- - - ">="
193
- - !ruby/object:Gem::Version
194
- version: 0.1.6
195
- - !ruby/object:Gem::Dependency
196
- name: yard
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - ">="
45
+ - - "~>"
200
46
  - !ruby/object:Gem::Version
201
- version: 0.7.0
47
+ version: '10.0'
202
48
  type: :development
203
49
  prerelease: false
204
50
  version_requirements: !ruby/object:Gem::Requirement
205
51
  requirements:
206
- - - ">="
52
+ - - "~>"
207
53
  - !ruby/object:Gem::Version
208
- version: 0.7.0
209
- description: Fork of Playful. druzy-upnp provides the tools you need to build an app
210
- that runs in a UPnP environment.
54
+ version: '10.0'
55
+ description: Discover and interact with upnp device
211
56
  email:
212
57
  - jonathan.legreneur@free.fr
213
58
  executables: []
214
59
  extensions: []
215
60
  extra_rdoc_files: []
216
61
  files:
217
- - lib/core_ext/hash_patch.rb
218
- - lib/core_ext/socket_patch.rb
219
- - lib/core_ext/to_upnp_s.rb
220
62
  - lib/druzy/upnp.rb
221
- - lib/druzy/upnp/control_point.rb
222
- - lib/druzy/upnp/control_point/base.rb
223
- - lib/druzy/upnp/control_point/device.rb
224
- - lib/druzy/upnp/control_point/error.rb
225
- - lib/druzy/upnp/control_point/service.rb
226
- - lib/druzy/upnp/device.rb
227
63
  - lib/druzy/upnp/ssdp.rb
228
- - lib/druzy/upnp/ssdp/broadcast_searcher.rb
229
- - lib/druzy/upnp/ssdp/error.rb
230
- - lib/druzy/upnp/ssdp/listener.rb
231
- - lib/druzy/upnp/ssdp/multicast_connection.rb
232
- - lib/druzy/upnp/ssdp/network_constants.rb
233
- - lib/druzy/upnp/ssdp/notifier.rb
234
- - lib/druzy/upnp/ssdp/searcher.rb
64
+ - lib/druzy/upnp/upnp_device.rb
65
+ - lib/druzy/upnp/upnp_service.rb
235
66
  - lib/druzy/upnp/version.rb
236
- - lib/rack/upnp_control_point.rb
237
67
  homepage: https://github.com/druzy/ruby-druzy-upnp
238
68
  licenses:
239
69
  - MIT
@@ -257,5 +87,5 @@ rubyforge_project:
257
87
  rubygems_version: 2.5.1
258
88
  signing_key:
259
89
  specification_version: 4
260
- summary: Use me to build a UPnP app!
90
+ summary: A control point UPNP
261
91
  test_files: []
@@ -1,5 +0,0 @@
1
- class Hash
2
- def symbolize_keys!
3
- self.inject({}) { |result, (k, v)| result[k.to_sym] = v; result }
4
- end
5
- end