<commit_before># encoding: utf-8

require 'has_guarded_handlers'
require 'thread'
require 'active_support/hash_with_indifferent_access'

module Adhearsion
  ##
  # Encapsulates call-related data and behavior.
  #
  class Call

    Hangup          = Class.new Adhearsion::Error
    CommandTimeout  = Class.new Adhearsion::Error
    ExpiredError    = Class.new Celluloid::DeadActorError

    include Celluloid
    include HasGuardedHandlers

    execute_block_on_receiver :register_handler, :register_tmp_handler, :register_handler_with_priority, :register_event_handler, :on_joined, :on_unjoined, :on_end, :execute_controller
    finalizer :finalize

    def self.new(*args, &block)
      super.tap do |proxy|
        def proxy.method_missing(*args)
          super
        rescue Celluloid::DeadActorError
          raise ExpiredError, "This call is expired and is no longer accessible"
        end
      end
    end

    attr_reader :end_reason, :commands, :controllers, :variables

    delegate :[], :[]=, :to => :variables
    delegate :to, :from, :to => :offer, :allow_nil => true

    def initialize(offer = nil)
      register_initial_handlers

      @offer        = nil
      @tags         = []
      @commands     = CommandRegistry.new
      @variables    = HashWithIndifferentAccess.new
      @controllers  = []
      @end_reason   = nil
      @end_blocker  = Celluloid::Condition.new
      @peers        = {}

      self << offer if offer
    end

    #
    # @return [String, nil] The globally unique ID for the call
    #
    def id
      offer.target_call_id if offer
    end

    #
    # @return [Array] The set of labels with which this call has been tagged.
    #
    def tags
      @tags.clone
    end

    #
    # Tag a call with an arbitrary label
    #
    # @param [String, Symbol] label String or Symbol with which to tag this call
    #
    def tag(label)
      abort ArgumentError.new "Tag must be a String or Symbol" unless [String, Symbol].include?(label.class)
      @tags << label
    end

    #
    # Remove a label
    #
    # @param [String, Symbol] label
    #
    def remove_tag(label)
      @tags.reject! { |tag| tag == label }
    end

    #
    # Establish if the call is tagged with the provided label
    #
    # @param [String, Symbol] label
    #
    def tagged_with?(label)
      @tags.include? label
    end

    #
    # Hash of joined peers
    # @return [Hash<String => Adhearsion::Call>]
    #
    def peers
      @peers.clone
    end

    #
    # Wait for the call to end. Returns immediately if the call has already ended, else blocks until it does so.
    # @return [Symbol] the reason for the call ending
    #
    def wait_for_end
      if end_reason
        end_reason
      else
        @end_blocker.wait
      end
    end

    def register_event_handler(*guards, &block)
      register_handler :event, *guards, &block
    end

    def deliver_message(message)
      logger.debug "Receiving message: #{message.inspect}"
      catching_standard_errors { trigger_handler :event, message }
    end
    alias << deliver_message

    # @private
    def register_initial_handlers
      register_event_handler Punchblock::Event::Offer do |offer|
        @offer  = offer
        @client = offer.client
        throw :pass
      end

      register_event_handler Punchblock::HasHeaders do |event|
        merge_headers event.headers
        throw :pass
      end

      on_joined do |event|
        target = event.call_uri || event.mixer_name
        @peers[target] = Adhearsion.active_calls[target]
        signal :joined, target
      end

      on_unjoined do |event|
        target = event.call_uri || event.mixer_name
        @peers.delete target
        signal :unjoined, target
      end

      on_end do |event|
        logger.info "Call ended"
        clear_from_active_calls
        @end_reason = event.reason
        @end_blocker.signal event.reason
        commands.terminate
        after(Adhearsion.config.platform.after_hangup_lifetime) { terminate }
        throw :pass
      end
    end

    ##
    # Registers a callback for when this call is joined to another call or a mixer
    #
    # @param [Call, String, Hash, nil] target the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
    # @option target [String] call_id The call ID to guard on
    # @option target [String] mixer_name The mixer name to guard on
    #
    def on_joined(target = nil, &block)
      register_event_handler Punchblock::Event::Joined, *guards_for_target(target) do |event|
        block.call event
        throw :pass
      end
    end

    ##
    # Registers a callback for when this call is unjoined from another call or a mixer
    #
    # @param [Call, String, Hash, nil] target the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
    # @option target [String] call_id The call ID to guard on
    # @option target [String] mixer_name The mixer name to guard on
    #
    def on_unjoined(target = nil, &block)
      register_event_handler Punchblock::Event::Unjoined, *guards_for_target(target) do |event|
        block.call event<commit_msg>[CS] Avoid 'spuriously' signaling a condition<commit_after># encoding: utf-8

require 'has_guarded_handlers'
require 'thread'
require 'active_support/hash_with_indifferent_access'

