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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 017b7021b1d9c35fab09ff9f670a660c96758443
4
- data.tar.gz: 793f938414da9e550a12b94aa90a05ba0de81480
3
+ metadata.gz: ff03da48709a543a35dbfe13a1ece864d9337db6
4
+ data.tar.gz: 61517d04933afc34e2465de2400c577d001b63fb
5
5
  SHA512:
6
- metadata.gz: 71e31a046b94b3e99cb6f79d87da6f2ee92fd06f209960ae67d0cb7457864bac839dfda9312ce8205b5fb4d8ac57d6c81f6673643343c6f84f044ff15b4e45ac
7
- data.tar.gz: 689804ce65c657638e8098403d7ea33571b0b6ca69bfc2cc16f63488fcc9d74b3639eb03d0da63facf86a1fc11bdfbf8f05871123e81ce048091f970a4ae561b
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(client, service_type, definition_url, options)
10
- @client = client
11
- @service_type = service_type
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
- service_methods = []
15
- definition = Nokogiri::XML(open(definition_url))
16
- definition.remove_namespaces!
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.xpath('//actionList/action').map do |action|
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: "#{@service_type}##{action_name}",
108
+ soap_action: "#{@urn}##{action_name}",
51
109
  attributes: {
52
- :'xmlns:u' => @service_type
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.new k, v
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 uuid, messages
12
+ def initialize(uuid, service_definitions)
13
13
  @uuid = uuid
14
- @service_definitions = messages.
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
- # Download one of the definitions to get the name of this device
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
- root_uri = definition[:location]
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
@@ -1,3 +1,3 @@
1
1
  module EasyUpnp
2
- VERSION = '0.1.8'
2
+ VERSION = '0.2.1'
3
3
  end
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.8
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: 2015-10-11 00:00:00.000000000 Z
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.4.8
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