]> git.rkrishnan.org Git - functorrent.git/blob - src/Tracker.hs
7d5525f4058d23d183deb024c56463bd543b0f3e
[functorrent.git] / src / Tracker.hs
1 module Tracker where
2
3 import qualified Data.ByteString.Char8 as BC
4 import qualified Data.Map as M
5 import qualified Data.List as List
6 import qualified Network.HTTP as HTTP
7 import qualified Bencode as Benc
8 import qualified Crypto.Hash as H
9 import qualified Crypto.Hash.SHA1 as SHA1
10 import qualified Data.ByteString.Base16 as B16
11 import Data.Char
12 -- import Network.HTTP
13
14 type Url = String
15
16 splitN :: Int -> BC.ByteString -> [BC.ByteString]
17 splitN n bs | BC.null bs = []
18             | otherwise = (BC.take n bs) : splitN n (BC.drop n bs)
19
20 -- | urlEncode
21 --
22 -- >>> urlEncode $ BC.pack "123456789abcdef123456789abcdef123456789a"
23 -- "%124Vx%9a%bc%de%f1%23Eg%89%ab%cd%ef%124Vx%9a"
24 urlEncode :: BC.ByteString -> String
25 urlEncode bs = concatMap (encode . BC.unpack) (splitN 2 bs)
26   where encode b@(c1 : c2 : []) = let c =  chr (read ("0x" ++ b))
27                                   in
28                                    escape c c1 c2
29         encode _ = ""
30         escape i c1 c2 | i `elem` nonSpecialChars = [i]
31                        | otherwise = "%" ++ [c1] ++ [c2]
32           where nonSpecialChars = ['A'..'Z'] ++
33                                   ['a'..'z'] ++
34                                   ['0'..'9'] ++
35                                   ['-', '_', '.', '~']
36
37 infoHash :: (M.Map Benc.BVal Benc.BVal) -> BC.ByteString
38 infoHash m = let info = m M.! (Benc.Bstr (BC.pack "info"))
39              in (B16.encode . SHA1.hash . BC.pack . Benc.encode) info
40
41 peerHash :: String -> BC.ByteString
42 peerHash = (B16.encode . SHA1.hash . BC.pack)
43
44 prepareRequest :: Benc.BVal -> String -> String
45 prepareRequest (Benc.Bdict d) peer_id = let p = [("info_hash", urlEncode (infoHash d)),
46                                                  ("peer_id", urlEncode (peerHash peer_id)),
47                                                  ("port", "6881"),
48                                                  ("uploaded", "0"),
49                                                  ("downloaded", "0"),
50                                                  ("left", "0"),
51                                                  ("compact", "1"),
52                                                  ("event", "started")]
53                                         in
54                                          List.intercalate "&" [f ++ "=" ++ s | (f,s) <- p]
55
56 connect :: Url -> String -> IO (String)
57 connect baseurl qstr = let url = baseurl ++ "?" ++ qstr
58                        in HTTP.simpleHTTP (HTTP.getRequest url) >>=
59                           HTTP.getResponseBody