diff options
author | joe <joe@jerkface.net> | 2017-07-23 20:23:39 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-07-23 20:23:39 -0400 |
commit | e7b15e2ca64bab5e0760caac7afa8373bf0e89ed (patch) | |
tree | dedc1c984486e4398c1c490ae01108d712cce1c8 | |
parent | cced8596d2fe2b35e373853382551756281d4602 (diff) |
fromBEncode for (Message BValue).
-rw-r--r-- | Mainline.hs | 71 |
1 files changed, 63 insertions, 8 deletions
diff --git a/Mainline.hs b/Mainline.hs index fdb77b4d..29f1df80 100644 --- a/Mainline.hs +++ b/Mainline.hs | |||
@@ -19,6 +19,7 @@ import Crypto.Random | |||
19 | import Data.BEncode as BE | 19 | import Data.BEncode as BE |
20 | import qualified Data.BEncode.BDict as BE | 20 | import qualified Data.BEncode.BDict as BE |
21 | ;import Data.BEncode.BDict (BKey) | 21 | ;import Data.BEncode.BDict (BKey) |
22 | import Data.BEncode.Types (BDict) | ||
22 | import Data.Bits | 23 | import Data.Bits |
23 | import Data.Bits.ByteString | 24 | import Data.Bits.ByteString |
24 | import Data.Bool | 25 | import Data.Bool |
@@ -64,6 +65,9 @@ instance S.Serialize NodeId where | |||
64 | instance FiniteBits NodeId where | 65 | instance FiniteBits NodeId where |
65 | finiteBitSize _ = 160 | 66 | finiteBitSize _ = 160 |
66 | 67 | ||
68 | zeroID :: NodeId | ||
69 | zeroID = NodeId $ B.replicate 20 0 | ||
70 | |||
67 | data NodeInfo = NodeInfo | 71 | data NodeInfo = NodeInfo |
68 | { nodeId :: NodeId | 72 | { nodeId :: NodeId |
69 | , nodeIP :: IP | 73 | , nodeIP :: IP |
@@ -183,17 +187,52 @@ data Message a = Q { msgOrigin :: NodeId | |||
183 | , rspReflectedIP :: Maybe SockAddr } | 187 | , rspReflectedIP :: Maybe SockAddr } |
184 | 188 | ||
185 | instance BE.BEncode (Message BValue) where | 189 | instance BE.BEncode (Message BValue) where |
186 | toBEncode = encodeMessage | 190 | toBEncode = encodeMessage |
187 | fromBEncode = error "TODO: fromBEncode (Mainline Message)" | 191 | fromBEncode = decodeMessage |
188 | 192 | ||
193 | decodeMessage :: BValue -> Either String (Message BValue) | ||
194 | decodeMessage = fromDict $ do | ||
195 | key <- lookAhead (field (req "y")) | ||
196 | let _ = key :: BKey | ||
197 | f <- case key of | ||
198 | "q" -> do a <- field (req "a") | ||
199 | g <- either fail return $ flip fromDict a $ do | ||
200 | who <- field (req "id") | ||
201 | ro <- fromMaybe False <$> optional (field (req "ro")) | ||
202 | return $ \meth tid -> Q who tid a meth ro | ||
203 | meth <- field (req "q") | ||
204 | return $ g meth | ||
205 | "r" -> do ip <- do | ||
206 | ipstr <- optional (field (req "ip")) | ||
207 | mapM (either fail return . decodeAddr) ipstr | ||
208 | vals <- field (req "r") | ||
209 | either fail return $ flip fromDict vals $ do | ||
210 | who <- field (req "id") | ||
211 | return $ \tid -> R who tid (Right vals) ip | ||
212 | "e" -> do (ecode,emsg) <- field (req "e") | ||
213 | ip <- do | ||
214 | ipstr <- optional (field (req "ip")) | ||
215 | mapM (either fail return . decodeAddr) ipstr | ||
216 | -- FIXME:Spec does not give us the NodeId of the sender. | ||
217 | -- Using 'zeroID' as place holder. | ||
218 | -- We should ignore the msgOrigin for errors in 'updateRouting'. | ||
219 | -- We should consider making msgOrigin a Maybe value. | ||
220 | return $ \tid -> R zeroID tid (Left (Error ecode emsg)) ip | ||
221 | _ -> fail $ "Mainline message is not a query, response, or an error: " | ||
222 | ++ show key | ||
223 | tid <- field (req "t") | ||
224 | return $ f (tid :: TransactionId) | ||
225 | |||
226 | |||
227 | encodeMessage :: Message BValue -> BValue | ||
189 | encodeMessage (Q origin tid a meth ro) | 228 | encodeMessage (Q origin tid a meth ro) |
190 | = case a of | 229 | = case a of |
191 | BDict args -> encodeQuery tid meth (BDict $ genericArgs origin ro `BE.union` args) | 230 | BDict args -> encodeQuery tid meth (BDict $ genericArgs origin ro `BE.union` args) |
192 | _ -> encodeQuery tid meth a -- XXX: Not really a valid query. | 231 | _ -> encodeQuery tid meth a -- XXX: Not really a valid query. |
193 | encodeMessage (R origin tid v ip) | 232 | encodeMessage (R origin tid v ip) |
194 | = case v of | 233 | = case v of |
195 | Right vals -> encodeResponse tid vals (BString . encodeAddr <$> ip) | 234 | Right (BDict vals) -> encodeResponse tid (BDict $ genericArgs origin False `BE.union` vals) ip |
196 | Left err -> encodeError tid err | 235 | Left err -> encodeError tid err |
197 | 236 | ||
198 | encodeAddr :: SockAddr -> ByteString | 237 | encodeAddr :: SockAddr -> ByteString |
199 | encodeAddr (SockAddrInet port addr) | 238 | encodeAddr (SockAddrInet port addr) |
@@ -202,17 +241,31 @@ encodeAddr (SockAddrInet6 port _ addr _) | |||
202 | = S.runPut (S.put addr >> S.put (fromIntegral port :: Word16)) | 241 | = S.runPut (S.put addr >> S.put (fromIntegral port :: Word16)) |
203 | encodeAddr _ = B.empty | 242 | encodeAddr _ = B.empty |
204 | 243 | ||
244 | decodeAddr :: ByteString -> Either String SockAddr | ||
245 | decodeAddr = S.runGet $ do | ||
246 | error "decodeAddr" | ||
247 | |||
248 | genericArgs :: BEncode a => a -> Bool -> BDict | ||
205 | genericArgs nodeid ro = | 249 | genericArgs nodeid ro = |
206 | "id" .=! nodeid | 250 | "id" .=! nodeid |
207 | .: "ro" .=? bool Nothing (Just (1 :: Int)) ro | 251 | .: "ro" .=? bool Nothing (Just (1 :: Int)) ro |
208 | .: endDict | 252 | .: endDict |
209 | 253 | ||
210 | encodeError tid (Error ecode emsg) = encodeAny tid "e" (ecode,emsg) id | 254 | encodeError :: BEncode a => a -> Error -> BValue |
255 | encodeError tid (Error ecode emsg) = encodeAny tid "e" (ecode,emsg) id | ||
211 | 256 | ||
212 | encodeResponse tid rvals rip = encodeAny tid "r" rvals ("ip" .=? rip .:) | 257 | encodeResponse :: (BEncode tid, BEncode vals) => |
258 | tid -> vals -> Maybe SockAddr -> BValue | ||
259 | encodeResponse tid rvals rip = | ||
260 | encodeAny tid "r" rvals ("ip" .=? (BString . encodeAddr <$> rip) .:) | ||
213 | 261 | ||
214 | encodeQuery tid qmeth qargs = encodeAny tid "q" qmeth ("a" .=! qargs .:) | 262 | encodeQuery :: (BEncode args, BEncode tid, BEncode method) => |
263 | tid -> method -> args -> BValue | ||
264 | encodeQuery tid qmeth qargs = encodeAny tid "q" qmeth ("a" .=! qargs .:) | ||
215 | 265 | ||
266 | encodeAny :: | ||
267 | (BEncode tid, BEncode a) => | ||
268 | tid -> BKey -> a -> (BDict -> BDict) -> BValue | ||
216 | encodeAny tid key val aux = toDict $ | 269 | encodeAny tid key val aux = toDict $ |
217 | aux $ key .=! val | 270 | aux $ key .=! val |
218 | .: "t" .=! tid | 271 | .: "t" .=! tid |
@@ -221,6 +274,8 @@ encodeAny tid key val aux = toDict $ | |||
221 | 274 | ||
222 | parsePacket :: ByteString -> SockAddr -> Either String (Message BValue, NodeInfo) | 275 | parsePacket :: ByteString -> SockAddr -> Either String (Message BValue, NodeInfo) |
223 | parsePacket bs addr = do pkt <- BE.decode bs | 276 | parsePacket bs addr = do pkt <- BE.decode bs |
277 | -- TODO: Error packets do not inclucde a valid msgOrigin. | ||
278 | -- The BE.decode method is using 'zeroID' as a placeholder. | ||
224 | ni <- nodeInfo (msgOrigin pkt) addr | 279 | ni <- nodeInfo (msgOrigin pkt) addr |
225 | return (pkt, ni) | 280 | return (pkt, ni) |
226 | 281 | ||