1 module FuncTorrent.Peer
9 import Prelude hiding (lookup, concat, replicate, splitAt)
10 import Data.ByteString.Char8 (ByteString, pack, unpack, concat, replicate, splitAt)
11 import Data.ByteString.Lazy (toChunks)
12 import Data.Int (Int8)
13 import Data.List (intercalate)
14 import Data.Map as M ((!), lookup)
15 import qualified Data.Binary as Bin (encode)
16 import qualified Data.ByteString.Base16 as B16 (encode)
18 import FuncTorrent.Bencode (BVal(..), InfoDict, decode)
19 import FuncTorrent.Tracker (infoHash)
20 import FuncTorrent.Utils (splitN)
26 data Peer = Peer Address Port
29 data PeerResp = PeerResponse { interval :: Maybe Integer
31 , complete :: Maybe Integer
32 , incomplete :: Maybe Integer
35 toInt :: String -> Integer
38 getPeers :: PeerResp -> [Peer]
41 getPeerResponse :: ByteString -> PeerResp
42 getPeerResponse body = case decode body of
43 Right (Bdict peerM) ->
44 let (Just (Bint i)) = lookup (Bstr (pack "lookup")) peerM
45 (Bstr peersBS) = peerM ! Bstr (pack "peers")
46 pl = map (\peer -> let (ip', port') = splitAt 4 peer
47 in Peer (toIPNum ip') (toPortNum port'))
49 in PeerResponse { interval = Just i
52 , incomplete = Nothing
54 where toPortNum = read . ("0x" ++) . unpack . B16.encode
55 toIPNum = intercalate "." .
56 map (show . toInt . ("0x" ++) . unpack) .
59 _ -> PeerResponse { interval = Nothing
62 , incomplete = Nothing
66 handShakeMsg :: InfoDict -> String -> ByteString
67 handShakeMsg m peer_id = let pstrlen = concat $ toChunks $ Bin.encode (19 :: Int8)
68 pstr = pack "BitTorrent protocol"
69 reserved = replicate 8 '\0'
72 in concat [pstrlen, pstr, reserved, infoH, peerID]