<commit_before>require 'hawkular/base_client'
require 'websocket-client-simple'
require 'json'

require 'hawkular/inventory/entities'

# Adding a method `perform` for each block so that we can write nice callbacks for this client
class Proc
  class PerformMethodMissing
  end
  def perform(callable, result)
    call(Class.new do
      method_name = callable.to_sym
      define_method(method_name) { |&block| block.nil? ? true : block.call(result) }
      define_method("#{method_name}?") { true }
      # method_missing is here because we are not forcing the client to provide both success and error callbacks
      # rubocop:disable Lint/NestedMethodDefinition
      # https://github.com/bbatsov/rubocop/issues/2704
      def method_missing(_method_name, *_args, &_block)
        PerformMethodMissing
      end
      # rubocop:enable Lint/NestedMethodDefinition
    end.new)
  end
end

# Operations module allows invoking operation on the WildFly agent.
module Hawkular::Operations
  # Client class to interact with the agent via websockets
  class OperationsClient < Hawkular::BaseClient
    include WebSocket::Client

    attr_accessor :ws, :session_id

    # helper for parsing the "OperationName=json_payload" messages
    class WebSocket::Frame::Data
      def to_msg_hash
        chunks = split('=', 2)
        {
          operationName: chunks[0],
          data: JSON.parse(chunks[1])
        }
      rescue
        {}
      end
    end

    # Initialize new OperationsClient
    #
    # @param [Hash] args Arguments for client.
    # There are two ways of passing in the target host/port: via :host and via :entrypoint. If
    # both are given, then :entrypoint will be used.
    #
    # @option args [String] :entrypoint Base URL of the hawkular server e.g. http://localhost:8080.
    # @option args [String] :host base host:port pair of Hawkular - e.g localhost:8080
    # @option args [Boolean] :use_secure_connection if no entrypoint is provided, determines if use a secure connection
    #                        defaults to false
    # @option args [Hash{String=>String}]  :credentials Hash of (username password) or token
    # @option args [Hash{String=>String}] :options Additional rest client options
    # @option args [Fixnum]  :wait_time Time in seconds describing how long the constructor should block - handshake
    #
    # @example
    #   Hawkular::Operations::OperationsClient.new(credentials: {username: 'jdoe', password: 'password'})
    def initialize(args)
      args[:use_secure_connection] ||= false
      ep = args[:entrypoint]

      unless ep.nil?
        uri = URI.parse ep.to_s
        args[:host] = "#{uri.host}:#{uri.port}"
        args[:use_secure_connection] = %w(https wss).include?(uri.scheme) ? true : false
      end

      fail 'no parameter ":host" or ":entrypoint" given' if args[:host].nil?
      args[:credentials] ||= {}
      args[:options] ||= {}
      args[:wait_time] ||= 0.5
      super(args[:host], args[:credentials], args[:options])
      url = "ws#{args[:use_secure_connection] ? 's' : ''}://#{args[:host]}/hawkular/command-gateway/ui/ws"
      ws_options = {}
      creds = args[:credentials]
      base64_creds = ["#{creds[:username]}:#{creds[:password]}"].pack('m').delete("\r\n")
      ws_options[:headers] = { 'Authorization' => 'Basic ' + base64_creds,
                               'Hawkular-Tenant' => args[:options][:tenant],
                               'Accept' => 'application/json'
      }

      @ws = Simple.connect url, ws_options do |client|
        client.on(:message, once: true) do |msg|
          parsed_message = msg.data.to_msg_hash
          puts parsed_message if ENV['HAWKULARCLIENT_LOG_RESPONSE']
          case parsed_message[:operationName]
          when 'WelcomeResponse'
            @session_id = parsed_message[:data]['sessionId']
          end
        end
      end
      sleep args[:wait_time]
    end

    # Closes the WebSocket connection
    def close_connection!
      @ws.close
    end

    # Invokes a generic operation on the WildFly agent
    # (the operation name must be specified in the hash)
    # Note: if success and failure callbacks are omitted, the client will not wait for the Response message
    # @param hash [Hash{String=>Object}] a hash containing: resourcePath [String] denoting the resource on
    # which the operation is about to run, operationName [String]
    # @param callback [Block] callback that is run after the operation is done
    def invoke_generic_operation(hash, &callback)
      required = [:resourcePath, :operationName]
      check_pre_conditions hash, required, &callback

      invoke_operation_helper(hash, &callback)
    end

    # Invokes operation on the WildFly agent that has it's own message type
    # @param operation_payload [Hash{String=>Object}] a hash containing: resourcePath [String] denoting
    # the resource on which the operation is about to run
    # @param operation_name [String] the name of the operation. This must correspond with the message type, they can be
    # found here https://git.io/v2h1a (Use only the first part of the name without the Request/Response suffix), e.g.
    # RemoveDatasource (and not RemoveDatasourceRequest)
    # @param callback [Block] callback that is run after the operation is done
    def invoke_specific_operation(operation_payload, operation_name, &callback)
      fail 'Operation must be specified' if operation_name.nil?
      required = [:resourcePath]
      check_pre_conditions operation_payload, required, &callback

      invoke_operation_helper(operation_payload, operation_name, &callback)
    end

    # Deploys an archive file into WildFly
    #
    # @param [Hash] hash Arguments for deployment
    # @option hash [String]  :resource_path canonical path of the WildFly server into which we deploy
    # @option hash [String]  :destination_file_name resulting file name
    # @option hash [String]  :binary_content binary content representing the war file
    # @option hash [String]  :enabled whether the deployment should be enabled immediately, or not (default = true)
    # @option hash [String]  :force_deploy whether to replace existing content or not (default = false)
    # @option hash [String]  :server_groups comma-separated list of server groups for the operation (default = ignored)
    #
    # @param callback [Block] callback that is run after the operation is done
    def add_deployment(hash, &callback)
      hash[:enabled] = hash.key?(:enabled) ? hash[:enabled] : true
      hash[:force_deploy] = hash.key?(:force_deploy) ? hash[:force_deploy] : false
      required = [:resource_path, :destination_file_name, :binary_content]
      check_pre_conditions hash, required, &callback

      operation_payload = prepare_payload_hash([:binary_content], hash)
      invoke_operation_helper(operation_payload, 'DeployApplication', hash[:binary_content], &callback)
    end<commit_msg>Docs: describing what resource_path is expected in case of deploying into a server group.<commit_after>require 'hawkular/base_client'
