diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-16 20:19:07 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-16 20:19:07 +0400 |
commit | 0cf1c142d0e18eef05e1190d0fdaa94d2fa4df59 (patch) | |
tree | b7103d0a55c665bd738eb23ccc3784f3e8d13c18 /src/Network/BitTorrent/Tracker/Message.hs | |
parent | f393a2ec1611d2e5587f6fc97317294377c72d5d (diff) |
Add spec for AnnounceInfo encoding
Diffstat (limited to 'src/Network/BitTorrent/Tracker/Message.hs')
-rw-r--r-- | src/Network/BitTorrent/Tracker/Message.hs | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/src/Network/BitTorrent/Tracker/Message.hs b/src/Network/BitTorrent/Tracker/Message.hs index d0be1c36..da46628b 100644 --- a/src/Network/BitTorrent/Tracker/Message.hs +++ b/src/Network/BitTorrent/Tracker/Message.hs | |||
@@ -70,7 +70,6 @@ module Network.BitTorrent.Tracker.Message | |||
70 | 70 | ||
71 | import Control.Applicative | 71 | import Control.Applicative |
72 | import Control.Monad | 72 | import Control.Monad |
73 | import Data.Aeson (ToJSON(..), FromJSON(..)) | ||
74 | import Data.Aeson.TH | 73 | import Data.Aeson.TH |
75 | import Data.BEncode as BE hiding (Result) | 74 | import Data.BEncode as BE hiding (Result) |
76 | import Data.BEncode.BDict as BE | 75 | import Data.BEncode.BDict as BE |
@@ -79,8 +78,10 @@ import Data.ByteString.Char8 as BC | |||
79 | import Data.Char as Char | 78 | import Data.Char as Char |
80 | import Data.Convertible | 79 | import Data.Convertible |
81 | import Data.Default | 80 | import Data.Default |
81 | import Data.Either | ||
82 | import Data.List as L | 82 | import Data.List as L |
83 | import Data.Maybe | 83 | import Data.Maybe |
84 | import Data.Monoid | ||
84 | import Data.Serialize as S hiding (Result) | 85 | import Data.Serialize as S hiding (Result) |
85 | import Data.String | 86 | import Data.String |
86 | import Data.Text (Text) | 87 | import Data.Text (Text) |
@@ -193,9 +194,9 @@ instance Serialize AnnounceQuery where | |||
193 | put reqPeerId | 194 | put reqPeerId |
194 | put reqProgress | 195 | put reqProgress |
195 | putEvent reqEvent | 196 | putEvent reqEvent |
196 | putWord32be $ fromMaybe 0 reqIP | 197 | putWord32host $ fromMaybe 0 reqIP |
197 | putWord32be $ 0 -- TODO what the fuck is "key"? | 198 | putWord32be $ 0 -- TODO what the fuck is "key"? |
198 | putWord32be $ fromIntegral $ fromMaybe (-1) reqNumWant | 199 | putWord32be $ fromIntegral $ fromMaybe (-1) reqNumWant |
199 | 200 | ||
200 | put reqPort | 201 | put reqPort |
201 | 202 | ||
@@ -415,7 +416,9 @@ data AnnounceRequest = AnnounceRequest | |||
415 | } deriving (Show, Eq, Typeable) | 416 | } deriving (Show, Eq, Typeable) |
416 | 417 | ||
417 | instance QueryLike AnnounceRequest where | 418 | instance QueryLike AnnounceRequest where |
418 | toQuery AnnounceRequest{..} = toQuery announceAdvises ++ toQuery announceQuery | 419 | toQuery AnnounceRequest{..} = |
420 | toQuery announceAdvises <> | ||
421 | toQuery announceQuery | ||
419 | 422 | ||
420 | -- | Parse announce request from query string. | 423 | -- | Parse announce request from query string. |
421 | parseAnnounceRequest :: SimpleQuery -> ParseResult AnnounceRequest | 424 | parseAnnounceRequest :: SimpleQuery -> ParseResult AnnounceRequest |
@@ -441,6 +444,11 @@ data PeerList ip | |||
441 | | CompactPeerList [PeerAddr ip] | 444 | | CompactPeerList [PeerAddr ip] |
442 | deriving (Show, Eq, Typeable, Functor) | 445 | deriving (Show, Eq, Typeable, Functor) |
443 | 446 | ||
447 | -- | The empty non-compact peer list. | ||
448 | instance Default (PeerList IP) where | ||
449 | def = PeerList [] | ||
450 | {-# INLINE def #-} | ||
451 | |||
444 | getPeerList :: PeerList IP -> [PeerAddr IP] | 452 | getPeerList :: PeerList IP -> [PeerAddr IP] |
445 | getPeerList (PeerList xs) = xs | 453 | getPeerList (PeerList xs) = xs |
446 | getPeerList (CompactPeerList xs) = xs | 454 | getPeerList (CompactPeerList xs) = xs |
@@ -482,6 +490,17 @@ data AnnounceInfo = | |||
482 | , respWarning :: !(Maybe Text) | 490 | , respWarning :: !(Maybe Text) |
483 | } deriving (Show, Eq, Typeable) | 491 | } deriving (Show, Eq, Typeable) |
484 | 492 | ||
493 | -- | Empty peer list with default reannounce interval. | ||
494 | instance Default AnnounceInfo where | ||
495 | def = AnnounceInfo | ||
496 | { respComplete = Nothing | ||
497 | , respIncomplete = Nothing | ||
498 | , respInterval = defaultReannounceInterval | ||
499 | , respMinInterval = Nothing | ||
500 | , respPeers = def | ||
501 | , respWarning = Nothing | ||
502 | } | ||
503 | |||
485 | -- | HTTP tracker protocol compatible encoding. | 504 | -- | HTTP tracker protocol compatible encoding. |
486 | instance BEncode AnnounceInfo where | 505 | instance BEncode AnnounceInfo where |
487 | toBEncode (Failure t) = toDict $ | 506 | toBEncode (Failure t) = toDict $ |
@@ -494,10 +513,24 @@ instance BEncode AnnounceInfo where | |||
494 | .: "interval" .=! respInterval | 513 | .: "interval" .=! respInterval |
495 | .: "min interval" .=? respMinInterval | 514 | .: "min interval" .=? respMinInterval |
496 | .: "peers" .=! peers | 515 | .: "peers" .=! peers |
497 | .: "peers6" .=! peers6 | 516 | .: "peers6" .=? peers6 |
498 | .: "warning message" .=? respWarning | 517 | .: "warning message" .=? respWarning |
499 | .: endDict | 518 | .: endDict |
500 | where (peers,peers6) = splitIPList $ getPeerList respPeers | 519 | where |
520 | (peers, peers6) = prttn respPeers | ||
521 | |||
522 | prttn :: PeerList IP -> (PeerList IPv4, Maybe (PeerList IPv6)) | ||
523 | prttn (PeerList xs) = (PeerList xs, Nothing) | ||
524 | prttn (CompactPeerList xs) = mk $ partitionEithers $ toEither <$> xs | ||
525 | where | ||
526 | mk (v4s, v6s) | ||
527 | | L.null v6s = (CompactPeerList v4s, Nothing) | ||
528 | | otherwise = (CompactPeerList v4s, Just (CompactPeerList v6s)) | ||
529 | |||
530 | toEither :: PeerAddr IP -> Either (PeerAddr IPv4) (PeerAddr IPv6) | ||
531 | toEither PeerAddr {..} = case peerHost of | ||
532 | IPv4 ipv4 -> Left $ PeerAddr peerId ipv4 peerPort | ||
533 | IPv6 ipv6 -> Right $ PeerAddr peerId ipv6 peerPort | ||
501 | 534 | ||
502 | fromBEncode (BDict d) | 535 | fromBEncode (BDict d) |
503 | | Just t <- BE.lookup "failure reason" d = Failure <$> fromBEncode t | 536 | | Just t <- BE.lookup "failure reason" d = Failure <$> fromBEncode t |
@@ -507,8 +540,26 @@ instance BEncode AnnounceInfo where | |||
507 | <*>? "incomplete" | 540 | <*>? "incomplete" |
508 | <*>! "interval" | 541 | <*>! "interval" |
509 | <*>? "min interval" | 542 | <*>? "min interval" |
510 | <*> (PeerList <$> (mergeIPLists <$>! "peers" <*>? "peers6")) | 543 | <*> (uncurry merge =<< (,) <$>! "peers" <*>? "peers6") |
511 | <*>? "warning message" | 544 | <*>? "warning message" |
545 | where | ||
546 | merge :: PeerList IPv4 -> Maybe (PeerList IPv6) -> BE.Get (PeerList IP) | ||
547 | merge (PeerList ips) Nothing = pure (PeerList ips) | ||
548 | merge (PeerList _ ) (Just _) | ||
549 | = fail "PeerList: non-compact peer list provided, \ | ||
550 | \but the `peers6' field present" | ||
551 | |||
552 | merge (CompactPeerList ipv4s) Nothing | ||
553 | = pure $ CompactPeerList (fmap IPv4 <$> ipv4s) | ||
554 | |||
555 | merge (CompactPeerList _ ) (Just (PeerList _)) | ||
556 | = fail "PeerList: the `peers6' field value \ | ||
557 | \should contain *compact* peer list" | ||
558 | |||
559 | merge (CompactPeerList ipv4s) (Just (CompactPeerList ipv6s)) | ||
560 | = pure $ CompactPeerList $ | ||
561 | (fmap IPv4 <$> ipv4s) <> (fmap IPv6 <$> ipv6s) | ||
562 | |||
512 | fromBEncode _ = decodingError "Announce info" | 563 | fromBEncode _ = decodingError "Announce info" |
513 | 564 | ||
514 | -- | UDP tracker protocol compatible encoding. | 565 | -- | UDP tracker protocol compatible encoding. |