<commit_before>require_relative 'base'

module RUPNP

  class Service < Base
    attr_reader :type
    attr_reader :id
    attr_reader :scpd_url
    attr_reader :control_url
    attr_reader :event_sub_url

    attr_reader :xmlns
    attr_reader :spec_version
    attr_reader :actions
    attr_reader :state_table

    def initialize(url_base, service)
      super()
      @description = service

      @type = build_url(url_base, service[:service_type].to_s)
      @scpd_url = build_url(url_base,  service[:scpdurl].to_s)
      @control_url =  build_url(url_base, service[:control_url].to_s)
      @event_sub_url =  build_url(url_base, service[:event_sub_url].to_s)
      @actions = []
    end

    def fetch
      if @scpd_url.empty?
        fail 'no SCPD URL'
        return
      end

      scpd_getter = EM::DefaultDeferrable.new

      scpd_getter.errback do
        fail "cannot get SCPD from #@scpd_url"
      end

      scpd_getter.callback do |scpd|
        if !scpd or scpd.empty?
          fail "SCPD from #@scpd_url is empty"
          next
        end

        if bad_description?(scpd)
          fail 'not a UPNP 1.0/1.1 SCPD'
          next
        end

        extract_service_state_table scpd
        succeed self
      end

      get_description @scpd_url, scpd_getter
    end


    private

    def bad_description?(scpd)
      if scpd[:scpd]
        bd = false
        @xmlns = scpd[:scpd][:@xmlns]
        bd |= @xmlns != "urn:schemas-upnp-org:service-1-0"
        bd |= scpd[:scpd][:spec_version][:major].to_i != 1
        @spec_version = scpd[:scpd][:spec_version][:major] + '.'
        @spec_version += scpd[:scpd][:spec_version][:minor]
        bd |= !scpd[:scpd][:service_state_table]
        bd | scpd[:scpd][:service_state_table].empty?
      else
        true
      end
    end

    def extract_service_state_table(scpd)
      if scpd[:scpd][:service_state_table][:state_variable]
        @state_table = scpd[:scpd][:service_state_table][:state_variable]
        # ease debug print
        @state_table.each { |s| s.each { |k, v| s[k] = v.to_s } }
      end
    end

  end

end<commit_msg>* lib/rupnp/service.rb:   - initialize a Savon SOAP client ;   - add #extract_actions   - write #define_method_from_action which create a SOAP request.     No process of return value made (todo).<commit_after>require 'savon'
require_relative 'base'

module RUPNP

  class Service < Base
    attr_reader :type
    attr_reader :scpd_url
    attr_reader :control_url
    attr_reader :event_sub_url

    attr_reader :xmlns
    attr_reader :spec_version
    attr_reader :actions
    attr_reader :state_table

    def initialize(url_base, service)
      super()
      @description = service

      @type = build_url(url_base, service[:service_type].to_s)
      @scpd_url = build_url(url_base,  service[:scpdurl].to_s)
      @control_url =  build_url(url_base, service[:control_url].to_s)
      @event_sub_url =  build_url(url_base, service[:event_sub_url].to_s)
      @actions = []

      initialize_savon
    end

    def fetch
      if @scpd_url.empty?
        fail 'no SCPD URL'
        return
      end

      scpd_getter = EM::DefaultDeferrable.new

      scpd_getter.errback do
        fail "cannot get SCPD from #@scpd_url"
      end

      scpd_getter.callback do |scpd|
        if !scpd or scpd.empty?
          fail "SCPD from #@scpd_url is empty"
          next
        end

        if bad_description?(scpd)
          fail 'not a UPNP 1.0/1.1 SCPD'
          next
        end

        extract_service_state_table scpd
        extract_actions scpd

        succeed self
      end

      get_description @scpd_url, scpd_getter
    end


    private

    def bad_description?(scpd)
      if scpd[:scpd]
        bd = false
        @xmlns = scpd[:scpd][:@xmlns]
        bd |= @xmlns != "urn:schemas-upnp-org:service-1-0"
        bd |= scpd[:scpd][:spec_version][:major].to_i != 1
        @spec_version = scpd[:scpd][:spec_version][:major] + '.'
        @spec_version += scpd[:scpd][:spec_version][:minor]
        bd |= !scpd[:scpd][:service_state_table]
        bd | scpd[:scpd][:service_state_table].empty?
      else
        true
      end
    end

    def extract_service_state_table(scpd)
      if scpd[:scpd][:service_state_table][:state_variable]
        @state_table = scpd[:scpd][:service_state_table][:state_variable]
        # ease debug print
        @state_table.each { |s| s.each { |k, v| s[k] = v.to_s } }
      end
    end

    def extract_actions(scpd)
      if scpd[:scpd][:action_list] and scpd[:scpd][:action_list][:action]
        log :info, "extract actions for service #@type"
        @action_list = scpd[:scpd][:action_list][:action]
        @action_list.each do |action|
          action[:argument_list] = action[:argument_list][:argument]
          define_method_from_action action
        end
        p @action_list
        p self.singleton_methods
      end
    end

    def define_method_from_action(action)
      action_name = action[:name]
      name = action_name.gsub(/(\w)([A-Z])/) { "#{$1}_#{$2}" }
      name = name.downcase.to_sym
      define_singleton_method(name) do |params|
        @soap.call(action_name) do |locals|
          local.message_tags 'xmlns:u' => @type
          local.soap_action "#{type}##{action_name}"
          if params
            unless params.is_a? Hash
              raise ArgumentError, 'only hash arguments are accepted'
            end
            soap.body params
          end
        end

        ## TODO: process return value
      end
    end

    def initialize_savon
      @soap = Savon.client do |globals|
        globals.endpoint @control_url
        globals.namespace @type
        globals.convert_request_keys_to :camel_case
        globals.log true
        globals.headers :HOST => "#{HOST_IP}"
      end
    end

  end

end
{'fraction_non_alphanumeric': 0.1037444177258674, 'fraction_numerical': 0.0027481964960494676, 'mean_word_length': 2.3697916666666665, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 9}, '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': '2930674', 'n_tokens_mistral': 2008, 'n_tokens_neox': 1948, 'n_words': 411}