{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} module Data.Hadoop.Protobuf.Headers where import Data.ByteString (ByteString) import Data.Int (Int32) import Data.ProtocolBuffers import Data.ProtocolBuffers.Orphans () import Data.Text (Text) import Data.Word (Word32, Word64) import GHC.Generics (Generic) ------------------------------------------------------------------------ -- TODO From Hadoop source: -- Spec for UserInformationProto is specified in ProtoUtil#makeIpcConnectionContext -- | User information beyond what can be determined as part of the -- security handshake at connection time (kerberos, tokens, etc) data UserInformation = UserInformation { effectiveUser :: Optional 1 (Value Text) , realUser :: Optional 2 (Value Text) } deriving (Generic, Show) instance Encode UserInformation instance Decode UserInformation -- | The connection context is sent as part of the connection -- establishment. It establishes the context for ALL Rpc calls -- within the connection. data IpcConnectionContext = IpcConnectionContext { ctxUserInfo :: Optional 2 (Message UserInformation) , ctxProtocol :: Optional 3 (Value Text) -- ^ Name of the next RPC layer. } deriving (Generic, Show) instance Encode IpcConnectionContext instance Decode IpcConnectionContext ------------------------------------------------------------------------ -- | Determines the RPC Engine and the serialization of the RPC request. data RpcKind = Builtin -- ^ Used for built-in calls by tests | Writable -- ^ Use WritableRpcEngine | ProtocolBuffer -- ^ Use ProtobufRpcEngine deriving (Generic, Show, Enum) data RpcOperation = FinalPacket -- ^ The final RPC packet | ContinuationPacket -- ^ Not implemented yet | CloseConnection -- ^ Close the RPC connection deriving (Generic, Show, Enum) data RpcRequestHeader = RpcRequestHeader { reqKind :: Optional 1 (Enumeration RpcKind) , reqOp :: Optional 2 (Enumeration RpcOperation) , reqCallId :: Required 3 (Value (Signed Int32)) -- ^ Sequence number that is sent back in response , reqClientId :: Required 4 (Value ByteString) -- ^ Globally unique client ID , reqRetryCount :: Optional 5 (Value (Signed Int32)) -- ^ Retry count, 1 means this is the first retry } deriving (Generic, Show) instance Encode RpcRequestHeader instance Decode RpcRequestHeader -- | This message is the header for the Protobuf Rpc Engine -- when sending a RPC request from RPC client to the RPC server. -- The actual request (serialized as protobuf) follows this request. -- -- No special header is needed for the Rpc Response for Protobuf Rpc Engine. -- The normal RPC response header (see RpcHeader.proto) are sufficient. data RequestHeader = RequestHeader { -- | Name of the RPC method reqMethodName :: Required 1 (Value Text) -- | RPCs for a particular interface (ie protocol) are done using an IPC -- connection that is setup using rpcProxy. The rpcProxy has a declared -- protocol name that is sent from client to server at connection time. -- -- Each Rpc call also sends a protocol name (reqProtocolName). This name is -- usually the same as the connection protocol name, but not always. For example, -- meta protocols, such as ProtocolInfoProto, reuse the connection but need to -- indicate that the actual protocol is different (i.e. the protocol is -- ProtocolInfoProto) since they reuse the connection; in this case the -- protocol name is set to ProtocolInfoProto. , reqProtocolName :: Required 2 (Value Text) -- | Protocol version of class declaring the called method. , reqProtocolVersion :: Required 3 (Value Word64) } deriving (Generic, Show) instance Encode RequestHeader instance Decode RequestHeader ------------------------------------------------------------------------ -- | Success or failure. The reponse header's error detail, exception -- class name and error message contains further details on the error. data RpcStatus = Success -- ^ Succeeded | Error -- ^ Non-fatal error, connection left open | Fatal -- ^ Fatal error, connection closed deriving (Generic, Show, Eq, Enum) -- | Note that RPC response header is also used when connection setup fails. -- (i.e. the response looks like an RPC response with a fake callId) -- -- In case of Fatal error then the respose contains the Serverside's IPC version. data RpcResponseHeader = RpcResponseHeader { rspCallId :: Required 1 (Value Word32) -- ^ Call ID used in request , rspStatus :: Required 2 (Enumeration RpcStatus) , rspServerIpcVersion :: Optional 3 (Value Word32) -- ^ v7: Sent if fatal v9: Sent if success or fail , rspExceptionClassName :: Optional 4 (Value Text) -- ^ If the request fails , rspErrorMsg :: Optional 5 (Value Text) -- ^ If the request fails, often contains stack trace , rspErrorDetail :: Optional 6 (Enumeration Error) -- ^ In case of error , rspClientId :: Optional 7 (Value ByteString) -- ^ Globally unique client ID , rspRetryCount :: Optional 8 (Value Int32) } deriving (Generic, Show) instance Encode RpcResponseHeader instance Decode RpcResponseHeader -- | Describes why an RPC error occurred. data Error = ErrorApplication -- ^ RPC failed - RPC app threw exception | ErrorNoSuchMethod -- ^ RPC error - no such method | ErrorNoSuchProtocol -- ^ RPC error - no such protocol | ErrorRpcServer -- ^ RPC error on server side | ErrorSerializingResponse -- ^ Error serializing response | ErrorRpcVersionMismatch -- ^ RPC protocol version mismatch | ErrorCode Int -- ^ RPC error that we don't know about -- starts at 10 | FatalUnknown -- ^ Unknown fatal error | FatalUnsupportedSerialization -- ^ IPC layer serilization type invalid | FatalInvalidRpcHeader -- ^ Fields of RPC header are invalid | FatalDeserializingRequest -- ^ Could not deserialize RPC request | FatalVersionMismatch -- ^ IPC layer version mismatch | FatalUnauthorized -- ^ Auth failed | FatalCode Int -- ^ Fatal error that we don't know about deriving (Generic, Show) instance Enum Error where toEnum n = case n of 1 -> ErrorApplication 2 -> ErrorNoSuchMethod 3 -> ErrorNoSuchProtocol 4 -> ErrorRpcServer 5 -> ErrorSerializingResponse 6 -> ErrorRpcVersionMismatch 10 -> FatalUnknown 11 -> FatalUnsupportedSerialization 12 -> FatalInvalidRpcHeader 13 -> FatalDeserializingRequest 14 -> FatalVersionMismatch 15 -> FatalUnauthorized _ -> if n < 10 then ErrorCode n else FatalCode n fromEnum e = case e of ErrorApplication -> 1 ErrorNoSuchMethod -> 2 ErrorNoSuchProtocol -> 3 ErrorRpcServer -> 4 ErrorSerializingResponse -> 5 ErrorRpcVersionMismatch -> 6 ErrorCode n -> n FatalUnknown -> 10 FatalUnsupportedSerialization -> 11 FatalInvalidRpcHeader -> 12 FatalDeserializingRequest -> 13 FatalVersionMismatch -> 14 FatalUnauthorized -> 15 FatalCode n -> n