1 module FuncTorrent.Peer
8 import Prelude hiding (lookup, concat, replicate, splitAt)
9 import Data.ByteString.Char8 (ByteString, pack, unpack, concat, replicate, splitAt)
10 import Data.ByteString.Lazy (toChunks)
11 import Data.Int (Int8)
12 import Data.List (intercalate)
13 import Data.Map as M ((!), lookup)
14 import qualified Data.Binary as Bin (encode)
15 import qualified Data.ByteString.Base16 as B16 (encode)
17 import FuncTorrent.Bencode (BVal(..), InfoDict, decode)
18 import FuncTorrent.Tracker (infoHash)
19 import FuncTorrent.Utils (splitN)
25 data Peer = Peer Address Port
28 data PeerResp = PeerResponse { interval :: Maybe Integer
30 , complete :: Maybe Integer
31 , incomplete :: Maybe Integer
34 toInt :: String -> Integer
37 getPeerResponse :: ByteString -> PeerResp
38 getPeerResponse body = case decode body of
39 Right (Bdict peerM) ->
40 let (Just (Bint i)) = lookup (Bstr (pack "lookup")) peerM
41 (Bstr peersBS) = peerM ! Bstr (pack "peers")
42 pl = map (\peer -> let (ip', port') = splitAt 4 peer
43 in Peer (toIPNum ip') (toPortNum port'))
45 in PeerResponse { interval = Just i
48 , incomplete = Nothing
50 where toPortNum = read . ("0x" ++) . unpack . B16.encode
51 toIPNum = intercalate "." .
52 map (show . toInt . ("0x" ++) . unpack) .
55 _ -> PeerResponse { interval = Nothing
58 , incomplete = Nothing
62 handShakeMsg :: InfoDict -> String -> ByteString
63 handShakeMsg m peer_id = let pstrlen = concat $ toChunks $ Bin.encode (19 :: Int8)
64 pstr = pack "BitTorrent protocol"
65 reserved = replicate 8 '\0'
68 in concat [pstrlen, pstr, reserved, infoH, peerID]