module Adhearsion
  ##
  # Encapsulates call-related data and behavior.
  #
  class Call

    Hangup          = Class.new Adhearsion::Error
    CommandTimeout  = Class.new Adhearsion::Error
    ExpiredError    = Class.new Celluloid::DeadActorError

    include Celluloid
    include HasGuardedHandlers

    execute_block_on_receiver :register_handler, :register_tmp_handler, :register_handler_with_priority, :register_event_handler, :on_joined, :on_unjoined, :on_end, :execute_controller
    finalizer :finalize

    def self.new(*args, &block)
      super.tap do |proxy|
        def proxy.method_missing(*args)
          super
        rescue Celluloid::DeadActorError
          raise ExpiredError, "This call is expired and is no longer accessible"
        end
      end
    end

    attr_reader :end_reason, :commands, :controllers, :variables

    delegate :[], :[]=, :to => :variables
    delegate :to, :from, :to => :offer, :allow_nil => true

    def initialize(offer = nil)
      register_initial_handlers

      @offer        = nil
      @tags         = []
      @commands     = CommandRegistry.new
      @variables    = HashWithIndifferentAccess.new
      @controllers  = []
      @end_reason   = nil
      @end_blocker  = Celluloid::Condition.new
      @peers        = {}

      self << offer if offer
    end

    #
    # @return [String, nil] The globally unique ID for the call
    #
    def id
      offer.target_call_id if offer
    end

    #
    # @return [Array] The set of labels with which this call has been tagged.
    #
    def tags
      @tags.clone
    end

    #
    # Tag a call with an arbitrary label
    #
    # @param [String, Symbol] label String or Symbol with which to tag this call
    #
    def tag(label)
      abort ArgumentError.new "Tag must be a String or Symbol" unless [String, Symbol].include?(label.class)
      @tags << label
    end

    #
    # Remove a label
    #
    # @param [String, Symbol] label
    #
    def remove_tag(label)
      @tags.reject! { |tag| tag == label }
    end

    #
    # Establish if the call is tagged with the provided label
    #
    # @param [String, Symbol] label
    #
    def tagged_with?(label)
      @tags.include? label
    end

    #
    # Hash of joined peers
    # @return [Hash<String => Adhearsion::Call>]
    #
    def peers
      @peers.clone
    end

    #
    # Wait for the call to end. Returns immediately if the call has already ended, else blocks until it does so.
    # @return [Symbol] the reason for the call ending
    #
    def wait_for_end
      if end_reason
        end_reason
      else
        @end_blocker.wait
      end
    end

    def register_event_handler(*guards, &block)
      register_handler :event, *guards, &block
    end

    def deliver_message(message)
      logger.debug "Receiving message: #{message.inspect}"
      catching_standard_errors { trigger_handler :event, message }
    end
    alias << deliver_message

    # @private
    def register_initial_handlers
      register_event_handler Punchblock::Event::Offer do |offer|
        @offer  = offer
        @client = offer.client
        throw :pass
      end

      register_event_handler Punchblock::HasHeaders do |event|
        merge_headers event.headers
        throw :pass
      end

      on_joined do |event|
        target = event.call_uri || event.mixer_name
        @peers[target] = Adhearsion.active_calls[target]
        signal :joined, target
      end

      on_unjoined do |event|
        target = event.call_uri || event.mixer_name
        @peers.delete target
        signal :unjoined, target
      end

      on_end do |event|
        logger.info "Call ended"
        clear_from_active_calls
        @end_reason = event.reason
        @end_blocker.broadcast event.reason
        commands.terminate
        after(Adhearsion.config.platform.after_hangup_lifetime) { terminate }
        throw :pass
      end
    end

    ##
    # Registers a callback for when this call is joined to another call or a mixer
    #
    # @param [Call, String, Hash, nil] target the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
    # @option target [String] call_id The call ID to guard on
    # @option target [String] mixer_name The mixer name to guard on
    #
    def on_joined(target = nil, &block)
      register_event_handler Punchblock::Event::Joined, *guards_for_target(target) do |event|
        block.call event
        throw :pass
      end
    end

    ##
    # Registers a callback for when this call is unjoined from another call or a mixer
    #
    # @param [Call, String, Hash, nil] target the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
    # @option target [String] call_id The call ID to guard on
    # @option target [String] mixer_name The mixer name to guard on
    #
    def on_unjoined(target = nil, &block)
      register_event_handler Punchblock::Event::Unjoined, *guards_for_target(target) do |event|
        block.call event
{'fraction_non_alphanumeric': 0.08003085526950149, 'fraction_numerical': 0.00019284543438434094, 'mean_word_length': 2.4758713136729225, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 13, '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': '3673179', 'n_tokens_mistral': 3162, 'n_tokens_neox': 3075, 'n_words': 982}