module Fox

Constants

Context
Poller
SockPath
VERSION

Public Class Methods

_assert(raise_p, req, *dependencies) click to toggle source

Connects to Fox server via ZeroMQ and ensures that all requested dependencies are met. If something isn't met, raises a special exception that's rescued by the main run loop and turned into an abort message.

# File lib/keminglabs-fox-rubby.rb, line 21
def self._assert(raise_p, req, *dependencies)
  deps = dependencies.flatten.uniq.compact

  return true if deps.empty?

  sock = Context.socket(ZMQ::REQ)
  sock.connect req[:socket]
  sock.send_string JSON.generate({target: req[:target], dependencies: deps})

  res = ""
  sock.recv_string res
  if (res == "fox-abort")
    if raise_p
      raise Abort
    else
      false
    end
  else
    true
  end
end
assert(req, *dependencies) click to toggle source
# File lib/keminglabs-fox-rubby.rb, line 44
def self.assert(req, *dependencies)
  self._assert true, req, dependencies
end
register(path, handler) click to toggle source
# File lib/keminglabs-fox-rubby.rb, line 49
def self.register(path, handler)
  FileUtils.mkdir_p SockPath + "/" + File.dirname(path)
  sock = Context.socket(ZMQ::ROUTER)
  sock.bind "ipc://#{SockPath}/#{path}.ipc"
  @handlers[sock] = {handler: handler, path: path}
  nil
end
start!() click to toggle source
# File lib/keminglabs-fox-rubby.rb, line 58
def self.start!
  @handlers.each do |sock, h|
    $stderr.puts "Registering handler at: #{h[:path]}"
    Poller.register_readable sock
  end

  Signal.trap("INT") do
    break
    Context.terminate
  end

  loop do
    Poller.poll(:blocking)
    Poller.readables.each do |sock|
      id, req = recv_multipart sock
      msg = begin
              parse_handler_response @handlers[sock][:handler].call(req)
            rescue Abort => _
              {exit: "abort"}
            rescue Exception => e
              $stderr.puts e
              {exit: "fail", log: e.to_s}
            end
      $stderr.puts "#{msg[:exit]}: #{req[:target]}"
      send! sock, id, msg
    end
  end
end

Private Class Methods

parse_handler_response(res) click to toggle source
# File lib/keminglabs-fox-rubby.rb, line 105
def self.parse_handler_response(res)
  case res
  when String # a successful build
    {
      exit: "succeed",
      result: res
    }

  when Array  # a successful build with log messages
    {
      exit: "succeed",
      result: res[0],
      log: res[1]
    }

  when Hash   # a full map
    if not (res.key?(:exit) or res.key?("exit"))
      throw "Response needs :exit key with value one of (:succeed, :abort, :fail)"
    end
    res
  end
end
recv_multipart(sock) click to toggle source
# File lib/keminglabs-fox-rubby.rb, line 96
def self.recv_multipart(sock)
  parts = []
  sock.recvmsgs parts
  id, _, msg = parts

  [id.copy_out_string, JSON.parse(msg.copy_out_string, symbolize_names: true)]
end
send!(sock, id, msg) click to toggle source

TODO: do I really want to make things private? This is just a documentation issue, really.

# File lib/keminglabs-fox-rubby.rb, line 92
def self.send!(sock, id, msg)
  sock.send_strings [id, "", JSON.generate(msg)]
end