SoarTransportApi

This gem specifies the API to be implemented by transport providers that want to communicate across soar_comms communication fabric. The API allows for message identification, sending and receiving, both synchronously and asynchronously. Messages are simple Hash objects with formatting to be dictated by the transport provider and consumer.

Installation

Add this line to your application's Gemfile:

gem 'soar_transport_api'

And then execute:

$ bundle

Or install it yourself as:

$ gem install soar_transport_api

Usage

Building a provider

Extend SoarTransportAPI::TransportAPI and override the methods of interest. For example, for a synchronous HTTP transport provider:

  class HttpTransportApi < SoarTransportApi::TransportAPI
    attr_accessor :server
    @received

    def initialize(transport_identifier)
      super(transport_identifier)
      @@received = []
    end

    def send_message(uri, message)
      uri = URI.parse(uri)
      response = Net::HTTP.post_form(uri, {"message" => message})
      @@received.push(response)
      response
    end

    def receive_message
      message = @@received.pop
      message.body
    end  
  end

Sending messages

Use the API as below to send messages both in the synchronous and asynchronous cases:

  message = { 'body' => 'This is a message' }
  provider = HttpTransportApi.new("http-example")
  provider.send_message("http://localhost:9393/postbox", message)

Receiving messages

Use the API as below for receiving in the synchronous case while sending:

  response = provider.send_message("http://localhost:9393/postbox", message)

Alternatively after a send, in the synchronous case:

  response = provider.receive_message

Use the API as below for receiving in the asynchronous case. Provide the transport API registered back to the subscriber in order for it to know which transport (it may have multiple) pinged it with a message. We are using an AMQP transport provider for this example:

  class Subscriber
    def receive(message)
      puts "Received #{message}"
    end
  end

  class RabbitTransportProvider < SoarTransportApi::TransportAPI
    def receive_messages(callback, transport_provider_id)
      t = Thread.new {
        @conn.start
        ch   = @conn.create_channel
        q    = ch.queue(@transport_identifier)
        begin
          message = nil
          q.subscribe(:block => true) do |delivery_info, properties, body|
            puts " [x] Received message"
            callback.receive(transport_provider_id, body)
          end
          @conn.close
        rescue Interrupt => _
          @conn.close
        end
      }
      t.abort_on_exception = true    
    end
  end

  provider = RabbitTransportProvider.new("bunnies")
  subscriber = Subscriber.new
  provider.receive_messages(suscriber, "bunnies")

Exceptions

The transport API raises the following exceptions:

  TransportIdentifierInvalidError - a transport identifier was not provided (nil) or was not a String or was an empty string
  SubscriberCallbackInvalidError - the subscriber specified for callbacks of received messages was not provided (nil) or does not have a receive method
  NoMessageError - No message was provided to send
  InvalidURIError - An invalid URI or no URI was provided

Contributing

Bug reports and feature requests are welcome by email to ernst dot van dot graan at hetzner dot co dot za. This gem is sponsored by Hetzner (Pty) Ltd (http://hetzner.co.za)

License

The gem is available as open source under the terms of the MIT License.