<commit_before>module Larynx
  class CallHandler < EventMachine::Protocols::HeaderAndContentProtocol
    include Observable
    include Commands

    attr_reader :state, :session, :response, :input, :observers, :last_command

    # EM hook which is run when call is received
    def post_init
      @queue, @input, @timers = [], [], {}
      connect {
        @session = Session.new(@response.header)
        log "Call received from #{caller_id}"
        Larynx.fire_callback(:connect, self)
        start_session
      }
      send_next_command
    end

    def start_session
      myevents {
				linger
				answer {
					log 'Answered call'
					Larynx.fire_callback(:answer, self)
				}
      }
    end

    def called_number
      @session[:caller_destination_number]
    end

    def caller_id
      @session[:caller_caller_id_number]
    end

    def clear_input
      @input = []
    end

    def current_command
      @queue.first
    end

    def next_command
      @queue[1]
    end

    def execute(command, immediately=false)
      log "Queued: #{command.name}"
      if immediately
        @queue.unshift command
        send_next_command
      else
        @queue << command
      end
      command
    end

    def timer(name, timeout, &block)
      @timers[name] = [RestartableTimer.new(timeout) {
        timer = @timers.delete(name)
        timer[1].call if timer[1]
        notify_observers :timed_out
        send_next_command if @state == :ready
      }, block]
    end

    def cancel_timer(name)
      if timer = @timers.delete(name)
        timer[0].cancel
        send_next_command if @state == :ready
      end
    end

    def cancel_all_timers
      @timers.values.each {|t| t[0].cancel }
    end

    def stop_timer(name)
      if timer = @timers.delete(name)
        timer[0].cancel
        timer[1].call if timer[1]
        send_next_command if @state == :ready
      end
    end

    def restart_timer(name)
      if timer = @timers[name]
        timer[0].restart
      end
    end

    def cleanup
      break! if @state == :executing
      cancel_all_timers
      clear_observers!
    end

    def receive_request(header, content)
      @response = Response.new(header, content)

      case
      when @response.reply? && !current_command.is_a?(AppCommand)
        log "Completed: #{current_command.name}"
        finalize_command
        @state = :ready
        send_next_command
      when @response.executing?
        log "Executing: #{current_command.name}"
        run_command_setup
        @state = :executing
      when @response.executed?<commit_msg>extra careful timer handling to avoid race conditions<commit_after>module Larynx
  class CallHandler < EventMachine::Protocols::HeaderAndContentProtocol
    include Observable
    include Commands

    attr_reader :state, :session, :response, :input, :observers, :last_command

    # EM hook which is run when call is received
    def post_init
      @queue, @input, @timers = [], [], {}
      connect {
        @session = Session.new(@response.header)
        log "Call received from #{caller_id}"
        Larynx.fire_callback(:connect, self)
        start_session
      }
      send_next_command
    end

    def start_session
      myevents {
				linger
				answer {
					log 'Answered call'
					Larynx.fire_callback(:answer, self)
				}
      }
    end

    def called_number
      @session[:caller_destination_number]
    end

    def caller_id
      @session[:caller_caller_id_number]
    end

    def clear_input
      @input = []
    end

    def current_command
      @queue.first
    end

    def next_command
      @queue[1]
    end

    def execute(command, immediately=false)
      log "Queued: #{command.name}"
      if immediately
        @queue.unshift command
        send_next_command
      else
        @queue << command
      end
      command
    end

    def timer(name, timeout, &block)
      @timers[name] = [RestartableTimer.new(timeout) {
        timer = @timers[name]
        timer[1].call if timer[1]
        @timers.delete(name)
        notify_observers :timed_out
        send_next_command if @state == :ready
      }, block]
    end

    def cancel_timer(name)
      if timer = @timers[name]
        timer[0].cancel
        @timers.delete(name)
        send_next_command if @state == :ready
      end
    end

    def cancel_all_timers
      @timers.values.each {|t| t[0].cancel }
    end

    def stop_timer(name)
      if timer = @timers[name]
        # only run callback if it was actually cancelled (i.e. returns false)
        if timer[0].cancel == false && timer[1]
          timer[1].call
        end
        @timers.delete(name)
        send_next_command if @state == :ready
      end
    end

    def restart_timer(name)
      if timer = @timers[name]
        timer[0].restart
      end
    end

    def cleanup
      break! if @state == :executing
      cancel_all_timers
      clear_observers!
    end

    def receive_request(header, content)
      @response = Response.new(header, content)

      case
      when @response.reply? && !current_command.is_a?(AppCommand)
        log "Completed: #{current_command.name}"
        finalize_command
        @state = :ready
        send_next_command
      when @response.executing?
        log "Executing: #{current_command.name}"
        run_command_setup
        @state = :executing
      when @response.executed?
{'fraction_non_alphanumeric': 0.08935854653318502, 'fraction_numerical': 0.0033370411568409346, 'mean_word_length': 2.201780415430267, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3596025', 'n_tokens_mistral': 1687, 'n_tokens_neox': 1618, 'n_words': 396}