module Tracker where
--- import qualified Bencode as Benc
-import qualified Data.ByteString.Char8 as BC
-import qualified Network.HTTP.Base as HB
-import Data.Char
--- import Network.HTTP
+import Prelude hiding (lookup)
-type Url = String
+import Bencode (BVal(..), InfoDict, encode)
+import Crypto.Hash.SHA1 (hash)
+import Data.ByteString.Char8 (ByteString, pack, unpack)
+import Data.Char (chr)
+import Data.List (intercalate)
+import Data.Maybe (fromJust)
+import Data.Map as M (Map, (!))
+import Network.HTTP (simpleHTTP, defaultGETRequest_, getResponseBody)
+import Network.HTTP.Base (urlEncode)
+import Network.URI (parseURI)
+import Utils (splitN)
+import qualified Data.ByteString.Base16 as B16 (encode)
-splitN :: Int -> BC.ByteString -> [BC.ByteString]
-splitN n bs | BC.null bs = []
- | otherwise = (BC.take n bs) : splitN n (BC.drop n bs)
+type Url = String
--- | urlEncode
+-- | urlEncodeHash
--
--- >>> urlEncode $ BC.pack "123456789abcdef123456789abcdef123456789a"
+-- >>> urlEncodeHash $ pack "123456789abcdef123456789abcdef123456789a"
-- "%124Vx%9a%bc%de%f1%23Eg%89%ab%cd%ef%124Vx%9a"
-urlEncode :: BC.ByteString -> String
-urlEncode bs = concatMap (encode . BC.unpack) (splitN 2 bs)
- where encode b@(c1 : c2 : []) = let c = chr (read ("0x" ++ b))
- in
- escape c c1 c2
- encode _ = ""
+urlEncodeHash :: ByteString -> String
+urlEncodeHash bs = concatMap (encode' . unpack) (splitN 2 bs)
+ where encode' b@[c1, c2] = let c = chr (read ("0x" ++ b))
+ in escape c c1 c2
+ encode' _ = ""
escape i c1 c2 | i `elem` nonSpecialChars = [i]
| otherwise = "%" ++ [c1] ++ [c2]
- where nonSpecialChars = ['A'..'Z'] ++
- ['a'..'z'] ++
- ['0'..'9'] ++
- ['-', '_', '.', '~']
-
--- (chr . read . ("0x" ++) . BC.unpack)
--- connect :: Url -> String -> IO (Benc.BVal)
--- connect url infoHash = case (parseUrl url) of
--- Nothing -> putStrLn "invalid tracker URL"
--- Just req -> let
-
+
+ nonSpecialChars = ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "-_.~"
+
+infoHash :: Map BVal BVal -> ByteString
+infoHash m = let info = m ! Bstr (pack "info")
+ in (hash . pack . encode) info
+
+prepareRequest :: InfoDict -> String -> Integer -> String
+prepareRequest d peer_id len =
+ let p = [("info_hash", urlEncodeHash ((B16.encode . infoHash) d)),
+ ("peer_id", urlEncode peer_id),
+ ("port", "6881"),
+ ("uploaded", "0"),
+ ("downloaded", "0"),
+ ("left", show len),
+ ("compact", "1"),
+ ("event", "started")]
+ in intercalate "&" [f ++ "=" ++ s | (f,s) <- p]
+
+connect :: Url -> String -> IO ByteString
+connect baseurl qstr = simpleHTTP (defaultGETRequest_ url) >>= getResponseBody
+ where url = fromJust . parseURI $ (baseurl ++ "?" ++ qstr)