easy_upnp 0.1.8 → 0.2.1
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/README.md +19 -0
- data/lib/easy_upnp/device_control_point.rb +68 -10
- data/lib/easy_upnp/ssdp_searcher.rb +1 -1
- data/lib/easy_upnp/upnp_device.rb +9 -44
- data/lib/easy_upnp/version.rb +1 -1
- metadata +16 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff03da48709a543a35dbfe13a1ece864d9337db6
|
4
|
+
data.tar.gz: 61517d04933afc34e2465de2400c577d001b63fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dbf1e5b113b33fe94db16655421b17f22f72eb57f5deb80521a2f5d6c83e4b097384495370ace08124fdce9da5e1fef228d8b960fefa408a3cc15c0aefb83ff
|
7
|
+
data.tar.gz: 50a3d09bd2a1d2fb00f8afab09fca6a95db15c1118a424fdde175e5ab2ddecd537109ef789dc163effac4e1708490c8667342c2c2088a3824dc6474b3c973f75
|
data/README.md
CHANGED
@@ -53,3 +53,22 @@ service.service_methods
|
|
53
53
|
service.GetSystemUpdateID
|
54
54
|
# => {:Id=>"207"}
|
55
55
|
```
|
56
|
+
|
57
|
+
## Static client construction
|
58
|
+
|
59
|
+
After you've constructed a client (`DeviceControlPoint`), you probably don't want to have to use SSDP to construct it again the next time you use it. `DeviceControlPoint` is equipped with `#to_params` and `#from_params` methods to make this easy.
|
60
|
+
|
61
|
+
Say you have a client called `client`. To dump it into a hash, do the following:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
params = client.to_params
|
65
|
+
#=> {:urn=>"urn:schemas-upnp-org:service:ContentDirectory:1", :service_endpoint=>"http://10.133.8.11:8200/ctl/ContentDir", :definition=>"<?xml version=\"1.0\"?>\r\n<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">( ... clipped ... )</scpd>", :options=>{}}
|
66
|
+
```
|
67
|
+
|
68
|
+
We can then reconstruct a client from these params and use it normally:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
client = EasyUpnp::DeviceControlPoint.from_params(params)
|
72
|
+
client.GetSystemUpdateID
|
73
|
+
=> {:Id=>"258"}
|
74
|
+
```
|
@@ -6,22 +6,80 @@ module EasyUpnp
|
|
6
6
|
class DeviceControlPoint
|
7
7
|
attr_reader :service_methods
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@
|
11
|
-
@
|
9
|
+
def initialize(urn, service_endpoint, definition, options)
|
10
|
+
@urn = urn
|
11
|
+
@service_endpoint = service_endpoint
|
12
12
|
@options = options
|
13
|
+
@definition = definition
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
@client = Savon.client do |c|
|
16
|
+
c.endpoint service_endpoint
|
17
|
+
c.namespace urn
|
18
|
+
|
19
|
+
# I found this was necessary on some of my UPnP devices (namely, a Sony TV).
|
20
|
+
c.namespaces({:'s:encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/"})
|
21
|
+
|
22
|
+
# This makes XML tags be like <ObjectID> instead of <objectID>.
|
23
|
+
c.convert_request_keys_to :camelcase
|
24
|
+
|
25
|
+
c.namespace_identifier :u
|
26
|
+
c.env_namespace :s
|
27
|
+
end
|
17
28
|
|
18
|
-
definition
|
29
|
+
definition_xml = Nokogiri::XML(definition)
|
30
|
+
definition_xml.remove_namespaces!
|
31
|
+
|
32
|
+
service_methods = []
|
33
|
+
definition_xml.xpath('//actionList/action').map do |action|
|
19
34
|
service_methods.push define_action(action)
|
20
35
|
end
|
21
36
|
|
22
37
|
@service_methods = service_methods
|
23
38
|
end
|
24
39
|
|
40
|
+
def to_params
|
41
|
+
{
|
42
|
+
urn: @urn,
|
43
|
+
service_endpoint: @service_endpoint,
|
44
|
+
definition: @definition,
|
45
|
+
options: @options
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.from_params(params)
|
50
|
+
DeviceControlPoint.new(
|
51
|
+
params[:urn],
|
52
|
+
params[:service_endpoint],
|
53
|
+
params[:definition],
|
54
|
+
params[:options]
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.from_service_definition(definition, options = {})
|
59
|
+
urn = definition[:st]
|
60
|
+
root_uri = definition[:location]
|
61
|
+
|
62
|
+
xml = Nokogiri::XML(open(root_uri))
|
63
|
+
xml.remove_namespaces!
|
64
|
+
|
65
|
+
service = xml.xpath("//device/serviceList/service[serviceType=\"#{urn}\"]").first
|
66
|
+
|
67
|
+
if service.nil?
|
68
|
+
raise RuntimeError.new "Couldn't find service with urn: #{urn}"
|
69
|
+
else
|
70
|
+
service = Nokogiri::XML(service.to_xml)
|
71
|
+
service_definition_uri = URI.join(root_uri, service.xpath('service/SCPDURL').text).to_s
|
72
|
+
service_definition = open(service_definition_uri) { |f| f.read }
|
73
|
+
|
74
|
+
DeviceControlPoint.new(
|
75
|
+
urn,
|
76
|
+
URI.join(root_uri, service.xpath('service/controlURL').text).to_s,
|
77
|
+
service_definition,
|
78
|
+
options
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
25
83
|
private
|
26
84
|
|
27
85
|
def define_action(action)
|
@@ -47,9 +105,9 @@ module EasyUpnp
|
|
47
105
|
end
|
48
106
|
|
49
107
|
attrs = {
|
50
|
-
soap_action: "#{@
|
108
|
+
soap_action: "#{@urn}##{action_name}",
|
51
109
|
attributes: {
|
52
|
-
:'xmlns:u' => @
|
110
|
+
:'xmlns:u' => @urn
|
53
111
|
},
|
54
112
|
}.merge(@options)
|
55
113
|
|
@@ -86,4 +144,4 @@ module EasyUpnp
|
|
86
144
|
downcase
|
87
145
|
end
|
88
146
|
end
|
89
|
-
end
|
147
|
+
end
|
@@ -63,7 +63,7 @@ module EasyUpnp
|
|
63
63
|
# and create UpnpDevices for them. This wrap the services advertized by the SSDP
|
64
64
|
# results.
|
65
65
|
parsed_messages.reject { |x| !x[:usn] }.group_by { |x| x[:usn].split('::').first }.map do |k, v|
|
66
|
-
UpnpDevice.
|
66
|
+
UpnpDevice.from_ssdp_messages(k, v)
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
@@ -9,9 +9,13 @@ module EasyUpnp
|
|
9
9
|
class UpnpDevice
|
10
10
|
attr_reader :uuid, :name, :host
|
11
11
|
|
12
|
-
def initialize
|
12
|
+
def initialize(uuid, service_definitions)
|
13
13
|
@uuid = uuid
|
14
|
-
@service_definitions =
|
14
|
+
@service_definitions = service_definitions
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_ssdp_messages(uuid, messages)
|
18
|
+
service_definitions = messages.
|
15
19
|
# Filter out messages that aren't service definitions. These include
|
16
20
|
# the root device and the root UUID
|
17
21
|
reject { |message| not message[:st].include? ':service:' }.
|
@@ -26,18 +30,7 @@ module EasyUpnp
|
|
26
30
|
}
|
27
31
|
end
|
28
32
|
|
29
|
-
|
30
|
-
if @service_definitions.any?
|
31
|
-
service_location = @service_definitions.first[:location]
|
32
|
-
|
33
|
-
xml = Nokogiri::XML(open(service_location))
|
34
|
-
xml.remove_namespaces!
|
35
|
-
@name = xml.xpath('//device/friendlyName').text
|
36
|
-
@host = URI.parse(service_location).host
|
37
|
-
else
|
38
|
-
@name = 'UNKNOWN'
|
39
|
-
@host = 'UNKNOWN'
|
40
|
-
end
|
33
|
+
UpnpDevice.new(uuid, service_definitions)
|
41
34
|
end
|
42
35
|
|
43
36
|
def all_services
|
@@ -52,35 +45,7 @@ module EasyUpnp
|
|
52
45
|
definition = service_definition(urn)
|
53
46
|
|
54
47
|
if !definition.nil?
|
55
|
-
|
56
|
-
xml = Nokogiri::XML(open(root_uri))
|
57
|
-
xml.remove_namespaces!
|
58
|
-
|
59
|
-
service = xml.xpath("//device/serviceList/service[serviceType=\"#{urn}\"]").first
|
60
|
-
|
61
|
-
if service.nil?
|
62
|
-
raise RuntimeError.new "Couldn't find service with urn: #{urn}"
|
63
|
-
else
|
64
|
-
service = Nokogiri::XML(service.to_xml)
|
65
|
-
wsdl = URI.join(root_uri, service.xpath('service/SCPDURL').text).to_s
|
66
|
-
|
67
|
-
client = Savon.client do |c|
|
68
|
-
c.endpoint URI.join(root_uri, service.xpath('service/controlURL').text).to_s
|
69
|
-
|
70
|
-
c.namespace urn
|
71
|
-
|
72
|
-
# I found this was necessary on some of my UPnP devices (namely, a Sony TV).
|
73
|
-
c.namespaces({:'s:encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/"})
|
74
|
-
|
75
|
-
# This makes XML tags be like <ObjectID> instead of <objectID>.
|
76
|
-
c.convert_request_keys_to :camelcase
|
77
|
-
|
78
|
-
c.namespace_identifier :u
|
79
|
-
c.env_namespace :s
|
80
|
-
end
|
81
|
-
|
82
|
-
DeviceControlPoint.new client, urn, wsdl, options
|
83
|
-
end
|
48
|
+
DeviceControlPoint.from_service_definition(definition, options)
|
84
49
|
end
|
85
50
|
end
|
86
51
|
|
@@ -90,4 +55,4 @@ module EasyUpnp
|
|
90
55
|
first
|
91
56
|
end
|
92
57
|
end
|
93
|
-
end
|
58
|
+
end
|
data/lib/easy_upnp/version.rb
CHANGED
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easy_upnp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.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:
|
11
|
+
date: 2016-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
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
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: savon
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 2.11.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.11.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: nori
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 2.6.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 2.6.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: nokogiri
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 1.6.6.2
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.6.6.2
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 2.0.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 2.0.0
|
83
83
|
description:
|
@@ -86,7 +86,7 @@ executables: []
|
|
86
86
|
extensions: []
|
87
87
|
extra_rdoc_files: []
|
88
88
|
files:
|
89
|
-
- .gitignore
|
89
|
+
- ".gitignore"
|
90
90
|
- Gemfile
|
91
91
|
- LICENSE
|
92
92
|
- README.md
|
@@ -105,17 +105,17 @@ require_paths:
|
|
105
105
|
- lib
|
106
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
|
-
- -
|
113
|
+
- - ">="
|
114
114
|
- !ruby/object:Gem::Version
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
117
117
|
rubyforge_project:
|
118
|
-
rubygems_version: 2.
|
118
|
+
rubygems_version: 2.5.1
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: A super easy to use UPnP control point client
|