require 'websocket-client-simple'
require 'json'

require 'hawkular/inventory/entities'

# Adding a method `perform` for each block so that we can write nice callbacks for this client
class Proc
  class PerformMethodMissing
  end
  def perform(callable, result)
    call(Class.new do
      method_name = callable.to_sym
      define_method(method_name) { |&block| block.nil? ? true : block.call(result) }
      define_method("#{method_name}?") { true }
      # method_missing is here because we are not forcing the client to provide both success and error callbacks
      # rubocop:disable Lint/NestedMethodDefinition
      # https://github.com/bbatsov/rubocop/issues/2704
      def method_missing(_method_name, *_args, &_block)
        PerformMethodMissing
      end
      # rubocop:enable Lint/NestedMethodDefinition
    end.new)
  end
end

# Operations module allows invoking operation on the WildFly agent.
module Hawkular::Operations
  # Client class to interact with the agent via websockets
  class OperationsClient < Hawkular::BaseClient
    include WebSocket::Client

    attr_accessor :ws, :session_id

    # helper for parsing the "OperationName=json_payload" messages
    class WebSocket::Frame::Data
      def to_msg_hash
        chunks = split('=', 2)
        {
          operationName: chunks[0],
          data: JSON.parse(chunks[1])
        }
      rescue
        {}
      end
    end

    # Initialize new OperationsClient
    #
    # @param [Hash] args Arguments for client.
    # There are two ways of passing in the target host/port: via :host and via :entrypoint. If
    # both are given, then :entrypoint will be used.
    #
    # @option args [String] :entrypoint Base URL of the hawkular server e.g. http://localhost:8080.
    # @option args [String] :host base host:port pair of Hawkular - e.g localhost:8080
    # @option args [Boolean] :use_secure_connection if no entrypoint is provided, determines if use a secure connection
    #                        defaults to false
    # @option args [Hash{String=>String}]  :credentials Hash of (username password) or token
    # @option args [Hash{String=>String}] :options Additional rest client options
    # @option args [Fixnum]  :wait_time Time in seconds describing how long the constructor should block - handshake
    #
    # @example
    #   Hawkular::Operations::OperationsClient.new(credentials: {username: 'jdoe', password: 'password'})
    def initialize(args)
      args[:use_secure_connection] ||= false
      ep = args[:entrypoint]

      unless ep.nil?
        uri = URI.parse ep.to_s
        args[:host] = "#{uri.host}:#{uri.port}"
        args[:use_secure_connection] = %w(https wss).include?(uri.scheme) ? true : false
      end

      fail 'no parameter ":host" or ":entrypoint" given' if args[:host].nil?
      args[:credentials] ||= {}
      args[:options] ||= {}
      args[:wait_time] ||= 0.5
      super(args[:host], args[:credentials], args[:options])
      url = "ws#{args[:use_secure_connection] ? 's' : ''}://#{args[:host]}/hawkular/command-gateway/ui/ws"
      ws_options = {}
      creds = args[:credentials]
      base64_creds = ["#{creds[:username]}:#{creds[:password]}"].pack('m').delete("\r\n")
      ws_options[:headers] = { 'Authorization' => 'Basic ' + base64_creds,
                               'Hawkular-Tenant' => args[:options][:tenant],
                               'Accept' => 'application/json'
      }

      @ws = Simple.connect url, ws_options do |client|
        client.on(:message, once: true) do |msg|
          parsed_message = msg.data.to_msg_hash
          puts parsed_message if ENV['HAWKULARCLIENT_LOG_RESPONSE']
          case parsed_message[:operationName]
          when 'WelcomeResponse'
            @session_id = parsed_message[:data]['sessionId']
          end
        end
      end
      sleep args[:wait_time]
    end

    # Closes the WebSocket connection
    def close_connection!
      @ws.close
    end

    # Invokes a generic operation on the WildFly agent
    # (the operation name must be specified in the hash)
    # Note: if success and failure callbacks are omitted, the client will not wait for the Response message
    # @param hash [Hash{String=>Object}] a hash containing: resourcePath [String] denoting the resource on
    # which the operation is about to run, operationName [String]
    # @param callback [Block] callback that is run after the operation is done
    def invoke_generic_operation(hash, &callback)
      required = [:resourcePath, :operationName]
      check_pre_conditions hash, required, &callback

      invoke_operation_helper(hash, &callback)
    end

    # Invokes operation on the WildFly agent that has it's own message type
    # @param operation_payload [Hash{String=>Object}] a hash containing: resourcePath [String] denoting
    # the resource on which the operation is about to run
    # @param operation_name [String] the name of the operation. This must correspond with the message type, they can be
    # found here https://git.io/v2h1a (Use only the first part of the name without the Request/Response suffix), e.g.
    # RemoveDatasource (and not RemoveDatasourceRequest)
    # @param callback [Block] callback that is run after the operation is done
    def invoke_specific_operation(operation_payload, operation_name, &callback)
      fail 'Operation must be specified' if operation_name.nil?
      required = [:resourcePath]
      check_pre_conditions operation_payload, required, &callback

      invoke_operation_helper(operation_payload, operation_name, &callback)
    end

    # Deploys an archive file into WildFly
    #
    # @param [Hash] hash Arguments for deployment
    # @option hash [String]  :resource_path canonical path of the WildFly server into which we deploy
    #                        or of the domain controller if we deploy into a server group (in case of domain mode)
    # @option hash [String]  :destination_file_name resulting file name
    # @option hash [String]  :binary_content binary content representing the war file
    # @option hash [String]  :enabled whether the deployment should be enabled immediately, or not (default = true)
    # @option hash [String]  :force_deploy whether to replace existing content or not (default = false)
    # @option hash [String]  :server_groups comma-separated list of server groups for the operation (default = ignored)
    #
    # @param callback [Block] callback that is run after the operation is done
    def add_deployment(hash, &callback)
      hash[:enabled] = hash.key?(:enabled) ? hash[:enabled] : true
      hash[:force_deploy] = hash.key?(:force_deploy) ? hash[:force_deploy] : false
      required = [:resource_path, :destination_file_name, :binary_content]
      check_pre_conditions hash, required, &callback

      operation_payload = prepare_payload_hash([:binary_content], hash)
      invoke_operation_helper(operation_payload, 'DeployApplication', hash[:binary_content], &callback)
    end
{'fraction_non_alphanumeric': 0.09464374866272021, 'fraction_numerical': 0.0032807930960701806, 'mean_word_length': 3.327777777777778, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 4, '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': '4216874', 'n_tokens_mistral': 3949, 'n_tokens_neox': 3872, 'n_words': 1291}