mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-05-26 09:45:31 +00:00
change message envelopes and encoding, unify message delivery (#252)
* types and encodings for double ratchet integration * upgrade stack resolver * type classes for version agreement, encode/decode connection request links and E2E params with versioning * encode/decode client parameters (version and DH key) in SMP queue URI using query string parameters * restore support of the current SMP queue URI format * update AMessage to only send queues in REPLY message (not the full connection request) * new agent message evnvelopes (tests fail) * new message envelopes - tests pass * store fully encrypted messages before sending * unify message delivery via DB queue (excluding confirmation and invitation) * remove activateSecuredQueue * linter hints * remove comment * export order * save rachet-encrypted message, not per-queue encrypted * delete message after it is accepted by the server, reduce message delivery interval for the tests Co-authored-by: Efim Poberezkin <8711996+efim-poberezkin@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
e452c6ebff
commit
488398df9f
@@ -7,7 +7,12 @@
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
module Simplex.Messaging.Encoding (Encoding (..), Tail (..)) where
|
||||
module Simplex.Messaging.Encoding
|
||||
( Encoding (..),
|
||||
Tail (..),
|
||||
Large (..),
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Attoparsec.ByteString.Char8 (Parser)
|
||||
import qualified Data.Attoparsec.ByteString.Char8 as A
|
||||
@@ -16,6 +21,7 @@ import Data.ByteString.Char8 (ByteString)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.ByteString.Internal (c2w, w2c)
|
||||
import Data.Int (Int64)
|
||||
import qualified Data.List.NonEmpty as L
|
||||
import Data.Time.Clock.System (SystemTime (..))
|
||||
import Data.Word (Word16, Word32)
|
||||
import Network.Transport.Internal (decodeWord16, decodeWord32, encodeWord16, encodeWord32)
|
||||
@@ -64,15 +70,21 @@ w32P = fromIntegral <$> smpP @Word32
|
||||
|
||||
-- ByteStrings are assumed no longer than 255 bytes
|
||||
instance Encoding ByteString where
|
||||
smpEncode s = B.cons (w2c len) s where len = fromIntegral $ B.length s
|
||||
smpP = A.take . fromIntegral . c2w =<< A.anyChar
|
||||
smpEncode s = B.cons (lenEncode $ B.length s) s
|
||||
smpP = A.take =<< lenP
|
||||
|
||||
lenEncode :: Int -> Char
|
||||
lenEncode = w2c . fromIntegral
|
||||
|
||||
lenP :: Parser Int
|
||||
lenP = fromIntegral . c2w <$> A.anyChar
|
||||
|
||||
instance Encoding a => Encoding (Maybe a) where
|
||||
smpEncode s = maybe "\0" (("\1" <>) . smpEncode) s
|
||||
smpEncode s = maybe "0" (("1" <>) . smpEncode) s
|
||||
smpP =
|
||||
smpP >>= \case
|
||||
'\0' -> pure Nothing
|
||||
'\1' -> Just <$> smpP
|
||||
'0' -> pure Nothing
|
||||
'1' -> Just <$> smpP
|
||||
_ -> fail "invalid Maybe tag"
|
||||
|
||||
newtype Tail = Tail {unTail :: ByteString}
|
||||
@@ -81,6 +93,15 @@ instance Encoding Tail where
|
||||
smpEncode = unTail
|
||||
smpP = Tail <$> A.takeByteString
|
||||
|
||||
-- newtype for encoding/decoding ByteStrings over 255 bytes with 2-bytes length prefix
|
||||
newtype Large = Large {unLarge :: ByteString}
|
||||
|
||||
instance Encoding Large where
|
||||
smpEncode (Large s) = smpEncode @Word16 (fromIntegral $ B.length s) <> s
|
||||
smpP = do
|
||||
len <- fromIntegral <$> smpP @Word16
|
||||
Large <$> A.take len
|
||||
|
||||
instance Encoding SystemTime where
|
||||
smpEncode = smpEncode . systemSeconds
|
||||
smpP = MkSystemTime <$> smpP <*> pure 0
|
||||
@@ -89,6 +110,18 @@ instance (Encoding a, Encoding b) => Encoding (a, b) where
|
||||
smpEncode (a, b) = smpEncode a <> smpEncode b
|
||||
smpP = (,) <$> smpP <*> smpP
|
||||
|
||||
-- lists encode/parse as a sequence of items prefixed with list length (as 1 byte)
|
||||
instance Encoding a => Encoding [a] where
|
||||
smpEncode xs = B.cons (lenEncode $ length xs) . B.concat $ map smpEncode xs
|
||||
smpP = (`A.count` smpP) =<< lenP
|
||||
|
||||
instance Encoding a => Encoding (L.NonEmpty a) where
|
||||
smpEncode = smpEncode . L.toList
|
||||
smpP =
|
||||
lenP >>= \case
|
||||
0 -> fail "empty list"
|
||||
n -> L.fromList <$> A.count n smpP
|
||||
|
||||
instance (Encoding a, Encoding b, Encoding c) => Encoding (a, b, c) where
|
||||
smpEncode (a, b, c) = smpEncode a <> smpEncode b <> smpEncode c
|
||||
smpP = (,,) <$> smpP <*> smpP <*> smpP
|
||||
|
||||
Reference in New Issue
Block a user