<commit_before>
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'pry'

# ScalerPlugin implementation that uses Google Analytics Live API
# to get the current active users on the site, and scale to an
# appropriate number of dynos.

class GoogleAnalyticsPlugin < ScalerPlugin
    attr_reader :seed
    API_VERSION = "v3"
    CACHED_API_FILE = "analytics-#{API_VERSION}.cache"
    KEYFILE = File.expand_path('~/.google/private.p12')
    PASSPHRASE = 'notasecret'

    # Load config from the config hash
    def initialize(config)
        super
        @unit = "active users"
        @keyfile = config.fetch("keyfile", KEYFILE)
        @passphrase = config.fetch("passphrase", PASSPHRASE)
        @client_email = config["client_email"]
        @analytics_view_id = config["analytics_view_id"]
        @users_per_dyno = config["users_per_dyno"]

        if @client_email.nil?
            raise "You must supply client_email in the google analytics plugin config"
        end
        if @analytics_view_id.nil?
            raise "You must supply analytics_view_id in the google analytics plugin config"
        end
        if @users_per_dyno.nil?
            raise "You must supply users_per_dyno in the google analytics plugin config"
        end

        init_api

    end

    def retrieve
        return get_active_users
    end

    def estimated_dynos
        @value = self.get_value
        if @value.nil?
            return -1
        end
        return (@value / @users_per_dyno).ceil
    end

    private
    def init_api
        @client = Google::APIClient.new(
            :application_name => "Analytics Dyno Scaler",
            :application_version => '1.0.0')  # TODO get real version
        @client.authorization = nil
        @key = Google::APIClient::KeyUtils.load_from_pkcs12(@keyfile, @passphrase)
        @analytics = nil

        # Load cached discovered API, if it exists. This prevents retrieving the
        # discovery document on every run, saving a round-trip to the discovery service.
        if File.exists? CACHED_API_FILE
          File.open(CACHED_API_FILE) do |file|
            @analytics = Marshal.load(file)
          end
        else
          @analytics = @client.discovered_api('analytics', API_VERSION)
          File.open(CACHED_API_FILE, 'w') do |file|
            Marshal.dump(@analytics, file)
          end
        end
    end

    def authorize(force=false)
        # Check for re-authorization
        if !@client.authorization.nil? && !force
            expiry = @client.authorization.issued_at + @client.authorization.expiry*60
            reauth_time = expiry - 2
            now = Time.now
            if now < reauth_time
                return  # Skip authorization
            end
        end
        @client.authorization = Signet::OAuth2::Client.new(
          :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
          :audience => 'https://accounts.google.com/o/oauth2/token',
          :scope => 'https://www.googleapis.com/auth/analytics.readonly',
          :issuer => @client_email,
          :signing_key => @key)
        # Request a token for our service account
        @client.authorization.fetch_access_token!
    end

    def get_active_users

        active = -1
        begin
            authorize
            r = @client.execute(:api_method => @analytics.data.realtime.get, :parameters => { 'ids' => "ga:#{@analytics_view_id}", 'metrics' => 'ga:activeVisitors'})
            active = r.data.rows[0][0].to_i
        rescue Exception => e
            puts "ERROR: failed to decipher result, forcing re-auth"
            puts e.inspect
            begin
                authorize(true)
            rescue
            end
        end
        return active
    end



end
<commit_msg>Use floating point in GA plugin<commit_after>
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'pry'

# ScalerPlugin implementation that uses Google Analytics Live API
# to get the current active users on the site, and scale to an
# appropriate number of dynos.

class GoogleAnalyticsPlugin < ScalerPlugin
    attr_reader :seed
    API_VERSION = "v3"
    CACHED_API_FILE = "analytics-#{API_VERSION}.cache"
    KEYFILE = File.expand_path('~/.google/private.p12')
    PASSPHRASE = '<PASSWORD>'

    # Load config from the config hash
    def initialize(config)
        super
        @unit = "active users"
        @keyfile = config.fetch("keyfile", KEYFILE)
        @passphrase = config.fetch("passphrase", PASSPHRASE)
        @client_email = config["client_email"]
        @analytics_view_id = config["analytics_view_id"]
        @users_per_dyno = config["users_per_dyno"]

        if @client_email.nil?
            raise "You must supply client_email in the google analytics plugin config"
        end
        if @analytics_view_id.nil?
            raise "You must supply analytics_view_id in the google analytics plugin config"
        end
        if @users_per_dyno.nil?
            raise "You must supply users_per_dyno in the google analytics plugin config"
        end

        init_api

    end

    def retrieve
        return get_active_users
    end

    def estimated_dynos
        @value = self.get_value
        if @value.nil?
            return -1
        end
        return (@value / @users_per_dyno.to_f).ceil
    end

    private
    def init_api
        @client = Google::APIClient.new(
            :application_name => "Analytics Dyno Scaler",
            :application_version => '1.0.0')  # TODO get real version
        @client.authorization = nil
        @key = Google::APIClient::KeyUtils.load_from_pkcs12(@keyfile, @passphrase)
        @analytics = nil

        # Load cached discovered API, if it exists. This prevents retrieving the
        # discovery document on every run, saving a round-trip to the discovery service.
        if File.exists? CACHED_API_FILE
          File.open(CACHED_API_FILE) do |file|
            @analytics = Marshal.load(file)
          end
        else
          @analytics = @client.discovered_api('analytics', API_VERSION)
          File.open(CACHED_API_FILE, 'w') do |file|
            Marshal.dump(@analytics, file)
          end
        end
    end

    def authorize(force=false)
        # Check for re-authorization
        if !@client.authorization.nil? && !force
            expiry = @client.authorization.issued_at + @client.authorization.expiry*60
            reauth_time = expiry - 2
            now = Time.now
            if now < reauth_time
                return  # Skip authorization
            end
        end
        @client.authorization = Signet::OAuth2::Client.new(
          :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
          :audience => 'https://accounts.google.com/o/oauth2/token',
          :scope => 'https://www.googleapis.com/auth/analytics.readonly',
          :issuer => @client_email,
          :signing_key => @key)
        # Request a token for our service account
        @client.authorization.fetch_access_token!
    end

    def get_active_users

        active = -1
        begin
            authorize
            r = @client.execute(:api_method => @analytics.data.realtime.get, :parameters => { 'ids' => "ga:#{@analytics_view_id}", 'metrics' => 'ga:activeVisitors'})
            active = r.data.rows[0][0].to_i
        rescue Exception => e
            puts "ERROR: failed to decipher result, forcing re-auth"
            puts e.inspect
            begin
                authorize(true)
            rescue
            end
        end
        return active
    end



end

{'fraction_non_alphanumeric': 0.09055577147298872, 'fraction_numerical': 0.004663816556548776, 'mean_word_length': 2.1861328931077177, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 28, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, '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': '3738605', 'n_tokens_mistral': 2271, 'n_tokens_neox': 2224, 'n_words': 571}