Class: RUPNP::CP::RemoteService

Inherits:
Base
  • Object
show all
Defined in:
lib/rupnp/cp/remote_service.rb

Overview

Service class for device’s services.

Actions

This class defines ruby methods from actions defined in service description, as provided by the device.

By example, from this description:

<action>
  <name>actionName</name>
  <argumentList>
  <argument>
    <name>argumentNameIn</name>
    <direction>in</direction>
    <relatedStateVariable>stateVariableName</relatedStateVariable>
  </argument>
  <argument>
    <name>argumentNameOut</name>
    <direction>out</direction>
    <relatedStateVariable>stateVariableName</relatedStateVariable>
  </argument>
</action>

a #action_name method is created. This method requires a hash with an element named argument_name_in. If no in argument is required, an empty hash ({}) must be passed to the method.

A Hash is returned, with a key for each out argument.

Author:

  • Sylvain Daubert

Constant Summary collapse

INTEGER_TYPES =
%w(ui1 ui2 ui4 i1 i2 i4 int).freeze
FLOAT_TYPES =
%w(r4 r8 number float).freeze
STRING_TYPES =
%w(char string uuid).freeze
TRUE_TYPES =
%w(1 true yes).freeze
FALSE_TYPES =
%w(0 false no).freeze
@@event_sub_count =
0

Constants inherited from Base

Base::HTTP_COMMON_CONFIG

Constants included from LogMixin

LogMixin::LOG_LEVEL

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#get_description, #inspect

Methods included from LogMixin

#log

Methods included from Tools

#build_url, #snake_case, #urn_are_equivalent?, #usn2udn

Constructor Details

#initialize(device, url_base, service) ⇒ RemoteService

Returns a new instance of RemoteService.

Parameters:

  • device (Device)
  • url_base (String)
  • service (Hash)


93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rupnp/cp/remote_service.rb', line 93

def initialize(device, url_base, service)
  super()
  @device = device
  @description = service

  @type = service[:service_type].to_s
  @scpd_url = build_url(url_base,  service[:scpdurl].to_s)
  @control_url =  build_url(url_base, service[:control_url].to_s)
  @event_sub_url =  build_url(url_base, service[:event_sub_url].to_s)
  @actions = []

  initialize_savon
end

Instance Attribute Details

#actionsArray<Hash> (readonly)

Available actions on this service

Returns:

  • (Array<Hash>)


85
86
87
# File 'lib/rupnp/cp/remote_service.rb', line 85

def actions
  @actions
end

#control_urlString (readonly)

URL for control

Returns:

  • (String)


72
73
74
# File 'lib/rupnp/cp/remote_service.rb', line 72

def control_url
  @control_url
end

#deviceDevice (readonly)

Get device to which this service belongs to

Returns:

  • (Device)


62
63
64
# File 'lib/rupnp/cp/remote_service.rb', line 62

def device
  @device
end

#event_sub_urlString (readonly)

URL for eventing

Returns:

  • (String)


75
76
77
# File 'lib/rupnp/cp/remote_service.rb', line 75

def event_sub_url
  @event_sub_url
end

#scpd_urlString (readonly)

URL for service description

Returns:

  • (String)


69
70
71
# File 'lib/rupnp/cp/remote_service.rb', line 69

def scpd_url
  @scpd_url
end

#spec_versionString (readonly)

Define architecture on which the service is implemented

Returns:

  • (String)


82
83
84
# File 'lib/rupnp/cp/remote_service.rb', line 82

def spec_version
  @spec_version
end

#state_tableArray<Hash> (readonly)

State table for the service

Returns:

  • (Array<Hash>)


88
89
90
# File 'lib/rupnp/cp/remote_service.rb', line 88

def state_table
  @state_table
end

#typeString (readonly)

Get service type

Returns:

  • (String)


66
67
68
# File 'lib/rupnp/cp/remote_service.rb', line 66

def type
  @type
end

#xmlnsString (readonly)

XML namespace for device description

Returns:

  • (String)


79
80
81
# File 'lib/rupnp/cp/remote_service.rb', line 79

def xmlns
  @xmlns
end

Class Method Details

.event_sub_countInteger

Get event subscription count for all services (unique ID for subscription)

Returns:

  • (Integer)


44
45
46
# File 'lib/rupnp/cp/remote_service.rb', line 44

def self.event_sub_count
  @@event_sub_count += 1
end

Instance Method Details

#fetchvoid

This method returns an undefined value.

Get service from its description



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rupnp/cp/remote_service.rb', line 109

def fetch
  if @scpd_url.empty?
    fail 'no SCPD URL'
    return
  end

  scpd_getter = EM::DefaultDeferrable.new

  scpd_getter.errback do
    fail "cannot get SCPD from #@scpd_url"
  end

  scpd_getter.callback do |scpd|
    if !scpd or scpd.empty?
      fail "SCPD from #@scpd_url is empty"
      next
    end

    if bad_description?(scpd)
      fail 'not a UPNP 1.0/1.1 SCPD'
      next
    end

    extract_service_state_table scpd
    extract_actions scpd

    succeed self
  end

  get_description @scpd_url, scpd_getter
end

#subscribe_to_event(options = {}) {|event| ... } ⇒ Object

Subscribe to event

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • timeout (Integer)

Yield Parameters:

  • event (Event)

    event received



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/rupnp/cp/remote_service.rb', line 145

def subscribe_to_event(options={}, &blk)
  cp = device.control_point

  cp.start_event_server

  port = cp.event_port
  num = self.class.event_sub_count
  @callback_url = "http://#{HOST_IP}:#{port}/event#{num}}"

  uri = URI(@event_sub_url)
  options[:timeout] ||= EVENT_SUB_DEFAULT_TIMEOUT
  subscribe_req = <<EOR
SUSCRIBE #{uri.path} HTTP/1.1\r
HOST: #{HOST_IP}:#{port}\r
USER-AGENT: #{RUPNP::USER_AGENT}\r
CALLBACK: #@callback_url\r
NT: upnp:event
TIMEOUT: Second-#{options[:timeout]}\r
\r
EOR

  server = uri.host
  port = (uri.port || 80).to_i
  ap @event_sub_url
  ap server
  ap port
  con = EM.connect(server, port, CP::EventSubscriber, subscribe_req)

  con.response.subscribe do |resp|
    if resp[:status_code] != 200
      log :warn, "Cannot subscribe to event #@event_sub_url: #{resp[:status]}"
    else
      event = Event.new(resp[:sid], resp[:timeout].match(/(\d+)/)[1].to_i)
      cp.add_event_url << ["/event#{num}", event]
      event.subscribe(event, blk)
    end
    log :info, 'Close connection to subscribe event URL'
    con.close_connection
  end
end