require 'rexml/document' require 'digest/md5' require 'net/http' module MooMoo module OpenSRS class Command # Constructor # # ==== Required # * :action - action of the command # * :object - object the command operates on # * :params - additional parameters for the command # # ==== Optional # * :cookie - a cookie for the domain if the command requires it def initialize(action, object, params = {}, cookie = nil) @action = action @object = object @params = params @cookie = cookie end # Runs the command against OpenSRS server # # ==== Required # * :host - host of the OpenSRS server # * :key - private key for the account # * :user - username for the account # * :port - port to connect to def run(host, key, user, port) xml = build_command(@action, @object, @params, @cookie) md5_signature = Digest::MD5.hexdigest( Digest::MD5.hexdigest( xml + key ) + key ) headers = { 'Content-Type' => 'text/xml', 'X-Username' => user, 'X-Signature' => md5_signature, 'Content-Length' => xml.size.to_s } http = Net::HTTP.new(URI.encode(host), port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE #http.ca_file = File.join(File.dirname(__FILE__), "../..", "cacert.pem") res = http.post(URI.encode("/"), xml, headers) @returned_parameters = parse_response(res.body) end private # Adds XML child elements to the specified XML element for a given collection # # ==== Required # * :elem - XML element to add the child nodes to # * :coll - collection that will be added as XML child elements def xml_add_collection_as_child(elem, coll) # default collection type is array dt_type = 'dt_array' # if it's a hash, make sure the keys aren't numeric if coll.is_a?(Hash) begin Float(coll.keys.first) rescue # the keys weren't numeric, so it really is an association (hash) dt_type = 'dt_assoc' end end elem = elem.add_element(dt_type) coll = coll.first if coll.is_a? Array coll.each do |key, value| child = elem.add_element('item', {'key' => key}) if value.is_a?(Hash) || value.is_a?(Array) xml_add_collection_as_child(child, value) else child.text = value end end end # Builds an XML string of the command which can be sent to OpenSRS # # ==== Required # * :action - action of the command # * :object - object the command operates on # # ==== Optional # * :attributes - additional attributes for the command # * :cookie - cookie for the domain if the command requires it def build_command(action, object, attributes = nil, cookie = nil) xml = <<-XML
0.9
XCP GET_BALANCE BALANCE
XML doc = REXML::Document.new(xml) doc.root.elements["body/data_block/dt_assoc/item[@key='action']"].text = action doc.root.elements["body/data_block/dt_assoc/item[@key='object']"].text = object unless cookie.nil? cookie_elem = doc.root.elements["body/data_block/dt_assoc"].add_element('item', {'key' => 'cookie'}) cookie_elem.text = cookie end unless attributes.nil? elem = doc.root.elements["body/data_block/dt_assoc"].add_element('item', {'key' => 'attributes'}) elem = elem.add_element('dt_assoc') attributes.each_pair do |key, value| attrib_elem = elem.add_element('item', {'key' => key}) if value.is_a?(Hash) || value.is_a?(Array) xml_add_collection_as_child(attrib_elem, value) else attrib_elem.text = (value.is_a?(String) ? value.dup : value) end end end doc.to_s end # Parses an XML response from the OpenSRS registry and generates a # hash containing all of the data. Elements with child elements # are converted into hashes themselves, with the :element_text entry # containing any raw text # # ==== Required # * data - data of the response def parse_response(data) doc = REXML::Document.new(data) values = {} elements = doc.elements["/OPS_envelope/body/data_block/dt_assoc"].select { |item| item.is_a? REXML::Element } build_xml_hash(elements) end # Builds a hash from a collection of XML elements # # ==== Required # * elements - collection of elemenents def build_xml_hash(elements) data_hash = {} elements.each do |elem| key = elem.attributes['key'] if elem.elements.size > 0 if key.nil? data_hash.merge!(build_xml_hash(elem.elements)) else data_hash[key] = build_xml_hash(elem.elements) end else data_hash[key] = elem.text unless key.nil? end end data_hash end end end end