Class: SonyCameraRemoteAPI::CameraAPIManager

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Logging
Defined in:
lib/sony_camera_remote_api/camera_api.rb

Overview

Camera API layer class, which enables us to handle camera APIs more friendly.

Constant Summary collapse

DEFAULT_API_CALL_TIMEOUT =

Default timeout for waiting camera API becomes available

8
DEFAULT_PARAM_CHANGE_TIMEOUT =

Default timeout for waiting camera parameter changes

15

Instance Method Summary collapse

Methods included from Logging

configure_logger_for, #log, log_file, logger_for, #output_to

Constructor Details

#initialize(endpoints, reconnect_by: nil) ⇒ CameraAPIManager

Create CameraAPIManager object.

Parameters:

  • endpoints (Hash)
  • reconnect_by (Proc) (defaults to: nil)


27
28
29
30
31
# File 'lib/sony_camera_remote_api/camera_api.rb', line 27

def initialize(endpoints, reconnect_by: nil)
  @raw_api_manager = RawAPIManager.new endpoints
  @api_group_manager = CameraAPIGroupManager.new self
  @reconnect_by = reconnect_by
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, params = [], *args, **opts) ⇒ Object

Ghost method, which handles almost API calls. If Camera API (servie type == camera) is called, call_api_safe() is used.

Parameters:

  • method (String)
  • params (Array, String) (defaults to: [])
  • service_type (String)
  • id (Fixnum)
  • version (String)
  • timeout (Fixnum)

    Timeout in seconds for waiting until the API is available



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/sony_camera_remote_api/camera_api.rb', line 127

def method_missing(method, params = [], *args, **opts)
  ignore_error = true if method.to_s.end_with? '!'
  method = method.to_s.delete('!').to_sym
  params = [params] unless params.is_a? Array
  response = nil
  reconnect_and_retry do
    begin
      name, service, id, version = @raw_api_manager.search_method(method, **opts)
      if service == 'camera' || name == ''
        if opts[:timeout]
          response = call_api_safe(service, name, params, id, version, opts[:timeout], **opts)
        else
          response = call_api_safe(service, name, params, id, version, **opts)
        end
      else
        response = @raw_api_manager.call_api(service, name, params, id, version)
      end
    rescue APINotSupported, APINotAvailable, IllegalArgument, HTTPClient::BadResponseError => e
      if ignore_error
        return nil
      else
        raise e
      end
    end
  end
  response
end

Instance Method Details

#call_api_safe(service_type, method, params, id, version, timeout = DEFAULT_API_CALL_TIMEOUT, **args) ⇒ Object

Call camera APIs with checking if it is available by ‘getAvailableApiList’. If not available, wait a minute until the called API turns to be available.

Parameters:

  • service_type (String)
  • method (String)
  • params (Array, String)
  • id (Fixnum)
  • version (String)
  • timeout (Fixnum) (defaults to: DEFAULT_API_CALL_TIMEOUT)

    Timeout in seconds for waiting until the API is available



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/sony_camera_remote_api/camera_api.rb', line 42

def call_api_safe(service_type, method, params, id, version, timeout = DEFAULT_API_CALL_TIMEOUT, **args)
  unless getAvailableApiList['result'][0].include? method
    log.error "Method '#{method}' is not available now! waiting..."
    begin
      wait_event(timeout: timeout) { |res| res[0]['names'].include? method }
    rescue EventTimeoutError => e
      raise APINotAvailable.new, "Method '#{method}' is not available now!"
    end
    log.info "Method '#{method}' has become available."
  end
  @raw_api_manager.call_api(service_type, method, params, id, version)
end

#getAvailableApiList(params = [], **opts) ⇒ Hash

getAvailableApiList API.

Returns:

  • (Hash)

    Response of API



77
78
79
80
81
82
# File 'lib/sony_camera_remote_api/camera_api.rb', line 77

def getAvailableApiList(params = [], **opts)
  name, service, id, version = @raw_api_manager.search_method(__method__, **opts)
  reconnect_and_retry do
    @raw_api_manager.call_api(service, name, params, id, version)
  end
end

#getEvent(params = [true], **opts) ⇒ Hash

getEvent API. Long polling flag is set true as default.

Parameters:

  • params (Array, String) (defaults to: [true])

Returns:

  • (Hash)

    Response of API



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/sony_camera_remote_api/camera_api.rb', line 60

def getEvent(params = [true], **opts)
  params = [params] unless params.is_a? Array
  name, service, id, version = @raw_api_manager.search_method(__method__, **opts)
  response = nil
  reconnect_and_retry do
    if params[0]
      response = @raw_api_manager.call_api_async(service, name, params, id, version, opts[:timeout])
    else
      response = @raw_api_manager.call_api(service, name, params, id, version)
    end
  end
  response
end

#wait_event(timeout: DEFAULT_PARAM_CHANGE_TIMEOUT, polling: nil) {|Array<Hash>| ... } ⇒ Object

Wait until ‘getEvent’ result response meets the specified condition. This method can be used to wait after calling APIs that change any camera parameters, such as ‘setCameraFunction’.

Parameters:

  • timeout (Fixnum) (defaults to: DEFAULT_PARAM_CHANGE_TIMEOUT)

    Timeout in seconds for changing parameter

  • polling (Boolean) (defaults to: nil)

    This method has 3 patterns to handle long polling flag by ‘polling’ parameter.

    • default : The first getEvent call doesn’t use long polling, but then later always use long polling.

    • polling = true : Always use long polling in getEvent call

    • polling = false : Never use long polling in getEvent call

Yields:

  • (Array<Hash>)

    The block that returns true or false based on the condition of the response of getEvent

Yield Parameters:

  • 'result' (Array<Hash>)

    element in the response of getEvent

Raises:

  • EventTimeoutError



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/sony_camera_remote_api/camera_api.rb', line 95

def wait_event(timeout: DEFAULT_PARAM_CHANGE_TIMEOUT, polling: nil, &block)
  start_time = Time.now if timeout
  # Long-polling is disabled only at the first call
  poll = polling.nil? ? false : polling
  while true do
    response = get_event_both(poll, timeout: timeout)
    begin
      break if yield(response.result)
    rescue StandardError => e
      # Catch all exceptions raised by given block, e.g. NoMethodError of '[]' for nil class.
    end
    sleep 0.1
    if timeout
      raise EventTimeoutError, "Timeout expired: #{timeout} sec." if Time.now - start_time > timeout
    end
    poll = polling.nil? ? true : polling
    log.debug "Waiting for #{block} returns true..."
  end
  log.debug "OK. (#{format('%.2f', Time.now-start_time)} sec.)"
  # pp response['result']
  response['result']
end