3 import Prelude hiding (lookup, concat, replicate, splitAt)
5 import Bencode (BVal(..), InfoDict, decode)
6 import Data.ByteString.Char8 (ByteString, pack, unpack, concat, replicate, splitAt)
7 import Data.ByteString.Lazy (toChunks)
9 import Data.List (intercalate)
10 import Data.Map as M ((!), lookup)
11 import Tracker (infoHash)
13 import qualified Data.Binary as Bin (encode)
14 import qualified Data.ByteString.Base16 as B16 (encode)
20 data Peer = Peer Address Port
23 data PeerResp = PeerResponse { interval :: Maybe Integer
25 , complete :: Maybe Integer
26 , incomplete :: Maybe Integer
29 toInt :: String -> Integer
32 getPeers :: PeerResp -> [Peer]
35 getPeerResponse :: ByteString -> PeerResp
36 getPeerResponse body = case decode body of
37 Right (Bdict peerM) ->
38 let (Just (Bint i)) = lookup (Bstr (pack "lookup")) peerM
39 (Bstr peersBS) = peerM ! Bstr (pack "peers")
40 pl = map (\peer -> let (ip', port') = splitAt 4 peer
41 in Peer (toIPNum ip') (toPortNum port'))
43 in PeerResponse { interval = Just i
46 , incomplete = Nothing
48 where toPortNum = read . ("0x" ++) . unpack . B16.encode
49 toIPNum = intercalate "." .
50 map (show . toInt . ("0x" ++) . unpack) .
53 _ -> PeerResponse { interval = Nothing
56 , incomplete = Nothing
60 handShakeMsg :: InfoDict -> String -> ByteString
61 handShakeMsg m peer_id = let pstrlen = concat $ toChunks $ Bin.encode (19 :: Int8)
62 pstr = pack "BitTorrent protocol"
63 reserved = replicate 8 '\0'
66 in concat [pstrlen, pstr, reserved, infoH, peerID]