class GxG::Networking::ZmqNode

xxx

class AbstractZMQSocket
  # Abstract class, never instantiated
  def self.supported_protocols()
    if ::GxG::SYSTEM.platform()[:platform] == :windows
      ["inproc", "tcp", "tcp4", "tcp6", "pgm", "epgm"]
    else
      ["inproc", "ipc", "tcp", "tcp4", "tcp6", "pgm", "epgm"]
    end
  end
  #
  def initialize(settings={})
    # {:context => nil, :type => nil, :bind => {:thisone => "", :thatone => ""}, :connect => nil}
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    @thread_safety = ::Mutex.new
    if settings[:context].is_a?(::ZMQ::Context)
      @context = settings[:context]
    else
      @context = ::GxG::Networking::zmq_context()
    end
    if settings[:type].is_a?(::Numeric)
      @socket = @context.socket(settings[:type])
    else
      raise ArgumentError, "you must supply a type for the socket"
    end
    @name = ::Celluloid::UUID.random_generate().to_sym
    socket_id = (settings[:identity] || @name).to_s.dup
    if socket_id.bytesize() > 255
      socket_id.force_encoding(::Encoding::ASCII_8BIT)
      socket_id = socket_id[(0..255)]
    end
    @socket.identity = socket_id
    #
    @recv_buffer_size = 1024
    @send_buffer_size = 1024
    #
    @bindings = {}
    if settings[:bind].is_a?(::Hash)
      #
      settings[:bind].keys.to_enum(:each).each do |binding_key|
        if settings[:bind][(binding_key)].is_a?(::URI::Generic)
          address = settings[:bind][(binding_key)]
        else
          address = ::URI::parse(settings[:bind][(binding_key)])
        end
        if ::GxG::Networking::AbstractZMQSocket::supported_protocols().include?(address.scheme())
          address.resolve_host()
          if ["tcp", "tcp4", "tcp6", "udp", "udp4", "udp6"].include?(address.scheme())
            if ::GxG::SYSTEM.network_port_used?(::Addrinfo::parse(address))
              raise Errno::EADDRINUSE, "Address and port already in use: #{address.to_s}"
            end
          end
          begin
            @socket.bind(address.to_s)
            @bindings[(binding_key)] = address
          rescue Exception
            @socket.close
            raise
          end
        else
          raise ArgumentError, "#{address.scheme().to_s} is an unsupported protocol"
        end
      end
      #
    end
    #
    @connections = {}
    if settings[:connect].is_a?(::Hash)
      settings[:connect].keys.to_enum(:each).each do |connection_key|
        if settings[:connect][(connection_key)].is_a?(::URI::Generic)
          address = settings[:connect][(connection_key)]
        else
          address = ::URI::parse(settings[:connect][(connection_key)])
        end
        # address = ::URI::parse(settings[:connect][(connection_key)])
        if ::GxG::Networking::AbstractZMQSocket::supported_protocols().include?(address.scheme())
          address.resolve_host()
          unless ::GxG::SYSTEM.network_port_used?(::Addrinfo::parse(address))
            raise Errno::EADDRNOTAVAIL, "Address and port not bound: #{address.to_s}"
          end
          begin
            @socket.connect(address.to_s)
            @connections[(connection_key)] = address
          rescue Exception
            @socket.close
            raise
          end
        else
          raise ArgumentError, "#{address.scheme().to_s} is an unsupported protocol"
        end
      end
    end
    #
    @recv_buffer_size = this.recv_buffer_size()
    @send_buffer_size = this.send_buffer_size()
    #
    this
  end
  #
  def context()
    @thread_safety.synchronize { @context }
  end
  #
  def socket()
    @thread_safety.synchronize { @socket }
  end
  #
  def identity()
    @socket.identity()
  end
  #
  def recv_buffer_size(*args)
    #
    if args.size > 0
      if args[0].is_a?(::Numeric)
        the_size = args.first.to_i
        if the_size > 0
          valid_min = [16384]
          valid_max = [65536]
          [@bindings, @connections].to_enum(:each).each do |the_set|
            the_set.keys.to_enum(:each).each do |the_terminus|
              setting = ::GxG::Networking::buffer_limits(:in, (the_set[(the_terminus)].scheme).to_sym)[:valid]
              valid_min << (setting.min)
              valid_max << (setting.max)
            end
          end
          if ((valid_min.min)..(valid_max.max)).include?(the_size)
            @thread_safety.synchronize {
              @recv_buffer_size = the_size
              @socket.setsockopt(::ZMQ::RCVBUF,the_size)
            }
          else
            raise Exception, "New buffer size #{the_size} is outside acceptable range: #{((valid_min.min)..(valid_max.max)).inspect}"
          end
        end
      end
    else
      data = []
      @thread_safety.synchronize { @socket.getsockopt(::ZMQ::RCVBUF,data) }
      the_size = (data.first || 0).to_i
      if the_size == 0
        # find scheme of connection/binding : the_scheme
        # buffer_size = (::GxG::Networking::buffer_limits(:out, the_scheme.to_sym)[:initial] || 65536)
        buffer_sizes = [65536]
        [@bindings, @connections].to_enum(:each).each do |the_set|
          the_set.keys.to_enum(:each).each do |the_terminus|
            buffer_sizes << (::GxG::Networking::buffer_limits(:in, (the_set[(the_terminus)].scheme).to_sym)[:valid].min)
          end
        end
        # FORNOW: use the smallest buffer size found across all bindings and/or connections
        @thread_safety.synchronize { @recv_buffer_size = buffer_sizes.min }
      else
        @thread_safety.synchronize { @recv_buffer_size = the_size }
      end
    end
    @thread_safety.synchronize { @recv_buffer_size.dup }
  end
  #
  def send_buffer_size(*args)
    #
    if args.size > 0
      if args[0].is_a?(::Numeric)
        the_size = args.first.to_i
        if the_size > 0
          valid_min = [16384]
          valid_max = [65536]
          [@bindings, @connections].to_enum(:each).each do |the_set|
            the_set.keys.to_enum(:each).each do |the_terminus|
              setting = ::GxG::Networking::buffer_limits(:out, (the_set[(the_terminus)].scheme).to_sym)[:valid]
              valid_min << (setting.min)
              valid_max << (setting.max)
            end
          end
          if ((valid_min.min)..(valid_max.max)).include?(the_size)
            @thread_safety.synchronize {
              @send_buffer_size = the_size
              @socket.setsockopt(::ZMQ::SNDBUF,the_size)
            }
          else
            raise Exception, "New buffer size #{the_size} is outside acceptable range: #{((valid_min.min)..(valid_max.max)).inspect}"
          end
        end
      end
    else
      data = []
      @thread_safety.synchronize { @socket.getsockopt(::ZMQ::SNDBUF,data) }
      the_size = (data.first || 0).to_i
      if the_size == 0
        # find scheme of connection/binding : the_scheme
        # buffer_size = (::GxG::Networking::buffer_limits(:out, the_scheme.to_sym)[:initial] || 65536)
        buffer_sizes = [65536]
        [@bindings, @connections].to_enum(:each).each do |the_set|
          the_set.keys.to_enum(:each).each do |the_terminus|
            buffer_sizes << (::GxG::Networking::buffer_limits(:out, (the_set[(the_terminus)].scheme).to_sym)[:valid].min)
          end
        end
        # FORNOW: use the smallest buffer size found across all bindings and/or connections
        @thread_safety.synchronize { @send_buffer_size = buffer_sizes.min }
      else
        @thread_safety.synchronize { @send_buffer_size = the_size }
      end
    end
    @thread_safety.synchronize { @send_buffer_size.dup }
  end
  #
  def binding(binding_key=nil)
    if binding_key
      @thread_safety.synchronize { @bindings[(binding_key)] }
    else
      @thread_safety.synchronize { @bindings }
    end
  end
  #
  def bind(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of keyed bind point(s) for the binding"
    end
    result = false
    settings.keys.to_enum(:each).each do |binding_key|
      if settings[(binding_key)].is_a?(::URI::Generic)
        address = settings[(binding_key)]
      else
        address = ::URI::parse(settings[(binding_key)])
      end
      # address = ::URI::parse(settings[(binding_key)])
      if ::GxG::Networking::AbstractZMQSocket::supported_protocols().include?(address.scheme())
        address.resolve_host()
        if ["tcp", "tcp4", "tcp6", "udp", "udp4", "udp6"].include?(address.scheme())
          if ::GxG::SYSTEM.network_port_used?(::Addrinfo::parse(address))
            raise Errno::EADDRINUSE, "Address and port already in use: #{address.to_s}"
          end
        end
        begin
          @thread_safety.synchronize {
            @socket.bind(address.to_s)
            @bindings[(binding_key)] = address
          }
          result = true
        rescue Exception
          @thread_safety.synchronize { @socket.close }
          raise
        end
      else
        raise ArgumentError, "#{address.scheme().to_s} is an unsupported protocol"
      end
    end
    @recv_buffer_size = this.recv_buffer_size()
    @send_buffer_size = this.send_buffer_size()
    #
    result
  end
  #
  def connection(connection_key=nil)
    if connection_key
      @thread_safety.synchronize { @connections[(connection_key)] }
    else
      @thread_safety.synchronize { @connections }
    end
  end
  #
  def connect(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of keyed address(es) for the connection"
    end
    result = false
    settings.keys.to_enum(:each).each do |connection_key|
      if settings[(connection_key)].is_a?(::URI::Generic)
        address = settings[(connection_key)]
      else
        address = ::URI::parse(settings[(connection_key)])
      end
      # address = ::URI::parse(settings[(connection_key)])
      if ::GxG::Networking::AbstractZMQSocket::supported_protocols().include?(address.scheme())
        address.resolve_host()
        if ["tcp", "tcp4", "tcp6"].include?(address.scheme())
          unless ::GxG::SYSTEM.network_port_used?(::Addrinfo::parse(address))
            raise Errno::EADDRNOTAVAIL, "Address and port not bound: #{address.to_s}"
          end
        end
        begin
          @thread_safety.synchronize {
            @socket.connect(address.to_s)
            @connections[(connection_key)] = address
          }
          result = true
        rescue Exception
          @thread_safety.synchronize { @socket.close() }
          raise
        end
      else
        raise ArgumentError, "#{address.scheme().to_s} is an unsupported protocol"
      end
    end
    @recv_buffer_size = this.recv_buffer_size()
    @send_buffer_size = this.send_buffer_size()
    #
    result
  end
  #
  def close()
    @thread_safety.synchronize { @socket.close() }
  end
  #
  def triage_strings(data=[])
    # takes raw output from @socket.recv_strings([]) and separates routing from content
    result = {:route => [], :content => []}
    prior_element = nil
    data.to_enum(:each).each do |the_element|
      # Empty strings terminate routes -- Do NOT use in payload as parse element
      if the_element.to_s.size > 0
        if prior_element.to_s.size > 0
          result[:content] << prior_element
        end
        prior_element = the_element
      else
        if prior_element.to_s.size > 0
          result[:route] << prior_element
        end
        prior_element = nil
      end
    end
    if prior_element.to_s.size > 0
      result[:content] << prior_element
    end
    result
  end
  #
  def recv(options={:autojoin => true})
    unless options.is_a?(::Hash)
      options = {:autojoin => true}
    end
    payload = []
    # @thread_safety.lock
    status = @socket.recv_strings(payload,0)
    if ::ZMQ::Util.resultcode_ok?(status)
      data = this.triage_strings(payload)
      if (data[:route].size > 0 || data[:content].size > 0)
        if options[:autojoin]
          ::GxG::Events::Message.new({:sender => this, :body => data[:content].join(), :route => data[:route]})
        else
          ::GxG::Events::Message.new({:sender => this, :body => data[:content], :route => data[:route]})
        end
      else
        nil
      end
    else
      begin
        raise Exception, ("ZMQ - " + ::ZMQ::Util.error_string())
      rescue => the_error
        log_error({:error => the_error})
      end
      nil
    end
    # @thread_safety.unlock
  end
  #
  def send(data=nil, route=[])
    if data
      # FORNOW: use the smallest buffer size found across all bindings and/or connections
      buffer_size = @thread_safety.synchronize { @send_buffer_size }
      payload = []
      messages = []
      unless route.is_a?(::Array)
        route = [(route)]
      end
      #
      if data.is_a?(::GxG::Events::Message)
        if data.body().is_a?(::String)
          data = [(data.body())]
        else
          data = [(data.body().serialize())]
        end
      end
      if data.is_a?(::String)
        data = [(data)]
      end
      #
      if route.is_a?(::Array)
        route.flatten.to_enum(:each).each do |the_route|
          if the_route.is_a?(::String)
            payload << the_route.slice_bytes(0..255)
            payload << ""
          end
        end
      end
      payload << @socket.identity()
      payload << ""
      #
      if data.is_a?(::Array)
        data.flatten.to_enum(:each).each do |the_element|
          if the_element.is_a?(::String)
            if the_element.size > 0
              # Disallow parsing payload with empty strings : used to parse routes
              # Break into appropriate buffer size as needed : respect buffer sizes
              if the_element.bytesize > buffer_size
                length = the_element.bytesize()
                passes = ::GxG::Networking::passes_needed(length, buffer_size)
                total = (length - 1)
                starting = 0
                ending = ([length,buffer_size].min - 1)
                passes.times do
                  messages << the_element.slice_bytes(starting..ending)
                  #
                  starting = ending + 1
                  ending = (starting + (buffer_size - 1))
                  if ending > total
                    ending = ending - (ending - total)
                  end
                end
                #
              else
                messages << the_element
              end
            end
          end
        end
        if messages.size > 0
          payload << messages
          payload.flatten!
          status = @thread_safety.synchronize { @socket.send_strings(payload) }
          if status == -1
            begin
              raise Exception, "ZMQ - Message could not be enqueued."
            rescue => the_error
              log_error({:error => the_error, :parameters => {:data => data, :route => route}})
            end
          end
        end
      end
      #
    end
  end
  #
end

class ZMQRouter < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    unless settings[:context].is_a?(::ZMQ::Context)
      settings[:context] = ::GxG::Networking::zmq_context()
    end
    settings[:type] = ::ZMQ::ROUTER
    bindings = (settings.delete(:bind) || {})
    super(settings)
    unless bindings.keys.size > 0
      bindings[:inproc] = ::URI::parse("inproc://#{@name}")
    end
    this.bind(bindings)
    #
    this
  end
  #
end

class ZMQDealer < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::DEALER
    super(settings)
    #
    this
  end
  #
end

class ZMQRequest < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::REQ
    super(settings)
    #
    this
  end
  #
end

class ZMQReply < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::REP
    super(settings)
    #
    this
  end
  #
end

class ZMQPuller < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::PULL
    super(settings)
    #
    this
  end
  #
  def send(*args)
    # no-op
  end
  #
end

class ZMQPusher < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::PUSH
    super(settings)
    #
    this
  end
  #
  def recv()
    nil
  end
  #
end

class ZMQPair < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::PAIR
    super(settings)
    #
    this
  end
  #
end

class ZMQSubscriber < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::SUB
    super(settings)
    @topics = []
    #
    this
  end
  #
  def topics()
    @thread_safety.synchronize { @topics.dup }
  end
  #
  def subscribe_topic(the_topic=nil)
    the_topic = the_topic.to_s
    if the_topic.bytesize > 255
      the_topic = the_topic.slice_bytes(0..255).to_s
    end
    if the_topic.bytesize > 0
      @thread_safety.synchronize {
        unless @topics.include?(the_topic)
          @topics << the_topic
          @socket.setsockopt(::ZMQ::SUBSCRIBE,the_topic)
        end
      }
    end
  end
  #
  def unsubscribe_topic(the_topic=nil)
    the_topic = the_topic.to_s
    if the_topic.bytesize > 255
      the_topic = the_topic.slice_bytes(0..255).to_s
    end
    if the_topic.bytesize > 0
      @thread_safety.synchronize {
        if @topics.include?(the_topic)
          @topics.delete(the_topic)
          @socket.setsockopt(::ZMQ::UNSUBSCRIBE,the_topic)
        end
      }
    end
  end
  #
  def send(*args)
    # no-op
  end
  #
end

class ZMQPublisher < ::GxG::Networking::AbstractZMQSocket
  #
  def initialize(settings={})
    #
    unless settings.is_a?(::Hash)
      raise ArgumentError, "you must supply a hash of settings for the socket"
    end
    settings[:type] = ::ZMQ::PUB
    bindings = (settings.delete(:bind) || {})
    super(settings)
    unless bindings.keys.size > 0
      bindings[:inproc] = ::URI::parse("inproc://#{@name}")
    end
    this.bind(bindings)
    #
    this
  end
  #
  def recv()
    nil
  end
  #
  def publish(the_data=nil,the_topic=nil)
    if the_data
      the_topic = the_topic.to_s
      if the_topic.bytesize > 255
        the_topic = the_topic.slice_bytes(0..255).to_s
      end
      if the_topic.bytesize > 0
        this.send(the_data,[(the_topic)])
      else
        this.send(the_data)
      end
    end
  end
end

class ZMQ_RequestReplyBroker < ::GxG::Events::Actor
  # class ZMQ_RequestReplyBroker is a derivative work based upon: http://zguide.zeromq.org/rb:rrbroker Copyright (c) 2013 iMatix Corporation
  # accordingly, class ZMQ_RequestReplyBroker is licensed under this license: http://creativecommons.org/licenses/by-sa/3.0/legalcode
  def initialize(settings={})
    unless settings.is_a?(::Hash)
      raise ArgumentError, "You must provide a hash of settings for the Broker."
    end
    unless settings[:frontend].is_a?(::URI::Generic)
      raise ArgumentError, "You must provide a URI as :frontend."
    end
    unless settings[:backend].is_a?(::URI::Generic)
      raise ArgumentError, "You must provide a URI as :backend."
    end
    super()
    #
    @context = ::GxG::Networking::zmq_context()
    @frontend = ::GxG::Networking::ZMQRouter.new({:context => @context, :bind => {:frontend => settings[:frontend]}})
    @backend = ::GxG::Networking::ZMQDealer.new({:context => @context, :bind => {:backend => settings[:backend]}})
    # @queue = ::ZMQ::Device.new(::ZMQ::QUEUE, @frontend.socket(), @backend.socket())
    @queue = ::ZMQ::Poller.new
    @queue.register(@frontend.socket(), ::ZMQ::POLLIN)
    @queue.register(@backend.socket(), ::ZMQ::POLLIN)
    #
    @circulating = false
    @is_circulating = false
    @circulate_safety = ::Mutex.new
    #
    this.resume_circulating()
    ::Celluloid::current_actor()
  end
  #
  def terminate()
    this.halt_circulating()
    @queue.deregister(@frontend.socket())
    @queue.deregister(@backend.socket())
    @frontend.close()
    @backend.close()
    #
    super()
  end
  #
  def circulating?()
    @circulate_safety.synchronize { @circulating }
  end
  #
  def halt_circulating()
    @circulate_safety.synchronize { @circulating = false }
  end
  #
  def resume_circulating()
    unless this.circulating?()
      @circulate_safety.synchronize { @circulating = true }
      this.async.circulate
    end
  end
  #
  def circulate()
    # Circulate Data as required
    if this.alive?()
      front_socket = @frontend.socket()
      front_id = @frontend.identity()
      back_socket = @backend.socket()
      back_id = @frontend.identity()
      busy = @circulate_safety.synchronize { @is_circulating }
      while (this.circulating?() && !busy) do
        #
        @circulate_safety.synchronize { @is_circulating = true }
        @circulate_safety.lock
        #
        @queue.poll(:blocking)
        @queue.readables.each do |the_socket|
          if the_socket === front_socket
            data = @frontend.triage_strings(the_socket.recv_strings([]))
            payload = []
            if (data[:route].size > 0 || data[:content].size > 0)
              data[:route].to_enum(:each).each do |the_route|
                payload << the_route
                payload << ""
              end
              payload << back_id
              payload << ""
              payload << data[:content]
              payload.flatten!
              if payload.size > 0
                back_socket.send_strings(payload)
              end
            end
          end
          if the_socket === back_socket
            data = @backend.triage_strings(the_socket.recv_strings([]))
            payload = []
            if (data[:route].size > 0 || data[:content].size > 0)
              data[:route].to_enum(:each).each do |the_route|
                payload << the_route
                payload << ""
              end
              payload << front_id
              payload << ""
              payload << data[:content]
              payload.flatten!
              if payload.size > 0
                front_socket.send_strings(payload)
              end
            end
          end
        end
        #
        @circulate_safety.unlock
        @circulate_safety.synchronize { @is_circulating = false }
        busy = @circulate_safety.synchronize { @is_circulating }
        #
        if this.alive?()
          if this.circulating?()
            sleep 0.033
          end
        end
        #
      end
    end
  end
  #
end

Deprecated: completely rethink this.

Public Class Methods

new(*args) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1026
def initialize(*args)
  #
  @zmq_thread_safety = ::Mutex.new
  @zmq_processing = false
  @zmq_is_processing = false
  @zmq_processing_handler = nil
  @zmq_processing_error_handler = nil
  @zmq_inputs = {}
  @zmq_outputs = {}
  #
  self
end

Public Instance Methods

add_zmq_input(the_key=nil, the_socket=nil) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1062
def add_zmq_input(the_key=nil, the_socket=nil)
  valid = [::GxG::Networking::ZMQPair, ::GxG::Networking::ZMQPuller, ::GxG::Networking::ZMQSubscriber, ::GxG::Networking::ZMQReply, ::GxG::Networking::ZMQRequest]
  #
  unless the_key.is_a?(::Symbol)
    raise ArgumentError, "you need so supply a unique symbol key for the socket"
  end
  if (@zmq_thread_safety.synchronize { @zmq_inputs[(the_key)] })
    raise ArgumentError, "inputs already exists, you need so supply a unique symbol key for the socket"
  end
  unless the_socket.is_any?(valid)
    raise ArgumentError, "you supplied a #{the_socket.class.inspect}, you need so supply one of these as socket type: #{valid.inspect}"
  end
  @zmq_thread_safety.synchronize { @zmq_inputs[(the_key)] = the_socket }
  true
end
add_zmq_output(the_key=nil, the_socket=nil) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1100
def add_zmq_output(the_key=nil, the_socket=nil)
  valid = [::GxG::Networking::ZMQPair, ::GxG::Networking::ZMQPusher, ::GxG::Networking::ZMQPublisher, ::GxG::Networking::ZMQReply, ::GxG::Networking::ZMQRequest]
  #
  unless the_key.is_a?(::Symbol)
    raise ArgumentError, "you need so supply a unique symbol key for the socket"
  end
  if (@zmq_thread_safety.synchronize { @zmq_outputs[(the_key)] })
    raise ArgumentError, "inputs already exists, you need so supply a unique symbol key for the socket"
  end
  unless the_socket.is_any?(valid)
    raise ArgumentError, "you supplied a #{the_socket.class.inspect}, you need so supply one of these as socket type: #{valid.inspect}"
  end
  @zmq_thread_safety.synchronize { @zmq_outputs[(the_key)] = the_socket }
  true
end
halt_zmq_processing() click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1167
def halt_zmq_processing()
  @zmq_thread_safety.synchronize { @zmq_processing = false;@zmq_is_processing = false }
end
remove_zmq_input(the_key=nil) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1078
def remove_zmq_input(the_key=nil)
  #
  result = false
  the_inputs = this.zmq_inputs()
  if the_inputs[(the_key)]
    @zmq_thread_safety.synchronize { @zmq_inputs.delete(the_key) }
    result = true
  end
  result
end
remove_zmq_output(the_key=nil) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1116
def remove_zmq_output(the_key=nil)
  #
  result = false
  the_outputs = this.zmq_outputs()
  if the_outputs[(the_key)]
    @zmq_thread_safety.synchronize { @zmq_outputs.delete(the_key) }
    result = true
  end
  result
end
resume_zmq_processing() click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1171
def resume_zmq_processing()
  unless this.processing?()
    @zmq_thread_safety.synchronize { @zmq_processing = true }
    this.async.zmq_process
  end
end
terminate() click to toggle source
Calls superclass method
# File lib/gxg/gxg_zmq.rb, line 1039
def terminate()
  # Halt any zmq processing first
  this.halt_zmq_processing()
  # Remove any references to input and output sockets
  # Question: should I close all input/output sockets here???
  @zmq_thread_safety.synchronize {
    @zmq_inputs = {}
    @zmq_outputs = {}
  }
  super()
end
zmq_error_handler(params={}) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1145
def zmq_error_handler(params={})
  result = {:result => false}
  begin
    unless params.is_a?(:Hash)
      raise ArgumentError, "you must provide a Hash as parameter container"
    end
    if params[:block].respond_to(:call)
      @zmq_thread_safety.synchronize { @zmq_processing_error_handler = params[:block] }
      result[:result] = true
    else
      raise ArgumentError, "you must provide something that responds to :call with the :block parameter"
    end
  rescue Exception => the_error
    log_error({:error => the_error, :parameters => params})
  end
  result
end
zmq_handler(params={}) click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1127
def zmq_handler(params={})
  result = {:result => false}
  begin
    unless params.is_a?(:Hash)
      raise ArgumentError, "you must provide a Hash as parameter container"
    end
    if params[:block].respond_to(:call)
      @zmq_thread_safety.synchronize { @zmq_processing_handler = params[:block] }
      result[:result] = true
    else
      raise ArgumentError, "you must provide something that responds to :call with the :block parameter"
    end
  rescue Exception => the_error
    log_error({:error => the_error, :parameters => params})
  end
  result
end
zmq_inputs() click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1051
def zmq_inputs()
  result = {}
  @zmq_thread_safety.synchronize {
    @zmq_inputs.keys.to_enum(:each).each do |the_key|
      result[(the_key)] = @zmq_inputs[(the_key)]
    end
    #
  }
  result
end
zmq_outputs() click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1089
def zmq_outputs()
  result = {}
  @zmq_thread_safety.synchronize {
    @zmq_outputs.keys.to_enum(:each).each do |the_key|
      result[(the_key)] = @zmq_outputs[(the_key)]
    end
    #
  }
  result
end
zmq_process() click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1178
def zmq_process()
  # Process items on the zmq inputs and potentially send things via outputs
  while (this.zmq_processing?() && !(@zmq_thread_safety.synchronize { @zmq_is_processing })) do
    #
    @zmq_thread_safety.synchronize { @zmq_is_processing = true }
    # Process event item
    begin
      my_handler = @zmq_thread_safety.synchronize { @zmq_processing_error_handler }
      begin
        processor = @zmq_thread_safety.synchronize { @zmq_processing_handler }
        if processor.respond_to?(:call)
          processor.call(this, this.zmq_inputs(), this.zmq_outputs())
        end
      rescue Exception => the_error
        # TODO: Revise logging/error-handling system generally, after display manager construction
        this.halt_zmq_processing()
        if my_handler.respond_to?(:call)
          # error handler provided
          my_handler.call({:error => the_error})
        else
          # log error and forget about it
          log_error({:error => the_error})
        end
      end
    rescue Exception => error_handling
      log_error({:error => error_handling})
    end
    #
    @zmq_thread_safety.synchronize { @zmq_is_processing = false }
    if this.alive?()
      if this.zmq_processing?()
        sleep 0.033
      end
    end
    #
  end
  #
end
zmq_processing?() click to toggle source
# File lib/gxg/gxg_zmq.rb, line 1163
def zmq_processing?()
  @zmq_thread_safety.synchronize { @zmq_processing }
end