memcache-0.0.0: Database/Memcache/Types.hs
{-# LANGUAGE DeriveDataTypeable #-}
-- | Stores the various types needed by memcache. Mostly concerned with the
-- representation of the protocol.
module Database.Memcache.Types (
Q(..), K(..), Key, Value, Extras, Initial, Delta, Expiration, Flags, Version,
mEMCACHE_HEADER_SIZE, Header(..),
Request(..), OpRequest(..), SESet(..), SEIncr(..), SETouch(..), emptyReq,
Response(..), OpResponse(..), Status(..),
ProtocolError(..), IncorrectResponse(..)
) where
import Control.Exception
import Data.ByteString (ByteString)
import Data.Typeable
import Data.Word
{- MEMCACHE MESSAGE:
header {
magic :: Word8
op :: Word8
keyLen :: Word16
extraLen :: Word8
datatype :: Word8
status / reserved :: Word16
bodyLen :: Word32 (total body length)
opaque :: Word32
cas :: Word64
}
extras :: ByteString
key :: ByteString
value :: ByteString
-}
mEMCACHE_HEADER_SIZE :: Int
mEMCACHE_HEADER_SIZE = 24
data Q = Loud | Quiet deriving (Eq, Show, Typeable)
data K = NoKey | IncludeKey deriving (Eq, Show, Typeable)
type Key = ByteString
type Value = ByteString
type Extras = ByteString
type Initial = Word64
type Delta = Word64
type Expiration = Word32
type Flags = Word32
type Version = Word64
-- XXX: Which ones care about version? (Encode?)
data OpRequest
= ReqGet Q K Key
| ReqSet Q Key Value SESet
| ReqAdd Q Key Value SESet
| ReqReplace Q Key Value SESet
| ReqDelete Q Key
| ReqIncrement Q Key SEIncr
| ReqDecrement Q Key SEIncr
| ReqAppend Q Key Value
| ReqPrepend Q Key Value
| ReqTouch Key SETouch
| ReqGAT Q K Key SETouch
| ReqFlush Q (Maybe SETouch)
| ReqNoop
| ReqVersion
| ReqStat (Maybe Key)
| ReqQuit Q
| ReqSASLList
| ReqSASLStart Key Value -- key: auth method, value: auth data
| ReqSASLStep Key Value -- key: auth method, value: auth data (continued)
deriving (Eq, Show, Typeable)
data SESet = SESet Flags Expiration deriving (Eq, Show, Typeable)
data SEIncr = SEIncr Initial Delta Expiration deriving (Eq, Show, Typeable)
data SETouch = SETouch Expiration deriving (Eq, Show, Typeable)
data Request = Req {
reqOp :: OpRequest,
reqOpaque :: Word32,
reqCas :: Version
} deriving (Eq, Show, Typeable)
emptyReq :: Request
emptyReq = Req { reqOp = ReqNoop, reqOpaque = 0, reqCas = 0 }
data OpResponse
= ResGet Q Value Flags
| ResGetK Q Key Value Flags
| ResSet Q
| ResAdd Q
| ResReplace Q
| ResDelete Q
| ResIncrement Q Word64
| ResDecrement Q Word64
| ResAppend Q
| ResPrepend Q
| ResTouch
| ResGAT Q Value Flags
| ResGATK Q Key Value Flags
| ResFlush Q
| ResNoop
| ResVersion Value
| ResStat Key Value
| ResQuit Q
| ResSASLList Value
| ResSASLStart
| ResSASLStep
deriving (Eq, Show, Typeable)
data Status
= NoError -- All
| ErrKeyNotFound -- Get, GAT, Touch, Replace, Del, Inc, Dec, App, Pre, Set (key not there and version specified...)
| ErrKeyExists -- Add, (version): Set, Rep, Del, Inc, Dec, App, Pre
| ErrValueTooLarge -- Set, Add, Rep, Pre, App
| ErrInvalidArgs -- All
| ErrItemNotStored -- ?
| ErrValueNonNumeric -- Incr, Decr
| ErrUnknownCommand -- All
| ErrOutOfMemory -- All
| SaslAuthFail -- SASL
| SaslAuthContinue -- SASL
deriving (Eq, Show, Typeable)
data Response = Res {
resOp :: OpResponse,
resStatus :: Status,
resOpaque :: Word32,
resCas :: Version
} deriving (Eq, Show, Typeable)
data Header = Header {
op :: Word8,
keyLen :: Word16,
extraLen :: Word8,
status :: Status,
bodyLen :: Word32,
opaque :: Word32,
cas :: Version
} deriving (Eq, Show, Typeable)
data ProtocolError = ProtocolError {
protocolMessage :: String,
protocolHeader :: Maybe Header,
protocolParams :: [String]
} deriving (Eq, Show, Typeable)
instance Exception ProtocolError
data IncorrectResponse = IncorrectResponse {
increspMessage :: String,
increspActual :: Response
} deriving (Eq, Show, Typeable)
instance Exception IncorrectResponse