# # MessagePack-RPC for Ruby # # Copyright (C) 2010-2011 FURUHASHI Sadayuki # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module MessagePack module RPC class Error < StandardError end ## ## MessagePack-RPC Exception ## # # RPCError # | # +-- TimeoutError # | # +-- TransportError # | | # | +-- NetworkUnreachableError # | | # | +-- ConnectionRefusedError # | | # | +-- ConnectionTimeoutError # | | # | +-- MalformedMessageError # | | # | +-- StreamClosedError # | # +-- CallError # | | # | +-- NoMethodError # | | # | +-- ArgumentError # | # +-- ServerError # | | # | +-- ServerBusyError # | # +-- RemoteError # | # +-- RuntimeError # | # +-- (user-defined errors) class RPCError < Error def initialize(code, *data) @code = code.to_s @data = data super(@data.shift || @code) end attr_reader :code attr_reader :data def is?(code) if code.is_a?(Class) && code < RPCError if code == RemoteError return @code[0] != ?. end code = code::CODE end @code == code || @code[0,code.length+1] == "#{code}." end end ## # Top Level Errors # class TimeoutError < RPCError CODE = ".TimeoutError" def initialize(msg) super(self.class::CODE, msg) end end class TransportError < RPCError CODE = ".TransportError" def initialize(msg) super(self.class::CODE, msg) end end class CallError < RPCError CODE = ".CallError" def initialize(msg) super(self.class::CODE, msg) end end class ServerError < RPCError CODE = ".ServerError" def initialize(msg) super(self.class::CODE, msg) end end class RemoteError < RPCError CODE = "" def initialize(code, *data) super(code, *data) end end ## # TransportError # class NetworkUnreachableError < TransportError CODE = ".TransportError.NetworkUnreachableError" end class ConnectionRefusedError < TransportError CODE = ".TransportError.ConnectionRefusedError" end class ConnectionTimeoutError < TransportError CODE = ".TransportError.ConnectionTimeoutError" end class MalformedMessageError < TransportError CODE = ".TransportError.ConnectionRefusedError" end class StreamClosedError < TransportError CODE = ".TransportError.StreamClosedError" end ## # CallError # class NoMethodError < CallError CODE = ".CallError.NoMethodError" end class ArgumentError < CallError CODE = ".CallError.ArgumentError" end ## # ServerError # class ServerBusyError < ServerError CODE = ".ServerError.ServerBusyError" end ## # RuntimeError # class RuntimeError < RemoteError CODE = ".RuntimeError" def initialize(msg, *data) super("RuntimeError", msg, *data) end end class RPCError def self.create(code, data) if code[0] == ?. code = code.dup while true if klass = SYSTEM_ERROR_TABLE[code] return klass.new(*data) end if code.slice!(/\.[^\.]*$/) == nil || code.empty? return RPCError.new(code, *data) end end elsif code == RuntimeError::CODE RuntimeError.new(*data) else RemoteError.new(code, *data) end end private SYSTEM_ERROR_TABLE = { TimeoutError::CODE => TimeoutError, TransportError::CODE => TransportError, CallError::CODE => CallError, ServerError::CODE => ServerError, NetworkUnreachableError::CODE => NetworkUnreachableError, ConnectionRefusedError::CODE => ConnectionRefusedError, ConnectionTimeoutError::CODE => ConnectionTimeoutError, MalformedMessageError::CODE => MalformedMessageError, StreamClosedError::CODE => StreamClosedError, NoMethodError::CODE => NoMethodError, ArgumentError::CODE => ArgumentError, ServerBusyError::CODE => ServerBusyError, } end end end