amatriain/openreader

View on GitHub
FeedBunch-app/app/assets/javascripts/ng-services/ng-JobStateSvc.js.coffee.erb

Summary

Maintainability
Test Coverage
########################################################
# AngularJS service to load the state of background jobs requested by the user
########################################################

angular.module('feedbunch').service 'jobStateSvc',
['$rootScope', '$timeout', '$window', 'csrfTokenSvc', 'loadFeedsSvc', 'timerFlagSvc', 'findSvc', 'favicoSvc', 'userDataSvc',
($rootScope, $timeout, $window, csrfTokenSvc, loadFeedsSvc, timerFlagSvc, findSvc, favicoSvc, userDataSvc)->

  # Constants for the different operations the web worker can perform
  LOAD_ALL_SUBSCRIBE_JOB_STATES = 'load_all_subscribe_job_states'
  LOAD_SINGLE_SUBSCRIBE_JOB_STATE = 'load_single_subscribe_job_state'
  DELETE_SUBSCRIBE_JOB_STATE = 'delete_subscribe_job_state'
  LOAD_ALL_REFRESH_JOB_STATES = 'load_all_refresh_job_states'
  LOAD_SINGLE_REFRESH_JOB_STATE = 'load_single_refresh_job_state'
  DELETE_REFRESH_JOB_STATE = 'delete_refresh_job_state'

  # CSRF token
  token = csrfTokenSvc.get_token()

  # Web worker to load or delete the state of  jobs
  worker = new Worker '<%= asset_path 'workers/job_state_worker' %>'
  worker.onmessage = (e) ->
    if e.data.status == 200 || e.data.status == 304
      if e.data.operation == LOAD_ALL_SUBSCRIBE_JOB_STATES
        all_subscribe_job_states_loaded e.data.response
      else if e.data.operation == LOAD_SINGLE_SUBSCRIBE_JOB_STATE
        single_subscribe_job_state_loaded e.data.response
      else if e.data.operation == LOAD_ALL_REFRESH_JOB_STATES
        all_refresh_job_states_loaded e.data.response
      else if e.data.operation == LOAD_SINGLE_REFRESH_JOB_STATE
        single_refresh_job_state_loaded e.data.response
    else if e.data.status == 401 || e.data.status == 422
      $window.location.href = '/login'
    else if e.data.status == 404
      if e.data.operation == LOAD_ALL_SUBSCRIBE_JOB_STATES
        $rootScope.subscribe_job_states = []
      else if e.data.operation == LOAD_ALL_REFRESH_JOB_STATES
        $rootScope.refresh_feed_job_states = []
    else
      if e.data.operation == LOAD_ALL_SUBSCRIBE_JOB_STATES || e.data.operation == LOAD_ALL_REFRESH_JOB_STATES || e.data.operation == LOAD_SINGLE_REFRESH_JOB_STATE
        timerFlagSvc.start 'error_loading_job_states'
      else if e.data.operation == LOAD_SINGLE_SUBSCRIBE_JOB_STATE
        timerFlagSvc.start 'error_subscribing'
    $rootScope.$digest()

  #---------------------------------------------
  # PRIVATE FUNCTION: Operations after all subscribe job states have been loaded
  #---------------------------------------------
  all_subscribe_job_states_loaded = (response)->
    $rootScope.subscribe_job_states = response.slice()
    for job_state in response
      # Periodically update the state of any running jobs
      load_subscribe_job_state job_state.id if job_state.state=="RUNNING"

  #---------------------------------------------
  # PRIVATE FUNCTION: Operations after a single subscribe job state has been loaded
  #---------------------------------------------
  single_subscribe_job_state_loaded = (response)->
    job = findSvc.find_subscribe_job response.id
    if job?
      job.state = response.state
      if job.state=="RUNNING"
        # If job is running, keep periodically updating its state
        load_subscribe_job_state job.id
      else if job.state=="ERROR"
        timerFlagSvc.start 'error_subscribing'
      else if job.state=="SUCCESS"
        timerFlagSvc.start 'success_subscribe'
        job.feed_id = response.feed_id
        # Update the total subscribed feeds count
        userDataSvc.load_data()

  #---------------------------------------------
  # PRIVATE FUNCTION: Operations after all refresh job states have been loaded
  #---------------------------------------------
  all_refresh_job_states_loaded = (response)->
    $rootScope.refresh_feed_job_states = response.slice()
    for job_state in response
      # Periodically update the state of any running jobs
      load_refresh_feed_job_state job_state.id if job_state.state=="RUNNING"

  #---------------------------------------------
  # PRIVATE FUNCTION: Operations after a single refresh job state has been loaded
  #---------------------------------------------
  single_refresh_job_state_loaded = (response)->
    job = findSvc.find_refresh_feed_job response.id
    if job?
      job.state = response.state
      if job.state=="RUNNING"
        # If job is running, keep periodically updating its state
        load_refresh_feed_job_state job.id
      else if job.state=="ERROR"
        timerFlagSvc.start 'error_refreshing_feed'
      else if job.state=="SUCCESS"
        timerFlagSvc.start 'success_refresh_feed'
        loadFeedsSvc.load_feed job.feed_id

  #---------------------------------------------
  # PRIVATE FUNCTION: load state of a single refresh feed job via AJAX.
  #
  # Receives as argument the id of the job.
  #---------------------------------------------
  load_refresh_feed_job_state = (job_id)->
    # Store running timers in a hash in the root scope
    $rootScope.refresh_job_state_timers ||= {}

    # Only start a timer to refresh the job state if there isn't a timer already refreshing that job state
    timer = $rootScope.refresh_job_state_timers[job_id]
    if !timer?
      timer = $timeout ->
        # Remove this timer from the list so that another update can be scheduled for 5 seconds in the future
        delete $rootScope.refresh_job_state_timers[job_id]
        worker.postMessage {operation: LOAD_SINGLE_REFRESH_JOB_STATE, token: token, id: job_id}
      , 5000
      # Store timer so that a second timer for the same job state is not started in the future
      $rootScope.refresh_job_state_timers[job_id] = timer

  #---------------------------------------------
  # PRIVATE FUNCTION: load state of a single subscribe job via AJAX.
  #
  # Receives as argument the id of the job.
  #---------------------------------------------
  load_subscribe_job_state = (job_id)->
    # Store running timers in a hash in the root scope
    $rootScope.subscribe_job_state_timers ||= {}

    # Only start a timer to refresh the job state if there isn't a timer already refreshing that job state
    timer = $rootScope.subscribe_job_state_timers[job_id]
    if !timer?
      timer = $timeout ->
        # Remove this timer from the list so that another update can be scheduled for 5 seconds in the future
        delete $rootScope.subscribe_job_state_timers[job_id]
        worker.postMessage {operation: LOAD_SINGLE_SUBSCRIBE_JOB_STATE, token: token, id: job_id}
      , 5000
      # Store timer so that a second timer for the same job state is not started in the future
      $rootScope.subscribe_job_state_timers[job_id] = timer

  service =

    #---------------------------------------------
    # Load job states via AJAX into the root scope
    #---------------------------------------------
    load_data: ->
      worker.postMessage {operation: LOAD_ALL_SUBSCRIBE_JOB_STATES, token: token}
      worker.postMessage {operation: LOAD_ALL_REFRESH_JOB_STATES, token: token}

    #---------------------------------------------
    # Hide a refresh feed job state alert and notify the server via AJAX that it should be deleted
    # from the database (it will not appear again).
    #---------------------------------------------
    hide_refresh_job_alert: (job_state)->
      # Remove job state from scope
      job_state = findSvc.find_refresh_feed_job job_state.id
      if job_state?
        index = $rootScope.refresh_feed_job_states.indexOf job_state
        $rootScope.refresh_feed_job_states.splice index, 1 if index != -1

      # If there is a timer updating this job state, stop it.
      if $rootScope.refresh_job_state_timers?
        timer = $rootScope.refresh_job_state_timers[job_state.id]
        if timer?
          $timeout.cancel timer
          delete $rootScope.refresh_job_state_timers[job_state.id]

      worker.postMessage {operation: DELETE_REFRESH_JOB_STATE, token: token, id: job_state.id}

    #---------------------------------------------
    # Hide a subscribe job state alert and notify the server via AJAX that it should be deleted
    # from the database (it will not appear again).
    #---------------------------------------------
    hide_subscribe_job_alert: (job_state)->
      # Remove job state from scope
      job_state = findSvc.find_subscribe_job job_state.id
      if job_state?
        index = $rootScope.subscribe_job_states.indexOf job_state
        $rootScope.subscribe_job_states.splice index, 1 if index != -1

      # If there is a timer updating this job state, stop it.
      if $rootScope.subscribe_job_state_timers?
        timer = $rootScope.subscribe_job_state_timers[job_state.id]
        if timer?
          $timeout.cancel timer
          delete $rootScope.subscribe_job_state_timers[job_state.id]

      worker.postMessage {operation: DELETE_SUBSCRIBE_JOB_STATE, token: token, id: job_state.id}

  return service
]