druzy-upnp 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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