lib/ernie.rb in ernie-1.0.0 vs lib/ernie.rb in ernie-1.1.0
- old
+ new
@@ -9,79 +9,144 @@
self.mods = {}
self.current_mod = nil
self.logger = nil
+ # Record a module.
+ # +name+ is the module Symbol
+ # +block+ is the Block containing function definitions
+ #
+ # Returns nothing
def self.mod(name, block)
m = Mod.new(name)
self.current_mod = m
self.mods[name] = m
block.call
end
+ # Record a function.
+ # +name+ is the function Symbol
+ # +block+ is the Block to associate
+ #
+ # Returns nothing
def self.fun(name, block)
self.current_mod.fun(name, block)
end
+ # Set the logfile to given path.
+ # +file+ is the String path to the logfile
+ #
+ # Returns nothing
def self.logfile(file)
self.logger = Logger.new(file)
end
+ # If logging is enabled, log the given text.
+ # +text+ is the String to log
+ #
+ # Returns nothing
def self.log(text)
self.logger.info(text) if self.logger
end
+ # Dispatch the request to the proper mod:fun.
+ # +mod+ is the module Symbol
+ # +fun+ is the function Symbol
+ # +args+ is the Array of arguments
+ #
+ # Returns the Ruby object response
def self.dispatch(mod, fun, args)
- xargs = BERT::Decoder.convert(args)
- self.log("-- " + [mod, fun, xargs].inspect)
self.mods[mod] || raise(ServerError.new("No such module '#{mod}'"))
self.mods[mod].funs[fun] || raise(ServerError.new("No such function '#{mod}:#{fun}'"))
- res = self.mods[mod].funs[fun].call(*xargs)
- BERT::Encoder.convert(res)
+ self.mods[mod].funs[fun].call(*args)
end
+ # Read the length header from the wire.
+ # +input+ is the IO from which to read
+ #
+ # Returns the size Integer if one was read
+ # Returns nil otherwise
+ def self.read_4(input)
+ raw = input.read(4)
+ return nil unless raw
+ raw.unpack('N').first
+ end
+
+ # Read a BERP from the wire and decode it to a Ruby object.
+ # +input+ is the IO from which to read
+ #
+ # Returns a Ruby object if one could be read
+ # Returns nil otherwise
+ def self.read_berp(input)
+ packet_size = self.read_4(input)
+ return nil unless packet_size
+ bert = input.read(packet_size)
+ BERT.decode(bert)
+ end
+
+ # Write the given Ruby object to the wire as a BERP.
+ # +output+ is the IO on which to write
+ # +ruby+ is the Ruby object to encode
+ #
+ # Returns nothing
+ def self.write_berp(output, ruby)
+ data = BERT.encode(ruby)
+ output.write([data.length].pack("N"))
+ output.write(data)
+ end
+
+ # Start the processing loop.
+ #
+ # Loops forever
def self.start
self.log("Starting")
self.log(self.mods.inspect)
- receive do |f|
- f.when([:call, Symbol, Symbol, Array]) do |mod, fun, args|
- self.log("-> " + [:call, mod, fun, args].inspect)
+
+ input = IO.new(3)
+ output = IO.new(4)
+ input.sync = true
+ output.sync = true
+
+ loop do
+ iruby = self.read_berp(input)
+ unless iruby
+ puts "Could not read BERP length header. Ernie server may have gone away. Exiting now."
+ exit!
+ end
+
+ if iruby.size == 4 && iruby[0] == :call
+ mod, fun, args = iruby[1..3]
+ self.log("-> " + iruby.inspect)
begin
res = self.dispatch(mod, fun, args)
- xres = [:reply, res]
- self.log("<- " + xres.inspect)
- f.send!(xres)
+ oruby = t[:reply, res]
+ self.log("<- " + oruby.inspect)
+ write_berp(output, oruby)
rescue ServerError => e
- xres = [:error, [:server, 0, e.class.to_s, e.message, e.backtrace]]
- self.log("<- " + xres.inspect)
+ oruby = t[:error, t[:server, 0, e.class.to_s, e.message, e.backtrace]]
+ self.log("<- " + oruby.inspect)
self.log(e.backtrace.join("\n"))
- f.send!(xres)
+ write_berp(output, oruby)
rescue Object => e
- xres = [:error, [:user, 0, e.class.to_s, e.message, e.backtrace]]
- self.log("<- " + xres.inspect)
+ oruby = t[:error, t[:user, 0, e.class.to_s, e.message, e.backtrace]]
+ self.log("<- " + oruby.inspect)
self.log(e.backtrace.join("\n"))
- f.send!(xres)
+ write_berp(output, oruby)
end
- f.receive_loop
- end
-
- f.when([:cast, Symbol, Symbol, Array]) do |mod, fun, args|
+ elsif iruby.size == 4 && iruby[0] == :cast
+ mod, fun, args = iruby[1..3]
self.log("-> " + [:cast, mod, fun, args].inspect)
begin
self.dispatch(mod, fun, args)
rescue Object => e
# ignore
end
- f.send!([:noreply])
- f.receive_loop
- end
-
- f.when(Any) do |any|
- self.log("-> " + any.inspect)
- xres = [:error, [:server, 0, "Invalid request: #{any.inspect}"]]
- self.log("<- " + xres.inspect)
- f.send!(xres)
- f.receive_loop
+ write_berp(output, t[:noreply])
+ else
+ self.log("-> " + iruby.inspect)
+ oruby = t[:error, t[:server, 0, "Invalid request: #{iruby.inspect}"]]
+ self.log("<- " + oruby.inspect)
+ write_berp(output, oruby)
end
end
end
end
\ No newline at end of file