natskell-0.3.0.0: internal/Types/Pub.hs
{-# LANGUAGE OverloadedStrings #-}
module Types.Pub where
import Data.ByteString hiding (foldr, map)
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Lazy as LBS
import Data.Maybe
import Prelude hiding (concat, length, null)
import Transformers.Transformers (Transformer (..))
import Types.Msg (Headers, Payload, Subject)
import Validators.Validators
data Pub = Pub
{ subject :: Subject
, replyTo :: Maybe Subject
, headers :: Maybe Headers
, payload :: Maybe Payload
}
deriving (Eq, Show)
instance Transformer Pub where
transform pubMsg =
case headers pubMsg of
Nothing ->
let payload' = payloadChunk (payload pubMsg)
payloadLen = length payload'
control = concat
(["PUB ", subject pubMsg, " "] ++ replyChunks (replyTo pubMsg)
++ [packInt payloadLen, "\r\n"])
in LBS.fromChunks [control, payload', "\r\n"]
Just headerList ->
let headers' = headerString headerList
headerLength = length headers'
payload' = payloadChunk (payload pubMsg)
totalLen = headerLength + length payload'
control = concat
(["HPUB ", subject pubMsg, " "] ++ replyChunks (replyTo pubMsg)
++ [packInt headerLength, " ", packInt totalLen, "\r\n"])
in LBS.fromChunks [control, headers', payload', "\r\n"]
instance Validator Pub where
validate p = do
validateSubject p
validateReplyTo p
validatePayload p
validateHeaders p
validateSubject :: Pub -> Either ByteString ()
validateSubject p
| subject p == "" = Left "explicit empty subject"
| otherwise = validateSubjectSyntax (subject p)
validateReplyTo :: Pub -> Either ByteString ()
validateReplyTo p
| replyTo p == Just "" = Left "explicit empty replyTo"
| otherwise = maybe (Right ()) validateSubjectSyntax (replyTo p)
validatePayload :: Pub -> Either ByteString ()
validatePayload p
| payload p == Just "" = Left "explicit empty payload"
| otherwise = Right ()
validateHeaders :: Pub -> Either ByteString ()
validateHeaders p
| isNothing (headers p) = Right ()
| headers p == Just [] = Left "explicit empty headers"
| Prelude.any (\(k, _) -> k == "") (fromJust (headers p)) = Left "explicit empty header key"
| Prelude.any (\(_, v) -> v == "") (fromJust (headers p)) = Left "explicit empty header value"
| otherwise = do
mapM_ (validateHeaderKeySyntax . fst) (fromJust (headers p))
mapM_ (validateHeaderValueSyntax . snd) (fromJust (headers p))
messageSize :: Pub -> Int
messageSize pubMsg =
case headers pubMsg of
Nothing ->
length (payloadChunk (payload pubMsg))
Just headerList ->
length (headerString headerList) + length (payloadChunk (payload pubMsg))
headerString :: Headers -> ByteString
headerString hs =
concat ("NATS/1.0\r\n" : foldr appendHeader ["\r\n"] hs)
where
appendHeader (key, value) acc = key : ":" : value : "\r\n" : acc
payloadChunk :: Maybe Payload -> Payload
payloadChunk = fromMaybe empty
replyChunks :: Maybe Subject -> [ByteString]
replyChunks = maybe [] (\reply -> [reply, " "])
packInt :: Int -> ByteString
packInt = BC.pack . show