class Hive::Worker::Tv

The TV worker

Public Class Methods

new(config) click to toggle source
Calls superclass method
# File lib/hive/worker/tv.rb, line 13
def initialize(config)
  @brand = config['brand'].downcase.gsub(/\s/, '_')
  @model = config['model'].downcase.gsub(/\s/, '_')

  if config['ir_blaster_clients'] and config['ir_blaster_clients'].has_key?(config['id'])
    require 'device_api/tv'
    DeviceAPI::RatBlaster.configure do |rb_config|
      rb_config.host = Hive.config.network.tv.ir_blaster_host if Hive.config.network.tv.ir_blaster_host?
      rb_config.port = Hive.config.network.tv.ir_blaster_port if Hive.config.network.tv.ir_blaster_port?
    end

    config.merge!({"device_api" => DeviceAPI::TV::Device.new(
      id: config['id'],
      ir: {
        type: config['ir_blaster_clients'][config['id']].type,
        mac: config['ir_blaster_clients'][config['id']].mac,
        dataset: config['ir_blaster_clients'][config['id']].dataset,
        output: config['ir_blaster_clients'][config['id']].output
      }
    )})
    config['ir_blaster_clients'][config['id']].sequences.each do |name, pattern|
      config['device_api'].set_sequence(name.to_sym, pattern)
    end
  end
  super(config)
end

Public Instance Methods

autogenerated_queues() click to toggle source
# File lib/hive/worker/tv.rb, line 141
def autogenerated_queues
  [ "#{@brand}-#{@model}" ]
end
device_status() click to toggle source
# File lib/hive/worker/tv.rb, line 131
def device_status
  @hive_mind.device_details['status']
end
diagnostics() click to toggle source

Between tests the TV must be in the holding app

Calls superclass method
# File lib/hive/worker/tv.rb, line 186
def diagnostics
  app_name = @hive_mind.device_details(refresh: true)['application']
  raise DeviceNotReady.new("Current application: '#{app_name}'") if app_name != Hive.config.network.tv.titantv_name
  super
end
forced_redirect(opts) click to toggle source
# File lib/hive/worker/tv.rb, line 226
def forced_redirect(opts)
end
job_message_klass() click to toggle source
# File lib/hive/worker/tv.rb, line 109
def job_message_klass
  Hive::Messages::TvJob
end
load_hive_mind(ts_port, app_name) click to toggle source
# File lib/hive/worker/tv.rb, line 192
      def load_hive_mind ts_port, app_name
        ts = Talkshow.new
        @log.info("Port: #{ts_port}")
        @log.info("App: #{app_name}")
        @log.info("Logfile: #{@file_system.results_path}/talkshowserver.log")
        @log.info("titantv_url: #{Hive.config.network.tv.titantv_url}")
        ts.start_server(port: ts_port, logfile: "#{@file_system.results_path}/talkshowserver.log")
        5.times do
          begin
            ts.execute <<JS
(function(){
  var load_script = document.createElement('script');
  load_script.type = 'text/javascript';
  load_script.charset = 'utf-8';
  load_script.src = '#{Hive.config.network.tv.titantv_url}/script/hive_mind_com.js';
  document.getElementsByTagName('head')[0].appendChild(load_script);
  // Give it 10 seconds to load
  // TODO Do this with a retry
  setTimeout(function() {
    hive_mind_com.init('#{app_name}', '#{Hive.config.network.tv.titantv_url}');
    hive_mind_com.start();
  }, 10000);
  return true;
})()
JS
            break
          rescue Talkshow::Timeout
            @log.info("Talkshow timeout")
            sleep 1
          end
        end
        ts.stop_server
      end
mind_meld_klass() click to toggle source
# File lib/hive/worker/tv.rb, line 113
def mind_meld_klass
  MindMeld::Tv
end
post_script(job, job_paths, script) click to toggle source
# File lib/hive/worker/tv.rb, line 117
def post_script(job, job_paths, script)
  @port_allocator.release_port(@ts_port) if @ts_port

  signal_safe_post_script(job, job_paths, script)
end
pre_script(job, job_paths, script) click to toggle source

Prepare the TV

