lib/bertrem/server.rb in bertrem-0.0.4 vs lib/bertrem/server.rb in bertrem-0.0.6
- old
+ new
@@ -3,26 +3,26 @@
require 'eventmachine'
module BERTREM
class Server < EventMachine::Connection
include BERTRPC::Encodes
-
+
# This class derived from Ernie/ernie.rb
-
+
class << self
attr_accessor :mods, :current_mod, :log
end
-
+
self.mods = {}
self.current_mod = nil
self.log = Logger.new(STDOUT)
self.log.level = Logger::INFO
-
+
def self.start(host, port)
EM.start_server(host, port, self)
end
-
+
# Record a module.
# +name+ is the module Symbol
# +block+ is the Block containing function definitions
#
# Returns nothing
@@ -71,11 +71,11 @@
#
# Returns nothing
def self.loglevel(level)
self.log.level = level
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
#
@@ -94,71 +94,87 @@
def write_berp(ruby)
data = BERT.encode(ruby)
send_data([data.length].pack("N"))
send_data(data)
end
-
+
def post_init
+ @receive_buf = ""; @receive_len = 0; @more = false
Server.log.info("(#{Process.pid}) Starting")
- Server.log.debug(Server.mods.inspect)
+ Server.log.debug(Server.mods.inspect)
end
-
+
# Receive data on the connection.
#
- def receive_data(data)
- # This needs to be much more intelligent (retain a buffer, append new request data
- # to the buffer, remember the length of the msg it is working with if it is incomplete,
- # etc.)
- while data.length > 4 do
- raw = data.slice!(0..3)
- puts "Could not find BERP length header. Weird, huh?" unless raw
- packet_size = raw.unpack('N').first
- puts "Could not understand BERP packet length. What gives?" unless packet_size
- bert = data.slice!(0..(packet_size - 1))
- iruby = BERT.decode(bert)
-
- unless iruby
- Server.log.info("(#{Process.pid}) No Ruby in this here packet. On to the next one...")
- next
- end
+ def receive_data(bert_request)
+ @receive_buf << bert_request
- if iruby.size == 4 && iruby[0] == :call
- mod, fun, args = iruby[1..3]
- Server.log.info("-> " + iruby.inspect)
+ while @receive_buf.length > 0 do
+ unless @more
begin
- res = Server.dispatch(mod, fun, args)
- oruby = t[:reply, res]
- Server.log.debug("<- " + oruby.inspect)
- write_berp(oruby)
- rescue ServerError => e
- oruby = t[:error, t[:server, 0, e.class.to_s, e.message, e.backtrace]]
+ if @receive_buf.length > 4
+ @receive_len = @receive_buf.slice!(0..3).unpack('N').first if @receive_len == 0
+ raise BERTRPC::ProtocolError.new(BERTRPC::ProtocolError::NO_DATA) unless @receive_buf.length > 0
+ else
+ raise BERTRPC::ProtocolError.new(BERTRPC::ProtocolError::NO_HEADER)
+ end
+ rescue Exception => e
+ log "Bad BERT message: #{e.message}"
+ return
+ end
+ end
+
+ if @receive_buf.length >= @receive_len
+ bert = @receive_buf.slice!(0..(@receive_len - 1))
+ @receive_len = 0; @more = false
+ iruby = BERT.decode(bert)
+
+ unless iruby
+ Server.log.info("(#{Process.pid}) No Ruby in this here packet. On to the next one...")
+ next
+ end
+
+ if iruby.size == 4 && iruby[0] == :call
+ mod, fun, args = iruby[1..3]
+ Server.log.info("-> " + iruby.inspect)
+ begin
+ res = Server.dispatch(mod, fun, args)
+ oruby = t[:reply, res]
+ Server.log.debug("<- " + oruby.inspect)
+ write_berp(oruby)
+ rescue ServerError => e
+ oruby = t[:error, t[:server, 0, e.class.to_s, e.message, e.backtrace]]
+ Server.log.error("<- " + oruby.inspect)
+ Server.log.error(e.backtrace.join("\n"))
+ write_berp(oruby)
+ rescue Object => e
+ oruby = t[:error, t[:user, 0, e.class.to_s, e.message, e.backtrace]]
+ Server.log.error("<- " + oruby.inspect)
+ Server.log.error(e.backtrace.join("\n"))
+ write_berp(oruby)
+ end
+ elsif iruby.size == 4 && iruby[0] == :cast
+ mod, fun, args = iruby[1..3]
+ Server.log.info("-> " + [:cast, mod, fun, args].inspect)
+ begin
+ Server.dispatch(mod, fun, args)
+ rescue Object => e
+ # ignore
+ end
+ write_berp(t[:noreply])
+ else
+ Server.log.error("-> " + iruby.inspect)
+ oruby = t[:error, t[:server, 0, "Invalid request: #{iruby.inspect}"]]
Server.log.error("<- " + oruby.inspect)
- Server.log.error(e.backtrace.join("\n"))
write_berp(oruby)
- rescue Object => e
- oruby = t[:error, t[:user, 0, e.class.to_s, e.message, e.backtrace]]
- Server.log.error("<- " + oruby.inspect)
- Server.log.error(e.backtrace.join("\n"))
- write_berp(oruby)
end
- elsif iruby.size == 4 && iruby[0] == :cast
- mod, fun, args = iruby[1..3]
- Server.log.info("-> " + [:cast, mod, fun, args].inspect)
- begin
- Server.dispatch(mod, fun, args)
- rescue Object => e
- # ignore
- end
- write_berp(t[:noreply])
else
- Server.log.error("-> " + iruby.inspect)
- oruby = t[:error, t[:server, 0, "Invalid request: #{iruby.inspect}"]]
- Server.log.error("<- " + oruby.inspect)
- write_berp(oruby)
+ @more = true
+ break
end
end
end
end
-
+
end
class BERTREM::ServerError < StandardError; end