summaryrefslogtreecommitdiff
path: root/src/Data
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-11-17 03:09:48 -0500
committerJoe Crayne <joe@jerkface.net>2018-12-16 14:08:26 -0500
commitc1d01920220bcab32b5a77c0b25e65518e8d90d4 (patch)
treeff5cd9038867c121eda89229440e881eca132fa3 /src/Data
parent18dd982102ad8cb46c75897cec10483621f38dfc (diff)
dependent-sum based CryptoMessage.
Diffstat (limited to 'src/Data')
-rw-r--r--src/Data/Tox/Message.hs3
-rw-r--r--src/Data/Tox/Msg.hs231
2 files changed, 233 insertions, 1 deletions
diff --git a/src/Data/Tox/Message.hs b/src/Data/Tox/Message.hs
index b77307a2..9f1ce339 100644
--- a/src/Data/Tox/Message.hs
+++ b/src/Data/Tox/Message.hs
@@ -31,7 +31,8 @@ pattern MSI = MessageID 69
31pattern FILE_SENDREQUEST = MessageID 80 -- 1+1+4+8+32+max255 = up to 301 31pattern FILE_SENDREQUEST = MessageID 80 -- 1+1+4+8+32+max255 = up to 301
32pattern FILE_CONTROL = MessageID 81 -- 8 bytes if seek, otherwise 4 32pattern FILE_CONTROL = MessageID 81 -- 8 bytes if seek, otherwise 4
33pattern FILE_DATA = MessageID 82 -- up to 1373 33pattern FILE_DATA = MessageID 82 -- up to 1373
34pattern INVITE_GROUPCHAT = MessageID 96 -- 0x60 34pattern INVITE_GROUPCHAT = MessageID 95
35pattern INVITE_GROUPCHAT0 = MessageID 96 -- 0x60
35-- TODO: rename to INVITE_CONFERENCE 96 36-- TODO: rename to INVITE_CONFERENCE 96
36pattern ONLINE_PACKET = MessageID 97 -- 0x61 37pattern ONLINE_PACKET = MessageID 97 -- 0x61
37pattern DIRECT_GROUPCHAT = MessageID 98 -- 0x62 38pattern DIRECT_GROUPCHAT = MessageID 98 -- 0x62
diff --git a/src/Data/Tox/Msg.hs b/src/Data/Tox/Msg.hs
new file mode 100644
index 00000000..84fffb12
--- /dev/null
+++ b/src/Data/Tox/Msg.hs
@@ -0,0 +1,231 @@
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DefaultSignatures #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE GADTs #-}
5{-# LANGUAGE KindSignatures #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE PolyKinds #-}
8{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE StandaloneDeriving #-}
10module Data.Tox.Msg where
11
12import Data.ByteString as B
13import Data.Dependent.Sum
14import Data.GADT.Compare
15import Data.GADT.Show
16import Data.Functor.Identity
17import Data.Serialize
18import Data.Text as T
19import Data.Text.Encoding as T
20import Data.Typeable
21import Data.Word
22import GHC.TypeLits
23
24import Crypto.Tox
25import Data.PacketBuffer (compressSequenceNumbers, decompressSequenceNumbers)
26
27newtype Unknown = Unknown B.ByteString deriving (Eq,Show)
28newtype Padded = Padded B.ByteString deriving (Eq,Show)
29
30-- The 'UserStatus' equivalent in Presence is:
31--
32-- data JabberShow = Offline
33-- | ExtendedAway
34-- | Away -- Tox equiv: Away (1)
35-- | DoNotDisturb -- Tox equiv: Busy (2)
36-- | Available -- Tox equiv: Online (0)
37-- | Chatty
38-- deriving (Show,Enum,Ord,Eq,Read)
39--
40-- The Enum instance on 'UserStatus' is not arbitrary. It corresponds
41-- to on-the-wire id numbers.
42data UserStatus = Online | Away | Busy deriving (Show,Read,Eq,Ord,Enum)
43
44instance Serialize UserStatus where
45 get = do
46 x <- get :: Get Word8
47 return (toEnum8 x)
48 put x = put (fromEnum8 x)
49
50
51newtype MissingPackets = MissingPackets [Word32]
52 deriving (Eq,Show)
53
54data Msg (n :: Nat) t where
55 Padding :: Msg 0 Padded
56 PacketRequest :: Msg 1 MissingPackets
57 KillPacket :: Msg 2 ()
58 ALIVE :: Msg 16 ()
59 SHARE_RELAYS :: Msg 17 Unknown
60 FRIEND_REQUESTS :: Msg 18 Unknown
61 ONLINE :: Msg 24 ()
62 OFFLINE :: Msg 25 ()
63 NICKNAME :: Msg 48 Text
64 STATUSMESSAGE :: Msg 49 Text
65 USERSTATUS :: Msg 50 UserStatus
66 TYPING :: Msg 51 Bool
67 MESSAGE :: Msg 64 Text
68 ACTION :: Msg 65 Text
69 MSI :: Msg 69 Unknown
70 FILE_SENDREQUEST :: Msg 80 Unknown
71 FILE_CONTROL :: Msg 81 Unknown
72 FILE_DATA :: Msg 82 Unknown
73 INVITE_GROUPCHAT :: Msg 95 Unknown
74 INVITE_CONFERENCE :: Msg 96 Unknown
75 ONLINE_PACKET :: Msg 97 Unknown
76 DIRECT_CONFERENCE :: Msg 98 Unknown
77 MESSAGE_CONFERENCE :: Msg 99 Unknown
78 LOSSY_CONFERENCE :: Msg 199 Unknown
79
80deriving instance Show (Msg n a)
81
82msgbyte :: KnownNat n => Msg n a -> Word8
83msgbyte m = fromIntegral (natVal $ proxy m)
84 where proxy :: Msg n a -> Proxy n
85 proxy _ = Proxy
86
87data Pkt a where Pkt :: (KnownNat n, Packet a, KnownMsg n) => Msg n a -> Pkt a
88
89deriving instance (Show (Pkt a))
90
91type CryptoMessage = DSum Pkt Identity
92
93msgID (Pkt mid :=> Identity _) = M mid
94
95-- TODO
96instance GShow Pkt where gshowsPrec = showsPrec
97instance ShowTag Pkt Identity where
98 showTaggedPrec (Pkt _) = showsPrec
99
100instance GEq Pkt where geq (Pkt _) (Pkt _) = eqT
101instance EqTag Pkt Identity where eqTagged (Pkt _) (Pkt _) = (==)
102
103someMsgVal :: KnownMsg n => Msg n a -> SomeMsg
104someMsgVal m = msgid (proxy m)
105 where proxy :: Msg n a -> Proxy n
106 proxy _ = Proxy
107
108class KnownMsg (n::Nat) where msgid :: proxy n -> SomeMsg
109
110instance KnownMsg 0 where msgid _ = M Padding
111instance KnownMsg 1 where msgid _ = M PacketRequest
112instance KnownMsg 2 where msgid _ = M KillPacket
113instance KnownMsg 16 where msgid _ = M ALIVE
114instance KnownMsg 17 where msgid _ = M SHARE_RELAYS
115instance KnownMsg 18 where msgid _ = M FRIEND_REQUESTS
116instance KnownMsg 24 where msgid _ = M ONLINE
117instance KnownMsg 25 where msgid _ = M OFFLINE
118instance KnownMsg 48 where msgid _ = M NICKNAME
119instance KnownMsg 49 where msgid _ = M STATUSMESSAGE
120instance KnownMsg 50 where msgid _ = M USERSTATUS
121instance KnownMsg 51 where msgid _ = M TYPING
122instance KnownMsg 64 where msgid _ = M MESSAGE
123instance KnownMsg 65 where msgid _ = M ACTION
124instance KnownMsg 69 where msgid _ = M MSI
125instance KnownMsg 80 where msgid _ = M FILE_SENDREQUEST
126instance KnownMsg 81 where msgid _ = M FILE_CONTROL
127instance KnownMsg 82 where msgid _ = M FILE_DATA
128instance KnownMsg 95 where msgid _ = M INVITE_GROUPCHAT
129instance KnownMsg 96 where msgid _ = M INVITE_CONFERENCE
130instance KnownMsg 97 where msgid _ = M ONLINE_PACKET
131instance KnownMsg 98 where msgid _ = M DIRECT_CONFERENCE
132instance KnownMsg 99 where msgid _ = M MESSAGE_CONFERENCE
133
134msgTag :: Word8 -> Maybe SomeMsg
135msgTag 0 = Just $ M Padding
136msgTag 1 = Just $ M PacketRequest
137msgTag 2 = Just $ M KillPacket
138msgTag 16 = Just $ M ALIVE
139msgTag 17 = Just $ M SHARE_RELAYS
140msgTag 18 = Just $ M FRIEND_REQUESTS
141msgTag 24 = Just $ M ONLINE
142msgTag 25 = Just $ M OFFLINE
143msgTag 48 = Just $ M NICKNAME
144msgTag 49 = Just $ M STATUSMESSAGE
145msgTag 50 = Just $ M USERSTATUS
146msgTag 51 = Just $ M TYPING
147msgTag 64 = Just $ M MESSAGE
148msgTag 65 = Just $ M ACTION
149msgTag 69 = Just $ M MSI
150msgTag 80 = Just $ M FILE_SENDREQUEST
151msgTag 81 = Just $ M FILE_CONTROL
152msgTag 82 = Just $ M FILE_DATA
153msgTag 95 = Just $ M INVITE_GROUPCHAT
154msgTag 96 = Just $ M INVITE_CONFERENCE
155msgTag 97 = Just $ M ONLINE_PACKET
156msgTag 98 = Just $ M DIRECT_CONFERENCE
157msgTag 99 = Just $ M MESSAGE_CONFERENCE
158msgTag _ = Nothing
159
160
161class (Typeable t, Eq t, Show t, Sized t) => Packet t where
162 getPacket :: Word32 -> Get t
163 putPacket :: Word32 -> t -> Put
164 default getPacket :: Serialize t => Word32 -> Get t
165 getPacket _ = get
166 default putPacket :: Serialize t => Word32 -> t -> Put
167 putPacket _ t = put t
168
169instance Sized UserStatus where size = ConstSize 1
170instance Packet UserStatus
171
172instance Sized () where size = ConstSize 0
173instance Packet () where
174 getPacket _ = return ()
175 putPacket _ _ = return ()
176
177instance Sized MissingPackets where size = VarSize $ \(MissingPackets ws) -> Prelude.length ws
178instance Packet MissingPackets where
179 getPacket seqno = do
180 bs <- B.unpack <$> (remaining >>= getBytes)
181 return $ MissingPackets (decompressSequenceNumbers seqno bs)
182 putPacket seqno (MissingPackets ws) = do
183 mapM_ putWord8 $ compressSequenceNumbers seqno ws
184
185instance Sized Unknown where size = VarSize $ \(Unknown bs) -> B.length bs
186instance Packet Unknown where
187 getPacket _ = Unknown <$> (remaining >>= getBytes)
188 putPacket _ (Unknown bs) = putByteString bs
189
190instance Sized Padded where size = VarSize $ \(Padded bs) -> B.length bs
191instance Packet Padded where
192 getPacket _ = Padded <$> (remaining >>= getBytes)
193 putPacket _ (Padded bs) = putByteString bs
194
195instance Sized Text where size = VarSize (B.length . T.encodeUtf8)
196instance Packet Text where
197 getPacket _ = T.decodeUtf8 <$> (remaining >>= getBytes)
198 putPacket _ = putByteString . T.encodeUtf8
199
200instance Sized Bool where size = ConstSize 1
201instance Packet Bool where
202 getPacket _ = (/= 0) <$> getWord8
203 putPacket _ False = putWord8 0
204 putPacket _ True = putWord8 1
205
206data SomeMsg where
207 M :: (KnownMsg n, KnownNat n, Packet t) => Msg n t -> SomeMsg
208
209instance Eq SomeMsg where
210 M m == M n = msgbyte m == msgbyte n
211
212instance Show SomeMsg where
213 show (M m) = show m
214
215toEnum8 :: (Enum a, Integral word8) => word8 -> a
216toEnum8 = toEnum . fromIntegral
217
218fromEnum8 :: Enum a => a -> Word8
219fromEnum8 = fromIntegral . fromEnum
220
221data LossyOrLossless = Lossless | Lossy deriving (Eq,Ord,Enum,Show,Bounded)
222
223someLossyness (M m) = lossyness m
224
225lossyness :: KnownNat n => Msg n t -> LossyOrLossless
226lossyness m = case msgbyte m of
227 x | x < 3 -> Lossy
228 | {-16 <= x,-} x < 192 -> Lossless
229 | 192 <= x, x < 255 -> Lossy
230 | otherwise -> Lossless
231