easy_upnp 0.3.2 → 0.4.1

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: 7e627952f646058b6e52e0e07dd1d41e3537239d
4
- data.tar.gz: ff1632d0686e54b5af395bdee11d355d0af23020
3
+ metadata.gz: 14a33377666a3b363416fdc8080e4bf411f2574d
4
+ data.tar.gz: b6c87a73312c8c4002b9d4d1206518f2f43c199a
5
5
  SHA512:
6
- metadata.gz: 7b3b414baf2608cbb3b1a86fae78b1cf4081c8610ad65c1ec7dbcc7cc29d0746cbd87e96c1c3dc2051dfa69d5569913dc2dadf0c7a29da0423edcbb8885ad8a9
7
- data.tar.gz: 3a494127415a59897a9573d6c0af584980c88dce64c971f6a16b05ac43d0264ed7279d6ef0fe01a8f44279a073e53f47a7c422bcf7c569acb0fa41d2c270db9c
6
+ metadata.gz: dcd63c1ca7bd1060112f5da3e12b8b05f8b8ab34053e3f57e93eb4c67e0015ce1d33d54505d7374c19c0e7c2d893cd95e129f8f5bce9fbaabe29de0659777d2d
7
+ data.tar.gz: ef39cf1f54bbb336e53df619f62f9a181f7f5050baec03e83e7495cddf809052d45af2caf1fb958493c5fbc87b792f9bad1fa8b9b28c0d503002a3e17887fadd
@@ -0,0 +1,125 @@
1
+ module EasyUpnp
2
+ class ArgumentValidator
3
+ class Builder
4
+ def initialize(&block)
5
+ @validators = {}
6
+ block.call(self) if block
7
+ end
8
+
9
+ def in_range(min, max, step = 1)
10
+ add_validator(RangeValidator.new((min..max).step(step)))
11
+ end
12
+
13
+ def allowed_values(*values)
14
+ add_validator(AllowedValueValidator.new(*values))
15
+ end
16
+
17
+ def type(type)
18
+ add_validator(TypeValidator.new(type))
19
+ end
20
+
21
+ def add_validator(validator)
22
+ @validators[validator.class] = validator
23
+ end
24
+
25
+ def build
26
+ ArgumentValidator.new(@validators)
27
+ end
28
+ end
29
+
30
+ class RangeValidator
31
+ attr_reader :range
32
+
33
+ def initialize(range)
34
+ @range = range
35
+ end
36
+
37
+ def validate(value)
38
+ if !@range.include?(value)
39
+ raise ArgumentError, "#{value} is not in allowed range of values: #{@range.inspect}"
40
+ end
41
+ end
42
+ end
43
+
44
+ class AllowedValueValidator
45
+ attr_reader :allowed_values
46
+
47
+ def initialize(*allowed_values)
48
+ @allowed_values = allowed_values
49
+ end
50
+
51
+ def validate(value)
52
+ if !@allowed_values.include?(value)
53
+ raise ArgumentError, "#{value} is not in list of allowed values: #{@allowed_values.inspect}"
54
+ end
55
+ end
56
+ end
57
+
58
+ class TypeValidator
59
+ # Valid UPnP types for each ruby class
60
+ RUBY_TYPE_TO_UPNP_TYPE = {
61
+ Float: %w{r4 r8 number fixed.14.4 float},
62
+ Integer: %w{ui1 ui2 ui4 i1 i2 i4 int},
63
+ String: %w{char string bin.base64 bin.hex uri uuid},
64
+ TrueClass: %w{bool boolean},
65
+ FalseClass: %w{bool boolean},
66
+ DateTime: %w{date dateTime dateTime.tz time time.tz},
67
+ Time: %w{date dateTime dateTime.tz time time.tz},
68
+ Date: %w{date dateTime time}
69
+ }
70
+
71
+ # Inversion of RUBY_TYPE_TO_UPNP_TYPE.
72
+ UPNP_TYPE_VALID_CLASSES = Hash[
73
+ RUBY_TYPE_TO_UPNP_TYPE.map { |k,v|
74
+ k = Kernel.const_get(k)
75
+ v.map { |x| [x, k] }
76
+ }.reduce({}) { |a,i|
77
+ Hash[i].each { |x,y| a[x] ||= []; a[x] << y }
78
+ a
79
+ }
80
+ ]
81
+
82
+ attr_reader :valid_classes
83
+
84
+ def initialize(type)
85
+ @valid_classes = UPNP_TYPE_VALID_CLASSES[type]
86
+ raise ArgumentError, "Unrecognized UPnP type: #{type}" if @valid_classes.nil?
87
+ end
88
+
89
+ def validate(value)
90
+ if !@valid_classes.any? { |x| value.is_a?(x) }
91
+ raise ArgumentError, "#{value} is the wrong type. Should be one of: #{@valid_classes.inspect}"
92
+ end
93
+ end
94
+ end
95
+
96
+ def initialize(validators)
97
+ @validators = validators
98
+ end
99
+
100
+ def validate(value)
101
+ @validators.each { |_, v| v.validate(value) }
102
+ true
103
+ end
104
+
105
+ def required_class
106
+ return nil unless @validators[TypeValidator]
107
+ c = @validators[TypeValidator].valid_classes
108
+ c.size == 1 ? c.first : c
109
+ end
110
+
111
+ def allowed_values
112
+ return nil unless @validators[AllowedValueValidator]
113
+ @validators[AllowedValueValidator].allowed_values
114
+ end
115
+
116
+ def valid_range
117
+ return nil unless @validators[RangeValidator]
118
+ @validators[RangeValidator].range
119
+ end
120
+
121
+ def self.build(&block)
122
+ Builder.new(&block).build
123
+ end
124
+ end
125
+ end
@@ -3,6 +3,7 @@ require 'open-uri'
3
3
  require 'nori'
