class Crossbar::HTTP::Client

Attributes

key[RW]
pre_serialize[RW]
secret[RW]
sequence[RW]
url[RW]
verbose[RW]

Public Class Methods

_get_nonce() click to toggle source
# File lib/crossbar-http/client.rb, line 133
def self._get_nonce
  rand(0..2**53)
end
_get_timestamp() click to toggle source
# File lib/crossbar-http/client.rb, line 129
def self._get_timestamp
  Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S.%LZ')
end
new(url, key: nil, secret: nil, verbose: false, pre_serialize: nil) click to toggle source

Initializes the client @param url [String] - The url of the router's HTTP bridge @param key [String] - The key (optional) @param secret [String] - The secret (optional) @param verbose [Bool] - 'True' if you want debug messages printed @param pre_serialize [lambda] - Lambda to format the data

# File lib/crossbar-http/client.rb, line 44
def initialize(url, key: nil, secret: nil, verbose: false, pre_serialize: nil)

  raise 'The url can not be nil' unless url != nil

  self.url = url
  self.key = key
  self.secret = secret
  self.verbose = verbose
  self.pre_serialize = pre_serialize
  self.sequence = 1
end

Public Instance Methods

_api_call(uri, body=nil) click to toggle source

This method makes tha API call. It is a class method so it can be more easily stubbed for testing @param uri [URI] The uri of the request @param body [String] The body of the request @return [Hash] The response from the server

# File lib/crossbar-http/client.rb, line 181
def _api_call(uri, body=nil)
  # Create the request
  res = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
    req = Net::HTTP::Post.new(uri)
    req['Content-Type'] = 'application/json'
    req.body = body

    http.request(req)
  end

  case res
    when Net::HTTPSuccess
      puts "Crossbar::HTTP - Response Body: #{res.body}" if self.verbose
      return JSON.parse(res.body, {:symbolize_names => true})
    else
      raise "Crossbar::HTTP - Code: #{res.code}, Error: #{res.message}"
  end
end
_compute_signature(body) click to toggle source

Computes the signature. Described at: crossbar.io/docs/HTTP-Bridge-Services-Caller/ Reference code is at: github.com/crossbario/crossbar/blob/master/crossbar/adapter/rest/common.py @param body [Hash] @return (signature, nonce, timestamp)

# File lib/crossbar-http/client.rb, line 113
def _compute_signature(body)
  timestamp = self.class._get_timestamp
  nonce = self.class._get_nonce

  # Compute signature: HMAC[SHA256]_{secret} (key | timestamp | seq | nonce | body) => signature
  hm = OpenSSL::HMAC.new(self.secret, OpenSSL::Digest::SHA256.new)
  hm << self.key
  hm << timestamp
  hm << self.sequence.to_s
  hm << nonce.to_s
  hm << body
  signature = Base64.urlsafe_encode64(hm.digest)

  return signature, nonce, timestamp
end
_make_api_call(json_params=nil) click to toggle source

Performs the API call @param json_params [Hash,nil] The parameters that will make up the body of the request @return [Hash] The response from the server

# File lib/crossbar-http/client.rb, line 140
def _make_api_call(json_params=nil)

  puts "Crossbar::HTTP - Request: POST #{url}" if self.verbose

  encoded_params = nil
  if json_params != nil
    if self.pre_serialize != nil and self.pre_serialize.is_a? Proc
      json_params = self._parse_params json_params
    end
    encoded_params = JSON.generate(json_params)
  end

  puts "Crossbar::HTTP - Params: #{encoded_params}" if encoded_params != nil and self.verbose

  uri = URI(self.url)

  if self.key != nil and self.secret != nil and encoded_params != nil
    signature, nonce, timestamp = self._compute_signature(encoded_params)
    params = {
        timestamp: timestamp,
        seq: self.sequence.to_s,
        nonce: nonce,
        signature: signature,
        key: self.key
    }
    uri.query = URI.encode_www_form(params)

    puts "Crossbar::HTTP - Signature Params: #{params}" if self.verbose
  end

  # TODO: Not sure what this is supposed to be but this works
  self.sequence += 1

  self._api_call uri, encoded_params
end
_parse_params(params) click to toggle source

Parses the params to pre-serialize the overrides

# File lib/crossbar-http/client.rb, line 89
def _parse_params(params)

  if params.is_a? Hash
    return_value = {}
    params.each do |key, value|
      return_value[key] = self._parse_params(value)
    end
  elsif params.is_a? Array
    return_value = []
    params.each_index {|i|
      return_value.push(self._parse_params (params[i]))
    }
  else
    return_value = self.pre_serialize.call(params) || params
  end

  return_value
end
call(procedure, *args, **kwargs) click to toggle source

Calls the procedure @param procedure [String] - The name of the topic @param *args [] - The arguments and key word arguments @return [Integer] - Returns the id of the publish

# File lib/crossbar-http/client.rb, line 76
def call(procedure, *args, **kwargs)
  raise 'The topic can not be nil' unless url != nil

  params = {
      procedure: procedure,
      args: args,
      kwargs: kwargs
  }

  self._make_api_call(params)
end
publish(topic, *args, **kwargs) click to toggle source

Publishes to the topic @param topic [String] - The name of the topic @param *args [] - The arguments and key word arguments @return [Integer] - Returns the id of the publish

# File lib/crossbar-http/client.rb, line 60
def publish(topic, *args, **kwargs)
  raise 'The topic can not be nil' unless url != nil

  params = {
      topic: topic,
      args: args,
      kwargs: kwargs
  }

  self._make_api_call(params)
end