module Vaultaire.Types.ReadRequest
(
ReadRequest(..),
) where
import Control.Applicative
import Control.Exception
import Data.ByteString (ByteString)
import qualified Data.ByteString as S
import Data.Packer (getBytes, getWord64LE, getWord8, putBytes, putWord64LE,
putWord8, runPacking, tryUnpacking)
import Data.Word (Word8)
import Test.QuickCheck
import Text.Printf
import Vaultaire.Classes.WireFormat
import Vaultaire.Types.Address
import Vaultaire.Types.TimeStamp
data ReadRequest = SimpleReadRequest Address TimeStamp TimeStamp
| ExtendedReadRequest Address TimeStamp TimeStamp
deriving (Eq)
instance Show ReadRequest where
show (SimpleReadRequest addr start end) = show addr ++ " (s) " ++ format start ++ " to " ++ format end
show (ExtendedReadRequest addr start end) = show addr ++ " (e) " ++ format start ++ " to " ++ format end
format :: TimeStamp -> String
format (TimeStamp t) = printf "%010d" (t `div` 1000000000)
instance WireFormat ReadRequest where
toWire (SimpleReadRequest addr start end) =
packWithHeaderByte 0 addr start end
toWire (ExtendedReadRequest addr start end) =
packWithHeaderByte 1 addr start end
fromWire bs
| S.length bs /= 25 = Left . SomeException $ userError "expected 25 bytes"
| otherwise = flip tryUnpacking bs $ do
header <- getWord8
addr_bytes <- getBytes 8
addr <- either (fail . show) return $ fromWire addr_bytes
start <- TimeStamp <$> getWord64LE
end <- TimeStamp <$> getWord64LE
case header of
0 -> return $ SimpleReadRequest addr start end
1 -> return $ ExtendedReadRequest addr start end
_ -> fail "invalid header byte"
packWithHeaderByte :: Word8 -> Address -> TimeStamp -> TimeStamp -> ByteString
packWithHeaderByte header addr start end =
let addr_bytes = toWire addr
in runPacking 25 $ do
putWord8 header
putBytes addr_bytes
putWord64LE (unTimeStamp start)
putWord64LE (unTimeStamp end)
instance Arbitrary ReadRequest where
arbitrary =
oneof [ SimpleReadRequest <$> arbitrary <*> arbitrary <*> arbitrary
, ExtendedReadRequest <$> arbitrary <*> arbitrary <*> arbitrary ]