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 +4 -4
- data/lib/druzy/upnp/ssdp.rb +52 -182
- data/lib/druzy/upnp/upnp_device.rb +73 -0
- data/lib/druzy/upnp/upnp_service.rb +74 -0
- data/lib/druzy/upnp/version.rb +2 -2
- metadata +17 -187
- data/lib/core_ext/hash_patch.rb +0 -5
- data/lib/core_ext/socket_patch.rb +0 -16
- data/lib/core_ext/to_upnp_s.rb +0 -65
- data/lib/druzy/upnp/control_point/base.rb +0 -70
- data/lib/druzy/upnp/control_point/device.rb +0 -465
- data/lib/druzy/upnp/control_point/error.rb +0 -15
- data/lib/druzy/upnp/control_point/service.rb +0 -387
- data/lib/druzy/upnp/control_point.rb +0 -161
- data/lib/druzy/upnp/device.rb +0 -31
- data/lib/druzy/upnp/ssdp/broadcast_searcher.rb +0 -110
- data/lib/druzy/upnp/ssdp/error.rb +0 -8
- data/lib/druzy/upnp/ssdp/listener.rb +0 -36
- data/lib/druzy/upnp/ssdp/multicast_connection.rb +0 -109
- data/lib/druzy/upnp/ssdp/network_constants.rb +0 -19
- data/lib/druzy/upnp/ssdp/notifier.rb +0 -39
- data/lib/druzy/upnp/ssdp/searcher.rb +0 -85
- data/lib/rack/upnp_control_point.rb +0 -70
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
# Workaround for missing constants on Windows
|
4
|
-
module Socket::Constants
|
5
|
-
IP_ADD_MEMBERSHIP = 12 unless defined? IP_ADD_MEMBERSHIP
|
6
|
-
IP_MULTICAST_LOOP = 11 unless defined? IP_MULTICAST_LOOP
|
7
|
-
IP_MULTICAST_TTL = 10 unless defined? IP_MULTICAST_TTL
|
8
|
-
IP_TTL = 4 unless defined? IP_TTL
|
9
|
-
end
|
10
|
-
|
11
|
-
class Socket
|
12
|
-
IP_ADD_MEMBERSHIP = 12 unless defined? IP_ADD_MEMBERSHIP
|
13
|
-
IP_MULTICAST_LOOP = 11 unless defined? IP_MULTICAST_LOOP
|
14
|
-
IP_MULTICAST_TTL = 10 unless defined? IP_MULTICAST_TTL
|
15
|
-
IP_TTL = 4 unless defined? IP_TTL
|
16
|
-
end
|
data/lib/core_ext/to_upnp_s.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
|
3
|
-
# Converts Hash search targets to SSDP search target String. Conversions are
|
4
|
-
# as follows:
|
5
|
-
# uuid: "someUUID" # => "uuid:someUUID"
|
6
|
-
# device_type: "someDeviceType:1" # => "urn:schemas-upnp-org:device:someDeviceType:1"
|
7
|
-
# service_type: "someServiceType:2" # => "urn:schemas-upnp-org:service:someServiceType:2"
|
8
|
-
#
|
9
|
-
# You can use custom UPnP domain names too:
|
10
|
-
# { device_type: "someDeviceType:3",
|
11
|
-
# domain_name: "mydomain-com" } # => "urn:my-domain:device:someDeviceType:3"
|
12
|
-
# { service_type: "someServiceType:4",
|
13
|
-
# domain_name: "mydomain-com" } # => "urn:my-domain:service:someDeviceType:4"
|
14
|
-
#
|
15
|
-
# @return [String] The converted String, according to the UPnP spec.
|
16
|
-
def to_upnp_s
|
17
|
-
if self.has_key? :uuid
|
18
|
-
return "uuid:#{self[:uuid]}"
|
19
|
-
elsif self.has_key? :device_type
|
20
|
-
if self.has_key? :domain_name
|
21
|
-
return "urn:#{self[:domain_name]}:device:#{self[:device_type]}"
|
22
|
-
else
|
23
|
-
return "urn:schemas-upnp-org:device:#{self[:device_type]}"
|
24
|
-
end
|
25
|
-
elsif self.has_key? :service_type
|
26
|
-
if self.has_key? :domain_name
|
27
|
-
return "urn:#{self[:domain_name]}:service:#{self[:service_type]}"
|
28
|
-
else
|
29
|
-
return "urn:schemas-upnp-org:service:#{self[:service_type]}"
|
30
|
-
end
|
31
|
-
else
|
32
|
-
self.to_s
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
class Symbol
|
39
|
-
|
40
|
-
# Converts Symbol search targets to SSDP search target String. Conversions are
|
41
|
-
# as follows:
|
42
|
-
# :all # => "ssdp:all"
|
43
|
-
# :root # => "upnp:rootdevice"
|
44
|
-
# "root" # => "upnp:rootdevice"
|
45
|
-
#
|
46
|
-
# @return [String] The converted String, according to the UPnP spec.
|
47
|
-
def to_upnp_s
|
48
|
-
if self == :all
|
49
|
-
'ssdp:all'
|
50
|
-
elsif self == :root
|
51
|
-
'upnp:rootdevice'
|
52
|
-
else
|
53
|
-
self
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
class String
|
60
|
-
# This doesn't do anything to the string; just allows users to call the
|
61
|
-
# method without having to check type first.
|
62
|
-
def to_upnp_s
|
63
|
-
self
|
64
|
-
end
|
65
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'nori'
|
2
|
-
require 'em-http-request'
|
3
|
-
require_relative 'error'
|
4
|
-
require_relative '../../upnp'
|
5
|
-
|
6
|
-
module Druzy
|
7
|
-
module Upnp
|
8
|
-
class ControlPoint
|
9
|
-
class Base
|
10
|
-
|
11
|
-
protected
|
12
|
-
|
13
|
-
def get_description(location, description_getter)
|
14
|
-
http = EM::HttpRequest.new(location).aget
|
15
|
-
|
16
|
-
t = EM::Timer.new(30) do
|
17
|
-
http.fail(:timeout)
|
18
|
-
end
|
19
|
-
|
20
|
-
http.errback do |error|
|
21
|
-
if error == :timeout
|
22
|
-
http = EM::HttpRequest.new(location).get
|
23
|
-
else
|
24
|
-
description_getter.set_deferred_status(:failed)
|
25
|
-
|
26
|
-
if ControlPoint.raise_on_remote_error
|
27
|
-
raise ControlPoint::Error, "Unable to retrieve DDF from #{location}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
http.callback {
|
33
|
-
if http.response_header.status != 200
|
34
|
-
description_getter.set_deferred_status(:failed)
|
35
|
-
else
|
36
|
-
response = xml_parser.parse(http.response)
|
37
|
-
description_getter.set_deferred_status(:succeeded, response)
|
38
|
-
end
|
39
|
-
}
|
40
|
-
end
|
41
|
-
|
42
|
-
def build_url(url_base, rest_of_url)
|
43
|
-
if url_base.end_with?('/') && rest_of_url.start_with?('/')
|
44
|
-
rest_of_url.sub!('/', '')
|
45
|
-
end
|
46
|
-
|
47
|
-
url_base + rest_of_url
|
48
|
-
end
|
49
|
-
|
50
|
-
# @return [Nori::Parser]
|
51
|
-
def xml_parser
|
52
|
-
@xml_parser if @xml_parser
|
53
|
-
|
54
|
-
options = {
|
55
|
-
convert_tags_to: lambda { |tag| tag.to_sym }
|
56
|
-
}
|
57
|
-
|
58
|
-
begin
|
59
|
-
require 'nokogiri'
|
60
|
-
options.merge! parser: :nokogiri
|
61
|
-
rescue LoadError
|
62
|
-
warn "Tried loading nokogiri for XML couldn't. This is OK, just letting you know."
|
63
|
-
end
|
64
|
-
|
65
|
-
@xml_parser = Nori.new(options)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,465 +0,0 @@
|
|
1
|
-
require_relative 'base'
|
2
|
-
require_relative 'service'
|
3
|
-
require_relative 'error'
|
4
|
-
require 'uri'
|
5
|
-
require 'eventmachine'
|
6
|
-
require 'time'
|
7
|
-
|
8
|
-
module Druzy
|
9
|
-
module Upnp
|
10
|
-
class ControlPoint
|
11
|
-
class Device < Base
|
12
|
-
include EM::Deferrable
|
13
|
-
|
14
|
-
attr_reader :ssdp_notification
|
15
|
-
|
16
|
-
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
17
|
-
# Passed in as part of +device_info+; given by the SSDP search response.
|
18
|
-
#
|
19
|
-
attr_reader :cache_control
|
20
|
-
attr_reader :date
|
21
|
-
attr_reader :ext
|
22
|
-
attr_reader :location
|
23
|
-
attr_reader :server
|
24
|
-
attr_reader :st
|
25
|
-
attr_reader :usn
|
26
|
-
#
|
27
|
-
# DONE +device_info+
|
28
|
-
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
29
|
-
|
30
|
-
# @return [Hash] The whole parsed description... just in case.
|
31
|
-
attr_reader :description
|
32
|
-
|
33
|
-
attr_reader :expiration
|
34
|
-
|
35
|
-
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
36
|
-
# Determined by device description file.
|
37
|
-
#
|
38
|
-
|
39
|
-
#------- <root> elements -------
|
40
|
-
|
41
|
-
# @return [String] The xmlns attribute of the device from the description file.
|
42
|
-
attr_reader :xmlns
|
43
|
-
|
44
|
-
# @return [Hash] :major and :minor revisions of the UPnP spec this device adheres to.
|
45
|
-
attr_reader :spec_version
|
46
|
-
|
47
|
-
# @return [String] URLBase from the device's description file.
|
48
|
-
attr_reader :url_base
|
49
|
-
|
50
|
-
#------- <root><device> elements -------
|
51
|
-
|
52
|
-
# @return [String] The type of UPnP device (URN) from the description file.
|
53
|
-
attr_reader :device_type
|
54
|
-
|
55
|
-
# @return [String] Short device description for the end user.
|
56
|
-
attr_reader :friendly_name
|
57
|
-
|
58
|
-
# @return [String] Manufacturer's name.
|
59
|
-
attr_reader :manufacturer
|
60
|
-
|
61
|
-
# @return [String] Manufacturer's web site.
|
62
|
-
attr_reader :manufacturer_url
|
63
|
-
|
64
|
-
# @return [String] Long model description for the end user, from the description file.
|
65
|
-
attr_reader :model_description
|
66
|
-
|
67
|
-
# @return [String] Model name of this device from the description file.
|
68
|
-
attr_reader :model_name
|
69
|
-
|
70
|
-
# @return [String] Model number of this device from the description file.
|
71
|
-
attr_reader :model_number
|
72
|
-
|
73
|
-
# @return [String] Web site for model of this device.
|
74
|
-
attr_reader :model_url
|
75
|
-
|
76
|
-
# @return [String] The serial number from the description file.
|
77
|
-
attr_reader :serial_number
|
78
|
-
|
79
|
-
# @return [String] The UDN for the device, from the description file.
|
80
|
-
attr_reader :udn
|
81
|
-
|
82
|
-
# @return [String] The UPC of the device from the description file.
|
83
|
-
attr_reader :upc
|
84
|
-
|
85
|
-
# @return [Array<Hash>] An Array where each element is a Hash that describes an icon.
|
86
|
-
attr_reader :icon_list
|
87
|
-
|
88
|
-
# Services provided directly by this device.
|
89
|
-
attr_reader :service_list
|
90
|
-
|
91
|
-
# Devices embedded directly into this device.
|
92
|
-
attr_reader :device_list
|
93
|
-
|
94
|
-
# @return [String] URL for device control via a browser.
|
95
|
-
attr_reader :presentation_url
|
96
|
-
|
97
|
-
#
|
98
|
-
# DONE description file
|
99
|
-
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
100
|
-
|
101
|
-
# @param [Hash] device_info
|
102
|
-
# @option device_info [Hash] ssdp_notification
|
103
|
-
# @option device_info [Hash] device_description
|
104
|
-
# @option device_info [Hash] parent_base_url
|
105
|
-
def initialize(device_info)
|
106
|
-
super()
|
107
|
-
|
108
|
-
@device_info = device_info
|
109
|
-
@device_list = []
|
110
|
-
@service_list = []
|
111
|
-
@icon_list = []
|
112
|
-
@xmlns = ''
|
113
|
-
@done_creating_devices = false
|
114
|
-
@done_creating_services = false
|
115
|
-
end
|
116
|
-
|
117
|
-
def fetch
|
118
|
-
description_getter = EventMachine::DefaultDeferrable.new
|
119
|
-
|
120
|
-
description_getter.errback do
|
121
|
-
msg = 'Failed getting description.'
|
122
|
-
@done_creating_devices = true
|
123
|
-
@done_creating_services = true
|
124
|
-
set_deferred_status(:failed, msg)
|
125
|
-
|
126
|
-
if ControlPoint.raise_on_remote_error
|
127
|
-
raise ControlPoint::Error, msg
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
if @device_info.has_key? :ssdp_notification
|
132
|
-
extract_from_ssdp_notification(description_getter)
|
133
|
-
elsif @device_info.has_key? :device_description
|
134
|
-
description_getter.set_deferred_success @device_info[:device_description]
|
135
|
-
else
|
136
|
-
description_getter.set_deferred_failure
|
137
|
-
end
|
138
|
-
|
139
|
-
description_getter.callback do |description|
|
140
|
-
@description = description
|
141
|
-
|
142
|
-
if @description.nil?
|
143
|
-
set_deferred_status(:failed, 'Got back an empty description...')
|
144
|
-
return
|
145
|
-
end
|
146
|
-
|
147
|
-
extract_spec_version
|
148
|
-
|
149
|
-
@url_base = extract_url_base
|
150
|
-
|
151
|
-
if @device_info[:ssdp_notification]
|
152
|
-
@xmlns = @description[:root][:@xmlns]
|
153
|
-
extract_description(@description[:root][:device])
|
154
|
-
elsif @device_info.has_key? :device_description
|
155
|
-
extract_description(@description)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
tickloop = EM.tick_loop do
|
160
|
-
if @done_creating_devices && @done_creating_services
|
161
|
-
:stop
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
tickloop.on_stop { set_deferred_status :succeeded, self }
|
166
|
-
end
|
167
|
-
|
168
|
-
def extract_from_ssdp_notification(callback)
|
169
|
-
@ssdp_notification = @device_info[:ssdp_notification]
|
170
|
-
|
171
|
-
@cache_control = @ssdp_notification[:cache_control]
|
172
|
-
@location = ssdp_notification[:location]
|
173
|
-
@server = ssdp_notification[:server]
|
174
|
-
@st = ssdp_notification[:st] || ssdp_notification[:nt]
|
175
|
-
@ext = ssdp_notification.has_key?(:ext) ? true : false
|
176
|
-
@usn = ssdp_notification[:usn]
|
177
|
-
@date = ssdp_notification[:date] || ''
|
178
|
-
@expiration = if @date.empty?
|
179
|
-
Time.now + @cache_control.match(/\d+/)[0].to_i
|
180
|
-
else
|
181
|
-
Time.at(Time.parse(@date).to_i + @cache_control.match(/\d+/)[0].to_i)
|
182
|
-
end
|
183
|
-
|
184
|
-
if @location
|
185
|
-
get_description(@location, callback)
|
186
|
-
else
|
187
|
-
message = 'M-SEARCH response is either missing the Location header or has an empty value.'
|
188
|
-
message << "Response: #{@ssdp_notification}"
|
189
|
-
|
190
|
-
if ControlPoint.raise_on_remote_error
|
191
|
-
raise ControlPoint::Error, message
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def extract_url_base
|
197
|
-
if @description[:root] && @description[:root][:URLBase]
|
198
|
-
@description[:root][:URLBase]
|
199
|
-
elsif @device_info[:parent_base_url]
|
200
|
-
@device_info[:parent_base_url]
|
201
|
-
else
|
202
|
-
tmp_uri = URI(@location)
|
203
|
-
"#{tmp_uri.scheme}://#{tmp_uri.host}:#{tmp_uri.port}/"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# True if the device hasn't received an alive notification since it last
|
208
|
-
# told its max age.
|
209
|
-
def expired?
|
210
|
-
Time.now > @expiration if @expiration
|
211
|
-
end
|
212
|
-
|
213
|
-
def has_devices?
|
214
|
-
!@device_list.empty?
|
215
|
-
end
|
216
|
-
|
217
|
-
def has_services?
|
218
|
-
!@service_list.empty?
|
219
|
-
end
|
220
|
-
|
221
|
-
def extract_description(ddf)
|
222
|
-
|
223
|
-
@device_type = ddf[:deviceType] || ''
|
224
|
-
@friendly_name = ddf[:friendlyName] || ''
|
225
|
-
@manufacturer = ddf[:manufacturer] || ''
|
226
|
-
@manufacturer_url = ddf[:manufacturerURL] || ''
|
227
|
-
@model_description = ddf[:modelDescription] || ''
|
228
|
-
@model_name = ddf[:modelName] || ''
|
229
|
-
@model_number = ddf[:modelNumber] || ''
|
230
|
-
@model_url = ddf[:modelURL] || ''
|
231
|
-
@serial_number = ddf[:serialNumber] || ''
|
232
|
-
@udn = ddf[:UDN] || ''
|
233
|
-
@upc = ddf[:UPC] || ''
|
234
|
-
@icon_list = extract_icons(ddf[:iconList])
|
235
|
-
@presentation_url = ddf[:presentationURL] || ''
|
236
|
-
|
237
|
-
start_device_extraction
|
238
|
-
start_service_extraction
|
239
|
-
end
|
240
|
-
|
241
|
-
def extract_spec_version
|
242
|
-
if @description[:root]
|
243
|
-
"#{@description[:root][:specVersion][:major]}.#{@description[:root][:specVersion][:minor]}"
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
def start_service_extraction
|
248
|
-
services_extractor = EventMachine::DefaultDeferrable.new
|
249
|
-
|
250
|
-
if @description[:serviceList]
|
251
|
-
extract_services(@description[:serviceList], services_extractor)
|
252
|
-
elsif @description[:root][:device][:serviceList]
|
253
|
-
extract_services(@description[:root][:device][:serviceList], services_extractor)
|
254
|
-
end
|
255
|
-
|
256
|
-
services_extractor.errback do
|
257
|
-
msg = 'Failed extracting services.'
|
258
|
-
@done_creating_services = true
|
259
|
-
|
260
|
-
if ControlPoint.raise_on_remote_error
|
261
|
-
raise ControlPoint::Error, msg
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
services_extractor.callback do |services|
|
266
|
-
@service_list = services
|
267
|
-
|
268
|
-
@done_creating_services = true
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
def start_device_extraction
|
273
|
-
device_extractor = EventMachine::DefaultDeferrable.new
|
274
|
-
extract_devices(device_extractor)
|
275
|
-
|
276
|
-
device_extractor.errback do
|
277
|
-
msg = 'Failed extracting device.'
|
278
|
-
@done_creating_devices = true
|
279
|
-
|
280
|
-
if ControlPoint.raise_on_remote_error
|
281
|
-
raise ControlPoint::Error, msg
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
device_extractor.callback do |device|
|
286
|
-
if device
|
287
|
-
@device_list << device
|
288
|
-
end
|
289
|
-
|
290
|
-
@done_creating_devices = true
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
# @return [Array<Hash>]
|
295
|
-
def extract_icons(ddf_icon_list)
|
296
|
-
return [] unless ddf_icon_list
|
297
|
-
|
298
|
-
if ddf_icon_list[:icon].is_a? Array
|
299
|
-
ddf_icon_list[:icon].map do |values|
|
300
|
-
values[:url] = build_url(@url_base, values[:url])
|
301
|
-
values
|
302
|
-
end
|
303
|
-
else
|
304
|
-
[{
|
305
|
-
mimetype: ddf_icon_list[:icon][:mimetype],
|
306
|
-
width: ddf_icon_list[:icon][:width],
|
307
|
-
height: ddf_icon_list[:icon][:height],
|
308
|
-
depth: ddf_icon_list[:icon][:depth],
|
309
|
-
url: build_url(@url_base, ddf_icon_list[:icon][:url])
|
310
|
-
}]
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
def extract_devices(group_device_extractor)
|
315
|
-
|
316
|
-
device_list_hash = if @description.has_key? :root
|
317
|
-
|
318
|
-
if @description[:root][:device][:deviceList]
|
319
|
-
@description[:root][:device][:deviceList][:device]
|
320
|
-
else
|
321
|
-
group_device_extractor.set_deferred_status(:succeeded)
|
322
|
-
end
|
323
|
-
elsif @description[:deviceList]
|
324
|
-
@description[:deviceList][:device]
|
325
|
-
else
|
326
|
-
group_device_extractor.set_deferred_status(:succeeded)
|
327
|
-
end
|
328
|
-
|
329
|
-
if device_list_hash.nil? || device_list_hash.empty?
|
330
|
-
group_device_extractor.set_deferred_status(:succeeded)
|
331
|
-
return
|
332
|
-
end
|
333
|
-
|
334
|
-
if device_list_hash.is_a? Array
|
335
|
-
EM::Iterator.new(device_list_hash, device_list_hash.count).map(
|
336
|
-
proc do |device, iter|
|
337
|
-
single_device_extractor = EventMachine::DefaultDeferrable.new
|
338
|
-
|
339
|
-
single_device_extractor.errback do
|
340
|
-
msg = 'Failed extracting device.'
|
341
|
-
|
342
|
-
if ControlPoint.raise_on_remote_error
|
343
|
-
raise ControlPoint::Error, msg
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
single_device_extractor.callback do |d|
|
348
|
-
iter.return(d)
|
349
|
-
end
|
350
|
-
|
351
|
-
extract_device(device, single_device_extractor)
|
352
|
-
end,
|
353
|
-
proc do |found_devices|
|
354
|
-
group_device_extractor.set_deferred_status(:succeeded, found_devices)
|
355
|
-
end
|
356
|
-
)
|
357
|
-
else
|
358
|
-
single_device_extractor = EventMachine::DefaultDeferrable.new
|
359
|
-
|
360
|
-
single_device_extractor.errback do
|
361
|
-
msg = 'Failed extracting device.'
|
362
|
-
group_device_extractor.set_deferred_status(:failed, msg)
|
363
|
-
|
364
|
-
if ControlPoint.raise_on_remote_error
|
365
|
-
raise ControlPoint::Error, msg
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
single_device_extractor.callback do |device|
|
370
|
-
group_device_extractor.set_deferred_status(:succeeded, [device])
|
371
|
-
end
|
372
|
-
|
373
|
-
extract_device(device_list_hash, group_device_extractor)
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
def extract_device(device, device_extractor)
|
378
|
-
deferred_device = Device.new(device_description: device, parent_base_url: @url_base)
|
379
|
-
|
380
|
-
deferred_device.errback do
|
381
|
-
msg = "Couldn't build device!"
|
382
|
-
device_extractor.set_deferred_status(:failed, msg)
|
383
|
-
|
384
|
-
if ControlPoint.raise_on_remote_error
|
385
|
-
raise ControlPoint::Error, msg
|
386
|
-
end
|
387
|
-
end
|
388
|
-
|
389
|
-
deferred_device.callback do |built_device|
|
390
|
-
device_extractor.set_deferred_status(:succeeded, built_device)
|
391
|
-
end
|
392
|
-
|
393
|
-
deferred_device.fetch
|
394
|
-
end
|
395
|
-
|
396
|
-
def extract_services(service_list, group_service_extractor)
|
397
|
-
return if service_list.nil?
|
398
|
-
|
399
|
-
service_list.each_value do |service|
|
400
|
-
if service.is_a? Array
|
401
|
-
EM::Iterator.new(service, service.count).map(
|
402
|
-
proc do |s, iter|
|
403
|
-
single_service_extractor = EventMachine::DefaultDeferrable.new
|
404
|
-
|
405
|
-
single_service_extractor.errback do
|
406
|
-
msg = 'Failed to create service.'
|
407
|
-
|
408
|
-
if ControlPoint.raise_on_remote_error
|
409
|
-
raise ControlPoint::Error, msg
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
single_service_extractor.callback do |serv|
|
414
|
-
iter.return(serv)
|
415
|
-
end
|
416
|
-
|
417
|
-
extract_service(s, single_service_extractor)
|
418
|
-
end,
|
419
|
-
proc do |found_services|
|
420
|
-
group_service_extractor.set_deferred_status(:succeeded, found_services)
|
421
|
-
end
|
422
|
-
)
|
423
|
-
else
|
424
|
-
single_service_extractor = EventMachine::DefaultDeferrable.new
|
425
|
-
|
426
|
-
single_service_extractor.errback do
|
427
|
-
msg = 'Failed to create service.'
|
428
|
-
group_service_extractor.set_deferred_status :failed, msg
|
429
|
-
|
430
|
-
if ControlPoint.raise_on_remote_error
|
431
|
-
raise ControlPoint::Error, msg
|
432
|
-
end
|
433
|
-
end
|
434
|
-
|
435
|
-
single_service_extractor.callback do |s|
|
436
|
-
group_service_extractor.set_deferred_status :succeeded, [s]
|
437
|
-
end
|
438
|
-
|
439
|
-
extract_service(service, single_service_extractor)
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|
443
|
-
|
444
|
-
def extract_service(service, single_service_extractor)
|
445
|
-
service_getter = Service.new(@url_base, service)
|
446
|
-
|
447
|
-
service_getter.errback do |message|
|
448
|
-
msg = "Couldn't build service with info: #{service}"
|
449
|
-
single_service_extractor.set_deferred_status(:failed, msg)
|
450
|
-
|
451
|
-
if ControlPoint.raise_on_remote_error
|
452
|
-
raise ControlPoint::Error, message
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
service_getter.callback do |built_service|
|
457
|
-
single_service_extractor.set_deferred_status(:succeeded, built_service)
|
458
|
-
end
|
459
|
-
|
460
|
-
service_getter.fetch
|
461
|
-
end
|
462
|
-
end
|
463
|
-
end
|
464
|
-
end
|
465
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Druzy
|
2
|
-
module Upnp
|
3
|
-
class ControlPoint
|
4
|
-
class Error < StandardError
|
5
|
-
#
|
6
|
-
end
|
7
|
-
|
8
|
-
# Indicates an error occurred when performing a UPnP action while controlling
|
9
|
-
# a device. See section 3.2 of the UPnP spec.
|
10
|
-
class ActionError < StandardError
|
11
|
-
#
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|