X-Git-Url: https://git.rkrishnan.org/?a=blobdiff_plain;f=src%2FFuncTorrent%2FTracker.hs;h=8d2b3ec7ce38196578155180beb8b2881b80066b;hb=56904b7b9799590e5dc4899246157961ae02c543;hp=3644781b4adfa47d5b523824daece3a698c02907;hpb=5c31236826ca18453f785019e472e775d80ff258;p=functorrent.git diff --git a/src/FuncTorrent/Tracker.hs b/src/FuncTorrent/Tracker.hs index 3644781..8d2b3ec 100644 --- a/src/FuncTorrent/Tracker.hs +++ b/src/FuncTorrent/Tracker.hs @@ -1,27 +1,74 @@ +{-# LANGUAGE OverloadedStrings #-} module FuncTorrent.Tracker - (connect, - infoHash, + (TrackerResponse(..), + connect, + mkTrackerResponse, prepareRequest, urlEncodeHash ) where -import Prelude hiding (lookup) -import Crypto.Hash.SHA1 (hash) -import Data.ByteString.Char8 (ByteString, unpack) +import Prelude hiding (lookup, concat, replicate, splitAt) +import Data.ByteString.Char8 (ByteString, unpack, splitAt) import Data.Char (chr) import Data.List (intercalate) +import Data.Map as M (lookup) import Data.Maybe (fromJust) -import Data.Map ((!)) import Network.HTTP (simpleHTTP, defaultGETRequest_, getResponseBody) import Network.HTTP.Base (urlEncode) import Network.URI (parseURI) import qualified Data.ByteString.Base16 as B16 (encode) -import FuncTorrent.Bencode (InfoDict, encode) +import FuncTorrent.Bencode (BVal(..), InfoDict) +import FuncTorrent.Metainfo (infoHash) +import FuncTorrent.Peer (Peer(..)) import FuncTorrent.Utils (splitN) + +-- | Tracker response +data TrackerResponse = TrackerResponse { + interval :: Maybe Integer + , peers :: [Peer] + , complete :: Maybe Integer + , incomplete :: Maybe Integer + } deriving (Show, Eq) + type Url = String +-- | Deserialize tracker response +mkTrackerResponse :: BVal -> Either ByteString TrackerResponse +mkTrackerResponse resp = + case lookup "failure reason" body of + Just (Bstr err) -> Left err + Just _ -> Left "Unknown failure" + Nothing -> + let (Just (Bint i)) = lookup "interval" body + (Just (Bstr peersBS)) = lookup "peers" body + pl = map makePeer (splitN 6 peersBS) + in Right TrackerResponse { + interval = Just i + , peers = pl + , complete = Nothing + , incomplete = Nothing + } + where + (Bdict body) = resp + + toInt :: String -> Integer + toInt = read + + toPort :: ByteString -> Integer + toPort = read . ("0x" ++) . unpack . B16.encode + + toIP :: ByteString -> String + toIP = intercalate "." . + map (show . toInt . ("0x" ++) . unpack) . + splitN 2 . B16.encode + + makePeer :: ByteString -> Peer + makePeer peer = Peer (toIP ip') (toPort port') + where (ip', port') = splitAt 4 peer + + -- | urlEncodeHash -- -- >>> urlEncodeHash $ pack "123456789abcdef123456789abcdef123456789a" @@ -36,9 +83,6 @@ urlEncodeHash bs = concatMap (encode' . unpack) (splitN 2 bs) nonSpecialChars = ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "-_.~" -infoHash :: InfoDict -> ByteString -infoHash m = hash . encode $ (m ! "info") - prepareRequest :: InfoDict -> String -> Integer -> String prepareRequest d peer_id len = let p = [("info_hash", urlEncodeHash ((B16.encode . infoHash) d)),