4
4
 
5
5
  require_relative 'logger'
6
+ require_relative 'argument_validator'
6
7
 
7
8
  module EasyUpnp
8
9
  class DeviceControlPoint
@@ -10,7 +11,8 @@ module EasyUpnp
10
11
 
11
12
  class Options
12
13
  DEFAULTS = {
13
- advanced_typecasting: true
14
+ advanced_typecasting: true,
15
+ validate_arguments: false
14
16
  }
15
17
 
16
18
  attr_reader :options
@@ -57,11 +59,29 @@ module EasyUpnp
57
59
  definition_xml.remove_namespaces!
58
60
 
59
61
  service_methods = []
62
+ service_methods_args = {}
60
63
  definition_xml.xpath('//actionList/action').map do |action|
61
- service_methods.push define_action(action)
64
+ service_methods.push(define_action(action))
65
+
66
+ name = action.xpath('name').text
67
+ args = {}
68
+ action.xpath('argumentList/argument').map do |arg|
69
+ arg_name = arg.xpath('name').text
70
+ arg_ref = arg.xpath('relatedStateVariable').text
71
+ args[arg_name.to_sym] = arg_ref.to_sym
72
+ end
73
+ service_methods_args[name.to_sym] = args
74
+ end
75
+
76
+ arg_validators = {}
77
+ definition_xml.xpath('//serviceStateTable/stateVariable').map do |var|
78
+ name = var.xpath('name').text
79
+ arg_validators[name.to_sym] = extract_validators(var)
62
80
  end
63
81
 
64
82
  @service_methods = service_methods
83
+ @service_methods_args = service_methods_args
84
+ @arg_validators = arg_validators
65
85
  end
66
86
 
67
87
  def to_params
@@ -111,8 +131,38 @@ module EasyUpnp
111
131
  end
112
132
  end
113
133
 
134
+ def arg_validator(method, arg)
135
+ method_args = @service_methods_args[method.to_sym]
136
+ raise ArgumentError, "Unknown method: #{method}" if method_args.nil?
137
+
138
+ arg_ref = method_args[arg.to_sym]
139
+ raise ArgumentValidator, "Unknown argument: #{arg}" if arg_ref.nil?
140
+
141
+ @arg_validators[arg_ref]
142
+ end
143
+
114
144
  private
115
145
 
146
+ def extract_validators(var)
147
+ ArgumentValidator.build do |v|
148
+ v.type(var.xpath('dataType').text)
149
+
150
+ if (range = var.xpath('allowedValueRange')).any?
151
+ min = range.xpath('minimum').text
152
+ max = range.xpath('maximum').text
153
+ step = range.xpath('step')
154
+ step = step.any? ? step.text : 1
155
+
156
+ v.in_range(min.to_i, max.to_i, step.to_i)
157
+ end
158
+
159
+ if (list = var.xpath('allowedValueList')).any?
160
+ allowed_values = list.xpath('allowedValue').map { |x| x.text }
161
+ v.allowed_values(*allowed_values)
162
+ end
163
+ end
164
+ end
165
+
116
166
  def define_action(action)
117
167
  action = Nori.new.parse(action.to_xml)['action']
118
168
  action_name = action['name']
@@ -138,6 +188,16 @@ module EasyUpnp
138
188
  " Supported args: #{input_args}"
139
189
  end
140
190
 
191
+ if @options.validate_arguments
192
+ args_hash.each { |k,v|
193
+ begin
194
+ arg_validator(action['name'], k).validate(v)
195
+ rescue ArgumentError => e
196
+ raise ArgumentError, "Invalid value for argument #{k}: #{e}"
197
+ end
198
+ }
199
+ end
200
+
141
201
  attrs = {
142
202
  soap_action: "#{@urn}##{action_name}",
143
203
  attributes: {
@@ -1,3 +1,3 @@
1
1
  module EasyUpnp
2
- VERSION = '0.3.2'
2
+ VERSION = '0.4.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_upnp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Mullins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-01 00:00:00.000000000 Z
11
+ date: 2016-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -94,6 +94,7 @@ files:
94
94
  - Rakefile
95
95
  - bin/upnp-list
96
96
  - easy_upnp.gemspec
97
+ - lib/easy_upnp/argument_validator.rb
97
98
  - lib/easy_upnp/device_control_point.rb
98
99
  - lib/easy_upnp/logger.rb
99
100
  - lib/easy_upnp/ssdp_searcher.rb