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 +4 -4
- data/lib/easy_upnp/argument_validator.rb +125 -0
- data/lib/easy_upnp/device_control_point.rb +62 -2
- data/lib/easy_upnp/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14a33377666a3b363416fdc8080e4bf411f2574d
|
4
|
+
data.tar.gz: b6c87a73312c8c4002b9d4d1206518f2f43c199a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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: {
|
data/lib/easy_upnp/version.rb
CHANGED
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.
|
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-
|
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
|