summaryrefslogtreecommitdiff
path: root/src/Network/KRPC/Protocol.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/KRPC/Protocol.hs')
-rw-r--r--src/Network/KRPC/Protocol.hs81
1 files changed, 40 insertions, 41 deletions
diff --git a/src/Network/KRPC/Protocol.hs b/src/Network/KRPC/Protocol.hs
index 1e7bd7c3..67a4057d 100644
--- a/src/Network/KRPC/Protocol.hs
+++ b/src/Network/KRPC/Protocol.hs
@@ -17,6 +17,7 @@
17{-# LANGUAGE MultiParamTypeClasses #-} 17{-# LANGUAGE MultiParamTypeClasses #-}
18{-# LANGUAGE FunctionalDependencies #-} 18{-# LANGUAGE FunctionalDependencies #-}
19{-# LANGUAGE DefaultSignatures #-} 19{-# LANGUAGE DefaultSignatures #-}
20{-# LANGUAGE DeriveDataTypeable #-}
20module Network.KRPC.Protocol 21module Network.KRPC.Protocol
21 ( -- * Error 22 ( -- * Error
22 KError(..) 23 KError(..)
@@ -46,9 +47,7 @@ module Network.KRPC.Protocol
46 47
47 -- * Re-exports 48 -- * Re-exports
48 , encode 49 , encode
49 , encoded
50 , decode 50 , decode
51 , decoded
52 , toBEncode 51 , toBEncode
53 , fromBEncode 52 , fromBEncode
54 ) where 53 ) where
@@ -59,11 +58,14 @@ import Control.Monad
59import Control.Monad.IO.Class 58import Control.Monad.IO.Class
60import Control.Monad.Trans.Control 59import Control.Monad.Trans.Control
61 60
62import Data.BEncode 61import Data.BEncode as BE
62import Data.BEncode.BDict as BE
63import Data.BEncode.Types as BE
63import Data.ByteString as B 64import Data.ByteString as B
64import Data.ByteString.Char8 as BC 65import Data.ByteString.Char8 as BC
65import qualified Data.ByteString.Lazy as LB 66import qualified Data.ByteString.Lazy as LB
66import Data.Map as M 67import Data.Map as M
68import Data.Typeable
67 69
68import Network.Socket hiding (recvFrom) 70import Network.Socket hiding (recvFrom)
69import Network.Socket.ByteString 71import Network.Socket.ByteString
@@ -89,20 +91,21 @@ data KError
89 91
90 -- | Occur when client trying to call method server don't know. 92 -- | Occur when client trying to call method server don't know.
91 | MethodUnknown { errorMessage :: ByteString } 93 | MethodUnknown { errorMessage :: ByteString }
92 deriving (Show, Read, Eq, Ord) 94 deriving (Show, Read, Eq, Ord, Typeable)
93 95
94instance BEncode KError where 96instance BEncode KError where
95 {-# SPECIALIZE instance BEncode KError #-} 97 {-# SPECIALIZE instance BEncode KError #-}
96 {-# INLINE toBEncode #-} 98 {-# INLINE toBEncode #-}
97 toBEncode e = fromAscAssocs -- WARN: keep keys sorted 99 toBEncode e = toDict $
98 [ "e" --> (errorCode e, errorMessage e) 100 "e" .=! (errorCode e, errorMessage e)
99 , "y" --> ("e" :: ByteString) 101 .: "y" .=! ("e" :: ByteString)
100 ] 102 .: endDict
101 103
102 {-# INLINE fromBEncode #-} 104 {-# INLINE fromBEncode #-}
103 fromBEncode (BDict d) 105 fromBEncode be @ (BDict d)
104 | M.lookup "y" d == Just (BString "e") 106 | BE.lookup "y" d == Just (BString "e")
105 = uncurry mkKError <$> d >-- "e" 107 = (`fromDict` be) $ do
108 uncurry mkKError <$>! "e"
106 109
107 fromBEncode _ = decodingError "KError" 110 fromBEncode _ = decodingError "KError"
108 111
@@ -140,33 +143,30 @@ type ParamName = ByteString
140-- 143--
141data KQuery = KQuery { 144data KQuery = KQuery {
142 queryMethod :: MethodName 145 queryMethod :: MethodName
143 , queryArgs :: Map ParamName BValue 146 , queryArgs :: BDict
144 } deriving (Show, Read, Eq, Ord) 147 } deriving (Show, Read, Eq, Ord, Typeable)
145 148
146instance BEncode KQuery where 149instance BEncode KQuery where
147 {-# SPECIALIZE instance BEncode KQuery #-} 150 {-# SPECIALIZE instance BEncode KQuery #-}
148 {-# INLINE toBEncode #-} 151 {-# INLINE toBEncode #-}
149 toBEncode (KQuery m args) = fromAscAssocs -- WARN: keep keys sorted 152 toBEncode (KQuery m args) = toDict $
150 [ "a" --> BDict args 153 "a" .=! BDict args
151 , "q" --> m 154 .: "q" .=! m
152 , "y" --> ("q" :: ByteString) 155 .: "y" .=! ("q" :: ByteString)
153 ] 156 .: endDict
154 157
155 {-# INLINE fromBEncode #-} 158 {-# INLINE fromBEncode #-}
156 fromBEncode (BDict d) 159 fromBEncode bv @ (BDict d)
157 | M.lookup "y" d == Just (BString "q") = 160 | BE.lookup "y" d == Just (BString "q") = (`fromDict` bv) $ do
158 KQuery <$> d >-- "q" 161 KQuery <$>! "q" <*>! "a"
159 <*> d >-- "a"
160 162
161 fromBEncode _ = decodingError "KQuery" 163 fromBEncode _ = decodingError "KQuery"
162 164
163kquery :: MethodName -> [(ParamName, BValue)] -> KQuery 165kquery :: MethodName -> BDict -> KQuery
164kquery name args = KQuery name (M.fromList args) 166kquery = KQuery
165{-# INLINE kquery #-} 167{-# INLINE kquery #-}
166 168
167 169
168
169
170type ValName = ByteString 170type ValName = ByteString
171 171
172-- | KResponse used to signal that callee successufully process a 172-- | KResponse used to signal that callee successufully process a
@@ -179,25 +179,24 @@ type ValName = ByteString
179-- > { "y" : "r", "r" : [<val1>, <val2>, ...] } 179-- > { "y" : "r", "r" : [<val1>, <val2>, ...] }
180-- 180--
181newtype KResponse = KResponse { respVals :: BDict } 181newtype KResponse = KResponse { respVals :: BDict }
182 deriving (Show, Read, Eq, Ord) 182 deriving (Show, Read, Eq, Ord, Typeable)
183 183
184instance BEncode KResponse where 184instance BEncode KResponse where
185 {-# INLINE toBEncode #-} 185 {-# INLINE toBEncode #-}
186 toBEncode (KResponse vals) = fromAscAssocs -- WARN: keep keys sorted 186 toBEncode (KResponse vals) = toDict $
187 [ "r" --> vals 187 "r" .=! vals
188 , "y" --> ("r" :: ByteString) 188 .: "y" .=! ("r" :: ByteString)
189 ] 189 .: endDict
190 190
191 {-# INLINE fromBEncode #-} 191 {-# INLINE fromBEncode #-}
192 fromBEncode (BDict d) 192 fromBEncode bv @ (BDict d)
193 | M.lookup "y" d == Just (BString "r") = 193 | BE.lookup "y" d == Just (BString "r") = (`fromDict` bv) $ do
194 KResponse <$> d >-- "r" 194 KResponse <$>! "r"
195 195
196 fromBEncode _ = decodingError "KDict" 196 fromBEncode _ = decodingError "KDict"
197 197
198 198kresponse :: BDict -> KResponse
199kresponse :: [(ValName, BValue)] -> KResponse 199kresponse = KResponse
200kresponse = KResponse . M.fromList
201{-# INLINE kresponse #-} 200{-# INLINE kresponse #-}
202 201
203type KRemoteAddr = SockAddr 202type KRemoteAddr = SockAddr
@@ -219,15 +218,15 @@ maxMsgSize = 64 * 1024 -- bench: max UDP MTU
219{-# INLINE maxMsgSize #-} 218{-# INLINE maxMsgSize #-}
220 219
221sendMessage :: BEncode msg => msg -> KRemoteAddr -> KRemote -> IO () 220sendMessage :: BEncode msg => msg -> KRemoteAddr -> KRemote -> IO ()
222sendMessage msg addr sock = sendManyTo sock (LB.toChunks (encoded msg)) addr 221sendMessage msg addr sock = sendManyTo sock (LB.toChunks (encode msg)) addr
223{-# INLINE sendMessage #-} 222{-# INLINE sendMessage #-}
224 223
225recvResponse :: KRemote -> IO (Either KError KResponse) 224recvResponse :: KRemote -> IO (Either KError KResponse)
226recvResponse sock = do 225recvResponse sock = do
227 (raw, _) <- recvFrom sock maxMsgSize 226 (raw, _) <- recvFrom sock maxMsgSize
228 return $ case decoded raw of 227 return $ case decode raw of
229 Right resp -> Right resp 228 Right resp -> Right resp
230 Left decE -> Left $ case decoded raw of 229 Left decE -> Left $ case decode raw of
231 Right kerror -> kerror 230 Right kerror -> kerror
232 _ -> ProtocolError (BC.pack decE) 231 _ -> ProtocolError (BC.pack decE)
233 232
@@ -252,7 +251,7 @@ remoteServer servAddr action = bracket (liftIO bindServ) (liftIO . sClose) loop
252 reply <- handleMsg bs addr 251 reply <- handleMsg bs addr
253 liftIO $ sendMessage reply addr sock 252 liftIO $ sendMessage reply addr sock
254 where 253 where
255 handleMsg bs addr = case decoded bs of 254 handleMsg bs addr = case decode bs of
256 Right query -> (either toBEncode toBEncode <$> action addr query) 255 Right query -> (either toBEncode toBEncode <$> action addr query)
257 `Lifted.catch` (return . toBEncode . serverError) 256 `Lifted.catch` (return . toBEncode . serverError)
258 Left decodeE -> return $ toBEncode (ProtocolError (BC.pack decodeE)) 257 Left decodeE -> return $ toBEncode (ProtocolError (BC.pack decodeE))