rbupnptools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/upnp_event.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'nokogiri'
2
+ require 'net/http'
3
+ require_relative 'upnp_xml.rb'
4
+
5
+ class NotifyRequest < Net::HTTPRequest
6
+ METHOD = 'NOTIFY'
7
+ REQUEST_HAS_BODY = true
8
+ RESPONSE_HAS_BODY = false
9
+ end
10
+
11
+ class SubscribeRequest < Net::HTTPRequest
12
+ METHOD = 'SUBSCRIBE'
13
+ REQUEST_HAS_BODY = false
14
+ RESPONSE_HAS_BODY = false
15
+ end
16
+
17
+ class UnsubscribeRequest < Net::HTTPRequest
18
+ METHOD = 'UNSUBSCRIBE'
19
+ REQUEST_HAS_BODY = false
20
+ RESPONSE_HAS_BODY = false
21
+ end
22
+
23
+ class UPnPEventProperty < Hash
24
+ def to_xml
25
+ propertyset = XmlTag.new 'e:propertyset'
26
+ propertyset.attributes = {
27
+ 'xmlns:e' => "urn:schemas-upnp-org:event-1-0"
28
+ }
29
+ self.each do |k,v|
30
+ prop = propertyset.append XmlTag.new 'e:property'
31
+ prop.append(XmlTag.new(k)).append(XmlText.new(v))
32
+ end
33
+ return propertyset.to_s
34
+ end
35
+ end
36
+
37
+ def UPnPEventProperty.to_xml_doc(property)
38
+ return '<?xml version="1.0" encoding="UTF-8"?>' + "\n#{property.to_xml}"
39
+ end
40
+
41
+ def UPnPEventProperty.read(xml)
42
+ props = UPnPEventProperty.new
43
+ doc = Nokogiri::XML(xml)
44
+ doc.root.elements.each do |elem|
45
+ if elem.name == 'property'
46
+ name = elem.elements.first.name
47
+ value = elem.elements.first.text
48
+ props[name] = value
49
+ end
50
+ end
51
+ props
52
+ end
53
+
54
+ class UPnPEventListener
55
+ def initialize(on_event_notify = nil)
56
+ @on_event_notify = on_event_notify
57
+ end
58
+
59
+ def on_event_notify(sid, props)
60
+ if @on_event_notify
61
+ @on_event_notify.call sid, props
62
+ end
63
+ end
64
+ end
65
+
66
+ class UPnPEventSubscription
67
+ def initialize(device, service, sid, timeout, callback_urls = nil)
68
+ @device = device
69
+ @service = service
70
+ @sid = sid
71
+ @timeout = timeout
72
+ @reg_date = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
73
+ @callback_urls = callback_urls
74
+ end
75
+
76
+ attr_accessor :device, :service, :sid, :timeout, :callback_urls
77
+
78
+ def renew_timeout
79
+ @reg_date = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
80
+ end
81
+
82
+ def expired?
83
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
84
+ return (now - @reg_date) >= @tiemout
85
+ end
86
+ end
data/lib/upnp_model.rb ADDED
@@ -0,0 +1,419 @@
1
+ require 'nokogiri'
2
+ require 'securerandom'
3
+ require_relative 'upnp_xml.rb'
4
+
5
+
6
+ class UPnPModel < Hash
7
+ def self.to_method_name(name)
8
+ return name.gsub(/([a-z])([A-Z]+)/, '\1_\2').downcase
9
+ end
10
+
11
+ def self.define_xml_attr(*names)
12
+ names.each do |name|
13
+ name = "#{name}"
14
+ define_method "#{to_method_name(name)}" do
15
+ self[name]
16
+ end
17
+ define_method "#{to_method_name(name)}=" do |v|
18
+ self[name] = v
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ class UPnPSpecVersion
25
+
26
+ attr_accessor :major, :minor
27
+
28
+ def to_s
29
+ "UPnPSpecVersion -- 'major: #{@major}, minor: #{minor}'"
30
+ end
31
+
32
+ def to_xml
33
+ spec_version = XmlTag.new('specVersion')
34
+ spec_version.append(XmlTag.new('major')).append(XmlText.new(@major))
35
+ spec_version.append(XmlTag.new('minor')).append(XmlText.new(@minor))
36
+ return spec_version.to_s
37
+ end
38
+
39
+ end
40
+
41
+ def UPnPSpecVersion.read_xml_node(node)
42
+ spec_version = UPnPSpecVersion.new
43
+ node.elements.each { |elem|
44
+ if elem.name == 'major'
45
+ spec_version.major = elem.text
46
+ elsif elem.name == 'minor'
47
+ spec_version.minor = elem.text
48
+ end
49
+ }
50
+ return spec_version
51
+ end
52
+
53
+
54
+ class UPnPDevice < UPnPModel
55
+ def initialize
56
+ @child_devices = []
57
+ @services = []
58
+ end
59
+
60
+ attr_accessor :base_url
61
+ attr_accessor :child_devices
62
+ attr_accessor :services
63
+
64
+ define_xml_attr :deviceType, :UDN, :friendlyName, :manufacturer, :manufacturerURL,
65
+ :modelDescription, :modelName, :modelNumber, :modelURL, :serialNumber
66
+
67
+ def usn
68
+ return udn + '::' + device_type
69
+ end
70
+
71
+ def all_usn
72
+ usn_list = []
73
+ usn_list << usn
74
+ @services.each do |service|
75
+ usn_list << udn + '::' + service.service_type
76
+ end
77
+ @child_devices.each do |device|
78
+ usn_list += device.all_usn
79
+ end
80
+ return usn_list
81
+ end
82
+
83
+ def get_device(type)
84
+ all_devices.each do |device|
85
+ if device.device_type == type
86
+ return device
87
+ end
88
+ end
89
+ nil
90
+ end
91
+
92
+ def get_service(type)
93
+ all_services.each do |service|
94
+ if service.service_type == type
95
+ return service
96
+ end
97
+ end
98
+ nil
99
+ end
100
+
101
+ def all_devices
102
+ devices = []
103
+ devices << self
104
+ @child_devices.each do |device|
105
+ devices += device.all_devices
106
+ end
107
+ return devices
108
+ end
109
+
110
+ def all_services
111
+ services = @services
112
+ @child_devices.each do |device|
113
+ services += device.all_services
114
+ end
115
+ return services
116
+ end
117
+
118
+ def to_s
119
+ "UPnPDevice -- '#{friendly_name}' (#{udn})"
120
+ end
121
+
122
+ def to_xml
123
+ device = XmlTag.new 'device'
124
+ self.each { |k,v|
125
+ device.append(XmlTag.new(k)).append(XmlText.new(v))
126
+ }
127
+
128
+ if @services.any?
129
+ serviceList = device.append XmlTag.new('serviceList')
130
+ @services.each { |service|
131
+ serviceList.append service.to_xml
132
+ }
133
+ end
134
+
135
+ if @child_devices.any?
136
+ deviceList = device.append XmlTag.new('deviceList')
137
+ @child_devices.each { |device|
138
+ deviceList.append device.to_xml
139
+ }
140
+ end
141
+ return device.to_s
142
+ end
143
+ end
144
+
145
+ def UPnPDevice.to_xml_doc(device)
146
+ root = XmlTag.new 'root'
147
+ root.attributes['xmlns'] = 'urn:schemas-upnp-org:device-1-0'
148
+
149
+ specVersion = root.append(XmlTag.new('specVersion'))
150
+ specVersion.append(XmlTag.new('major')).append(XmlText.new(1))
151
+ specVersion.append(XmlTag.new('major')).append(XmlText.new(0))
152
+
153
+ root.append device.to_xml
154
+ return '<?xml version="1.0" encoding="UTF-8"?>' + "\n#{root}"
155
+ end
156
+
157
+ def UPnPDevice.read(xml)
158
+ doc = Nokogiri::XML(xml)
159
+ doc.root.elements.each do |elem|
160
+ if elem.name == 'specVersion'
161
+ spec_version = UPnPSpecVersion.read_xml_node elem
162
+ elsif elem.name == 'device'
163
+ return UPnPDevice.read_xml_node elem
164
+ end
165
+ end
166
+ nil
167
+ end
168
+
169
+ def UPnPDevice.read_xml_node(node)
170
+ device = UPnPDevice.new
171
+ node.elements.each do |elem|
172
+ if elem.elements.empty?
173
+ device[elem.name] = elem.text
174
+ elsif elem.name == 'deviceList'
175
+ elem.elements.each do |device_node|
176
+ if device_node.name == 'device'
177
+ device.child_devices << UPnPDevice.read_xml_node(device_node)
178
+ end
179
+ end
180
+ elsif elem.name == 'serviceList'
181
+ elem.elements.each do |service_node|
182
+ if service_node.name == 'service'
183
+ device.services << UPnPService.read_xml_node(service_node)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ device
189
+ end
190
+
191
+
192
+ class UPnPService < UPnPModel
193
+ attr_accessor :scpd
194
+
195
+ define_xml_attr :serviceId, :serviceType, :SCPDURL, :controlURL, :eventSubURL
196
+
197
+ def to_xml
198
+ service = XmlTag.new 'service'
199
+ self.each { |k,v|
200
+ service.append(XmlTag.new(k)).append(XmlText.new(v))
201
+ }
202
+ return service.to_s
203
+ end
204
+ end
205
+
206
+ def UPnPService.read_xml_node(node)
207
+ service = UPnPService.new
208
+ node.elements.each do |elem|
209
+ if elem.elements.empty?
210
+ service[elem.name] = elem.text
211
+ end
212
+ end
213
+ service
214
+ end
215
+
216
+
217
+ class UPnPScpd < UPnPModel
218
+
219
+ def initialize
220
+ @actions = []
221
+ @state_variables = []
222
+ end
223
+
224
+ attr_accessor :spec_version, :actions, :state_variables
225
+
226
+ def to_xml
227
+ scpd = XmlTag.new 'scpd'
228
+ scpd.attributes['xmlns'] = 'urn:schemas-upnp-org:service-1-0'
229
+
230
+ spec_version = scpd.append XmlTag.new('specVersion')
231
+ spec_version.append(XmlTag.new('major')).append(XmlText.new(1))
232
+ spec_version.append(XmlTag.new('minor')).append(XmlText.new(0))
233
+
234
+ action_list = scpd.append XmlTag.new('actionList')
235
+ @actions.each { |action|
236
+ action_list.append action.to_xml
237
+ }
238
+
239
+ service_state_table = scpd.append XmlTag.new('serviceStateTable');
240
+ @state_variables.each { |state_variable|
241
+ service_state_table.append state_variable.to_xml
242
+ }
243
+ return scpd.to_s
244
+
245
+ end
246
+ end
247
+
248
+ def UPnPScpd.to_xml_doc(scpd)
249
+ return '<?xml version="1.0" encoding="UTF-8"?>' + "\n#{scpd.to_xml}"
250
+ end
251
+
252
+ def UPnPScpd.read(xml)
253
+ scpd = UPnPScpd.new
254
+ doc = Nokogiri::XML(xml)
255
+ doc.root.elements.each do |elem|
256
+ case elem.name
257
+ when 'specVersion'
258
+ scpd.spec_version = [1,0]
259
+ when 'actionList'
260
+ elem.elements.each { |action_node|
261
+ if action_node.name == 'action'
262
+ action = UPnPAction.read_xml_node(action_node)
263
+ scpd.actions << action
264
+ end
265
+ }
266
+ when 'serviceStateTable'
267
+ elem.elements.each { |state_variable_node|
268
+ if state_variable_node.name == 'stateVariable'
269
+ state_variable = UPnPStateVariable.read_xml_node(state_variable_node)
270
+ scpd.state_variables << state_variable
271
+ end
272
+ }
273
+ end
274
+ end
275
+ return scpd
276
+ end
277
+
278
+
279
+ class UPnPAction < UPnPModel
280
+ def initialize
281
+ @arguments = []
282
+ end
283
+
284
+ attr_accessor :name
285
+ attr_accessor :arguments
286
+
287
+ def get_argument(name)
288
+ @arguments.each { |argument|
289
+ if argument.name == name
290
+ return argument
291
+ end
292
+ }
293
+ nil
294
+ end
295
+
296
+ def in_arguments
297
+ @arguments.select { |argument| argument.direction == 'in' }
298
+ end
299
+
300
+ def out_arguments
301
+ @arguments.select { |argument| argument.direction == 'out' }
302
+ end
303
+
304
+ def to_s
305
+ "UPnPAction -- #{@name}"
306
+ end
307
+
308
+ def to_xml
309
+ action = XmlTag.new 'action'
310
+
311
+ prop = action.append XmlTag.new 'name'
312
+ prop.append XmlText.new @name
313
+
314
+ argument_list = action.append XmlTag.new 'argumentList'
315
+ @arguments.each { |argument|
316
+ argument_list.append argument.to_xml
317
+ }
318
+
319
+ return action.to_s
320
+ end
321
+ end
322
+
323
+ def UPnPAction.read_xml_node(node)
324
+ action = UPnPAction.new
325
+ node.elements.each do |elem|
326
+ if elem.name == 'name'
327
+ action.name = elem.text
328
+ elsif elem.name == 'argumentList'
329
+ elem.elements.each { |argument_node|
330
+ if argument_node.name == 'argument'
331
+ action.arguments << UPnPActionArgument.read_xml_node(argument_node)
332
+ end
333
+ }
334
+ end
335
+ end
336
+ return action
337
+ end
338
+
339
+
340
+ class UPnPActionArgument < UPnPModel
341
+ attr_accessor :name, :direction, :related_state_variable
342
+
343
+ def to_s
344
+ "UPnPActionArgument -- #{@name} (direction: '#{@direction}' related state variable: '#{@related_state_variable}')"
345
+ end
346
+
347
+ def to_xml
348
+ argument = XmlTag.new 'argument'
349
+
350
+ prop = argument.append XmlTag.new 'name'
351
+ prop.append XmlText.new @name
352
+
353
+ prop = argument.append XmlTag.new 'direction'
354
+ prop.append XmlText.new @direction
355
+
356
+ prop = argument.append XmlTag.new 'relatedStateVariable'
357
+ prop.append XmlText.new @related_state_variable
358
+
359
+ return argument.to_s
360
+ end
361
+ end
362
+
363
+ def UPnPActionArgument.read_xml_node(node)
364
+ argument = UPnPActionArgument.new
365
+ node.elements.each do |elem|
366
+ case elem.name
367
+ when 'name'
368
+ argument.name = elem.text
369
+ when 'direction'
370
+ argument.direction = elem.text
371
+ when 'relatedStateVariable'
372
+ argument.related_state_variable = elem.text
373
+ end
374
+ end
375
+ return argument
376
+ end
377
+
378
+
379
+ class UPnPStateVariable < UPnPModel
380
+ attr_accessor :name, :data_type, :send_events, :multicast
381
+
382
+ def to_s
383
+ "State Variable -- #{@name} (data type: '#{@data_type}' send events? '#{@send_events}' multicast? '#{@multicast}')"
384
+ end
385
+
386
+ def to_xml
387
+ state_variable = XmlTag.new 'stateVariable'
388
+ if @send_events != nil
389
+ state_variable.attributes['sendEvents'] = @send_events
390
+ end
391
+
392
+ if @multicast != nil
393
+ state_variable.attributes['multicast'] = @multicast
394
+ end
395
+
396
+ prop = state_variable.append XmlTag.new 'name'
397
+ prop.append XmlText.new @name
398
+
399
+ prop = state_variable.append XmlTag.new 'dataType'
400
+ prop.append XmlText.new @data_type
401
+
402
+ return state_variable.to_s
403
+ end
404
+ end
405
+
406
+ def UPnPStateVariable.read_xml_node(node)
407
+ state_variable = UPnPStateVariable.new
408
+ state_variable.send_events = node.attribute('sendEvents')
409
+ state_variable.multicast = node.attribute('multicast')
410
+ node.elements.each do |elem|
411
+ case elem.name
412
+ when 'name'
413
+ state_variable.name = elem.text
414
+ when 'dataType'
415
+ state_variable.data_type = elem.text
416
+ end
417
+ end
418
+ return state_variable
419
+ end