lib/marilyn-rpc/mails.rb in marilyn-rpc-0.0.3 vs lib/marilyn-rpc/mails.rb in marilyn-rpc-0.0.4
- old
+ new
@@ -1,101 +1,86 @@
module MarilynRPC
# Helper that gets mixed into the mail classes to make common things easyer
module MailHelper
- # generate a new serialize id which can be used in a mail
- # @param [Integer] a number between 0 and 254
- # @param [String] returns an 1 byte string as type id
- def self.type(nr)
- [nr].pack("c")
- end
-
- # extracts the real data and ignores the type information
- # @param [String] data the data to extract the mail from
- # @return [String] the extracted data
- def only_data(data)
- data.slice(1, data.size)
- end
-
- # serialize the data using marilyns default serializer
- # @param [Object] data the data to encode
- # @param [String] the serialized data
- def serialize(data)
- Marshal.dump(data)
- end
-
- # deserializes the passed data to the original objects
- # @param [String] data the serialized data
- # @return [Object] the deserialized object
- def deserialize(data)
- Marshal.load(data)
- end
+ SERIALIZER = Marshal
end
class CallRequestMail < Struct.new(:tag, :path, :method, :args)
include MarilynRPC::MailHelper
- TYPE = MarilynRPC::MailHelper.type(1)
+ TYPE = 1
def encode
- TYPE + serialize([self.tag, self.path, self.method, self.args])
+ SERIALIZER.dump([self.tag, self.path, self.method, self.args])
end
def decode(data)
- self.tag, self.path, self.method, self.args = deserialize(only_data(data))
+ self.tag, self.path, self.method, self.args = SERIALIZER.load(data)
end
end
class CallResponseMail < Struct.new(:tag, :result)
include MarilynRPC::MailHelper
- TYPE = MarilynRPC::MailHelper.type(2)
+ TYPE = 2
def encode
- TYPE + serialize([self.tag, self.result])
+ SERIALIZER.dump([self.tag, self.result])
end
def decode(data)
- self.tag, self.result = deserialize(only_data(data))
+ self.tag, self.result = SERIALIZER.load(data)
end
end
class ExceptionMail < Struct.new(:tag, :exception)
include MarilynRPC::MailHelper
- TYPE = MarilynRPC::MailHelper.type(3)
+ TYPE = 3
def encode
- TYPE + serialize([self.tag, self.exception])
+ SERIALIZER.dump([self.tag, self.exception])
end
def decode(data)
- self.tag, self.exception = deserialize(only_data(data))
+ self.tag, self.exception = SERIALIZER.load(data)
end
end
# Helper to destiguish between the different mails
module MailFactory
+ include MarilynRPC::MailHelper
+
+ # table which contains all types that can be unpacked
+ TYPE_LOOK_UP = {
+ MarilynRPC::CallRequestMail::TYPE => MarilynRPC::CallRequestMail,
+ MarilynRPC::CallResponseMail::TYPE => MarilynRPC::CallResponseMail,
+ MarilynRPC::ExceptionMail::TYPE => MarilynRPC::ExceptionMail
+ }
+
# Parses the envelop and generate the correct mail.
# @param [MarilynRPC::Envelope] envelope the envelope which contains a mail
# @return [MarilynRPC::CallRequestMail, MarilynRPC::CallResponseMail,
# MarilynRPC::ExceptionMail] the mail object that was extracted
- def self.unpack(envelope)
- data = envelope.content
- type = data.slice(0, 1)
- case type
- when MarilynRPC::CallRequestMail::TYPE
- mail = MarilynRPC::CallRequestMail.new
- when MarilynRPC::CallResponseMail::TYPE
- mail = MarilynRPC::CallResponseMail.new
- when MarilynRPC::ExceptionMail::TYPE
- mail = MarilynRPC::ExceptionMail.new
- else
- raise MarilynRPC::BrokenEnvelopeError.new("The passed envelope is broken!")
- end
- mail.decode(data)
- mail
+ def self.unpack(envelope)
+ if mail_klass = TYPE_LOOK_UP[envelope.type]
+ mail = mail_klass.new(*SERIALIZER.load(envelope.content))
+ else
+ raise MarilynRPC::BrokenEnvelopeError.new \
+ "The passed envelope is broken, no (correct) type!"
+ end
end
- # builds the binary data for a method call
- def self.build_call(tag, path, method_name, args)
- mail = MarilynRPC::CallRequestMail.new(tag, path, method_name, args)
- MarilynRPC::Envelope.new(mail.encode).encode
+ # builds the binary data for a method call, it inlines some of the packing
+ # for performance critical applications.
+ # @param [Object] tag the tag for the object is relevate for multuplexing,
+ # it should be unique on a per conncetion base
+ # @param [Object] path the path to identifiy the service
+ # @param [Symbol, String] method the method name to call on the service
+ # @param [Array<Object>] args the arguments that are passed to the remote
+ # side
+ # @return [Object] the result of the call
+ def self.build_call(tag, path, method, args)
+ data = MarilynRPC::MailHelper::SERIALIZER.dump([tag, path, method, args])
+ [
+ data.size, MarilynRPC::CallRequestMail::TYPE
+ ].pack(MarilynRPC::Envelope::HEADER_ENCODING) + data
end
end
end