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