# File lib/hive/worker/tv.rb, line 41
      def pre_script(job, job_paths, script)
        url = job.application_url
        @log.info("Application url: #{url}")
        # TODO Set device as busy in Hive mind

        params = ""

        # 'cross_network_restriction' means that the device requires Talkshow
        # on the same network as the application.
        # For the moment, assume networks are '10.10.*.*' and'*.bbc.co.uk'
        # TODO Make this more general
        if @options['features'] && @options['features'].include?('cross_network_restriction') and /bbc.co.uk/.match url
          ts_address = Hive.config.network.remote_talkshow_address
          ts_port = @ts_port = Hive.config.network.remote_talkshow_port_offset + @options['id']
          @log.info("Using remote talkshow on port #{ts_port}")
          script.set_env 'TALKSHOW_REMOTE_URL', "http://#{ts_address}:#{ts_port}"
          # Not actually required but talkshow fails without it set
          script.set_env 'TALKSHOW_PORT', ts_port
        else
          ts_port = @ts_port = @port_allocator.allocate_port
          @log.info("Using talkshow on port #{ts_port}")
          # TODO Move this more centrally
          ip = Socket.ip_address_list.detect { |intf| intf.ipv4_private? }
          ts_address = ip.ip_address
          script.set_env 'TALKSHOW_PORT', ts_port
        end
        @log.info("Talkshow server address is: #{ts_address}")

        if job.application_url_parameters.present?
          params = "?#{job.application_url_parameters}&talkshowurl=#{ts_address}:#{ts_port}"
        else
          params = "?talkshowurl=#{ts_address}:#{ts_port}"
        end
        url += params

        self.redirect(
          url: url,
          old_app: Hive.config.network.tv.titantv_name,
          skip_first_load: true
        )
        load_hive_mind ts_port, url

        @log.info("Starting TV Application monitor")
        @monitor = Thread.new do
          loop do
            poll_response = Hive.hive_mind.poll(@device_id)
#            if poll_response.is_a? Array and poll_response.length > 0
#              @log.debug("[TV app monitor] Polled TV. Application = #{poll_response.first['application']}")
#        #    if @hive_mind.device_details(refresh: true)['application'] == Hive.config.network.tv.titantv_name
#              if poll_response.first['application'] == Hive.config.network.tv.titantv_name
#                # TV has returned to the holding app
#                # Put back in the app under test
#                self.redirect(
#                  url: url,
#                  old_app: Hive.config.network.tv.titantv_name,
#                  log_prefix: '[TV app monitor] '
#                )
#              end
#            else
#              @log.warn("[TV app monitor] Failed to poll TV")
#            end
            sleep 20
          end
        end

        return nil
      end
redirect(opts) click to toggle source
# File lib/hive/worker/tv.rb, line 145
def redirect(opts)
  raise ArgumentError if ! ( opts.has_key?(:url) && ( opts.has_key?(:old_app) || opts.has_key?(:new_app) ) )
  load_hive_mind(@ts_port, opts[:old_app] || "Trying to redirect ...") if ! opts[:skip_first_load]
  opts[:log_prefix] ||= ''
  @log.info("#{opts[:log_prefix]}Redirecting to #{opts[:url]}")
  @hive_mind.create_action(action_type: 'redirect', body: opts[:url])
  sleep 5
  load_hive_mind(@ts_port, opts[:url]) if ! opts[:skip_last_load]

  max_wait_count = 10
  wait_count = 0
  max_retry_count = 15
  retry_count = 0

  forced_redirect(opts)

  app_name = @hive_mind.device_details(refresh: true)['application']
  @log.debug("#{opts[:log_prefix]}Current app: #{app_name}")
  while (opts.has_key?(:new_app) && app_name != opts[:new_app]) || (opts.has_key?(:old_app) && app_name == opts[:old_app])
    if wait_count >= max_wait_count
      if retry_count >= max_retry_count
        raise FailedRedirect
      else
        retry_count += 1
        wait_count = 0
        @log.info("#{opts[:log_prefix]}Redirecting to #{opts[:url]} [#{retry_count}]")
        @hive_mind.create_action(action_type: 'redirect', body: opts[:url])
        sleep 2
      end
    else
      wait_count += 1
      @log.info("#{opts[:log_prefix]}  . [#{wait_count}]")
      load_hive_mind(@ts_port, opts[:url]) if ! opts[:skip_last_load]
      sleep 1
    end
    app_name = @hive_mind.device_details(refresh: true)['application']
    @log.debug("#{opts[:log_prefix]}Current app: #{app_name}")
  end
end
set_device_status(status) click to toggle source
# File lib/hive/worker/tv.rb, line 135
def set_device_status(status)
  # TODO Set status from Hive Mind
  # At the moment the device state cannot be changed
  device_status
end
signal_safe_post_script(job, job_paths, script) click to toggle source
# File lib/hive/worker/tv.rb, line 123
def signal_safe_post_script(job, job_paths, script)
  @log.info('Terminating TV Application monitor')
  @monitor.exit if @monitor

  self.redirect(url: Hive.config.network.tv.titantv_url, new_app: Hive.config.network.tv.titantv_name, skip_last_load: true)
  # TODO Set device as idle in Hive Mind
end