module Network.LibP2P.MultistreamSelect.Wire
( encodeMessage
, decodeMessage
, multistreamHeader
, naMessage
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Text (Text)
import qualified Data.Text.Encoding as TE
import Network.LibP2P.Core.Varint (decodeUvarint, encodeUvarint)
multistreamHeader :: Text
= Text
"/multistream/1.0.0"
naMessage :: Text
naMessage :: Text
naMessage = Text
"na"
encodeMessage :: Text -> ByteString
encodeMessage :: Text -> ByteString
encodeMessage Text
msg =
let payload :: ByteString
payload = Text -> ByteString
TE.encodeUtf8 Text
msg ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word8 -> ByteString
BS.singleton Word8
0x0a
len :: Word64
len = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
payload)
in Word64 -> ByteString
encodeUvarint Word64
len ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
payload
decodeMessage :: ByteString -> Either String (Text, ByteString)
decodeMessage :: ByteString -> Either String (Text, ByteString)
decodeMessage ByteString
bs = do
(len, rest1) <- ByteString -> Either String (Word64, ByteString)
decodeUvarint ByteString
bs
let msgLen = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
len :: Int
if BS.length rest1 < msgLen
then Left "decodeMessage: not enough bytes"
else
let (payload, rest2) = BS.splitAt msgLen rest1
in if BS.null payload || BS.last payload /= 0x0a
then Left "decodeMessage: message does not end with newline"
else
case TE.decodeUtf8' (BS.init payload) of
Left UnicodeException
err -> String -> Either String (Text, ByteString)
forall a b. a -> Either a b
Left (String -> Either String (Text, ByteString))
-> String -> Either String (Text, ByteString)
forall a b. (a -> b) -> a -> b
$ String
"decodeMessage: invalid UTF-8: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> UnicodeException -> String
forall a. Show a => a -> String
show UnicodeException
err
Right Text
text -> (Text, ByteString) -> Either String (Text, ByteString)
forall a b. b -> Either a b
Right (Text
text, ByteString
rest2)
where