summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Tracker
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/Tracker')
-rw-r--r--src/Network/BitTorrent/Tracker/Message.hs24
-rw-r--r--src/Network/BitTorrent/Tracker/Wai.hs64
2 files changed, 62 insertions, 26 deletions
diff --git a/src/Network/BitTorrent/Tracker/Message.hs b/src/Network/BitTorrent/Tracker/Message.hs
index 54de44f7..dc8794b6 100644
--- a/src/Network/BitTorrent/Tracker/Message.hs
+++ b/src/Network/BitTorrent/Tracker/Message.hs
@@ -51,8 +51,6 @@ module Network.BitTorrent.Tracker.Message
51 , defaultNumWant 51 , defaultNumWant
52 , defaultMaxNumWant 52 , defaultMaxNumWant
53 , defaultReannounceInterval 53 , defaultReannounceInterval
54 , announceType
55 , parseFailureStatus
56 54
57 -- * Scrape 55 -- * Scrape
58 -- ** Query 56 -- ** Query
@@ -64,6 +62,14 @@ module Network.BitTorrent.Tracker.Message
64 , ScrapeEntry (..) 62 , ScrapeEntry (..)
65 , ScrapeInfo 63 , ScrapeInfo
66 64
65 -- * HTTP specific
66 , RawPath
67 , defaultAnnouncePath
68 , defaultScrapePath
69 , announceType
70 , scrapeType
71 , parseFailureStatus
72
67 -- * Extra 73 -- * Extra
68 , queryToSimpleQuery 74 , queryToSimpleQuery
69 ) 75 )
@@ -615,6 +621,14 @@ defaultMaxNumWant = 200
615defaultReannounceInterval :: Int 621defaultReannounceInterval :: Int
616defaultReannounceInterval = 30 * 60 622defaultReannounceInterval = 30 * 60
617 623
624type RawPath = BS.ByteString
625
626defaultAnnouncePath :: RawPath
627defaultAnnouncePath = "announce"
628
629defaultScrapePath :: RawPath
630defaultScrapePath = "scrape"
631
618missingOffset :: Int 632missingOffset :: Int
619missingOffset = 101 633missingOffset = 101
620 634
@@ -630,10 +644,14 @@ parseFailureMessage e = BS.concat $ case e of
630 Missing p -> ["Missing parameter: ", paramName p] 644 Missing p -> ["Missing parameter: ", paramName p]
631 Invalid p v -> ["Invalid parameter: ", paramName p, " = ", v] 645 Invalid p v -> ["Invalid parameter: ", paramName p, " = ", v]
632 646
633-- | HTTP response /content type/. 647-- | HTTP response /content type/ for announce info.
634announceType :: ByteString 648announceType :: ByteString
635announceType = "text/plain" 649announceType = "text/plain"
636 650
651-- | HTTP response /content type/ for scrape info.
652scrapeType :: ByteString
653scrapeType = "text/plain"
654
637-- | Get HTTP response status from a announce params parse failure. 655-- | Get HTTP response status from a announce params parse failure.
638-- 656--
639-- For more info see: 657-- For more info see:
diff --git a/src/Network/BitTorrent/Tracker/Wai.hs b/src/Network/BitTorrent/Tracker/Wai.hs
index 69510fa0..29e0e952 100644
--- a/src/Network/BitTorrent/Tracker/Wai.hs
+++ b/src/Network/BitTorrent/Tracker/Wai.hs
@@ -16,6 +16,7 @@ module Network.BitTorrent.Tracker.Wai
16 , tracker 16 , tracker
17 ) where 17 ) where
18 18
19import Control.Applicative
19import Control.Monad.Trans.Resource 20import Control.Monad.Trans.Resource
20import Data.BEncode as BE 21import Data.BEncode as BE
21import Data.ByteString 22import Data.ByteString
@@ -30,9 +31,12 @@ import Network.BitTorrent.Tracker.Message
30 31
31-- | Various configuration settings used to generate tracker response. 32-- | Various configuration settings used to generate tracker response.
32data TrackerSettings = TrackerSettings 33data TrackerSettings = TrackerSettings
33 { -- | If peer did not specified the "numwant" then this value is 34 { announcePath :: !RawPath
35 , scrapePath :: !RawPath
36
37 -- | If peer did not specified the "numwant" then this value is
34 -- used. 38 -- used.
35 defNumWant :: {-# UNPACK #-} !Int 39 , defNumWant :: {-# UNPACK #-} !Int
36 40
37 -- | If peer specified too big numwant value. 41 -- | If peer specified too big numwant value.
38 , maxNumWant :: {-# UNPACK #-} !Int 42 , maxNumWant :: {-# UNPACK #-} !Int
@@ -63,7 +67,9 @@ data TrackerSettings = TrackerSettings
63-- | Conservative tracker settings compatible with any client. 67-- | Conservative tracker settings compatible with any client.
64instance Default TrackerSettings where 68instance Default TrackerSettings where
65 def = TrackerSettings 69 def = TrackerSettings
66 { defNumWant = defaultNumWant 70 { announcePath = defaultAnnouncePath
71 , scrapePath = defaultScrapePath
72 , defNumWant = defaultNumWant
67 , maxNumWant = defaultMaxNumWant 73 , maxNumWant = defaultMaxNumWant
68 , reannounceInterval = defaultReannounceInterval 74 , reannounceInterval = defaultReannounceInterval
69 , reannounceMinInterval = Nothing 75 , reannounceMinInterval = Nothing
@@ -73,34 +79,46 @@ instance Default TrackerSettings where
73 , noPeerId = False 79 , noPeerId = False
74 } 80 }
75 81
82
83
84{-----------------------------------------------------------------------
85-- Handlers
86-----------------------------------------------------------------------}
87
76getAnnounceR :: TrackerSettings -> AnnounceRequest -> ResourceT IO AnnounceInfo 88getAnnounceR :: TrackerSettings -> AnnounceRequest -> ResourceT IO AnnounceInfo
77getAnnounceR = undefined 89getAnnounceR = undefined
78 90
79getScrapeR :: TrackerSettings -> ScrapeQuery -> ResourceT IO ScrapeInfo 91getScrapeR :: TrackerSettings -> ScrapeQuery -> ResourceT IO ScrapeInfo
80getScrapeR = undefined 92getScrapeR = undefined
81 93
94{-----------------------------------------------------------------------
95-- Routing
96-----------------------------------------------------------------------}
97
98announceResponse :: AnnounceInfo -> Response
99announceResponse info = responseLBS ok200 headers $ BE.encode info
100 where
101 headers = [(hContentType, announceType)]
102
103scrapeResponse :: ScrapeInfo -> Response
104scrapeResponse info = responseLBS ok200 headers $ BE.encode info
105 where
106 headers = [(hContentType, scrapeType)]
107
82-- content-type: "text/plain"! 108-- content-type: "text/plain"!
83tracker :: TrackerSettings -> Application 109tracker :: TrackerSettings -> Application
84tracker settings Request {..} 110tracker settings @ TrackerSettings {..} Request {..}
85 | requestMethod /= methodGet 111 | requestMethod /= methodGet
86 = return $ responseLBS methodNotAllowed405 [] "" 112 = return $ responseLBS methodNotAllowed405 [] ""
87 113
88 | otherwise = do 114 | rawPathInfo == announcePath = do
89 case pathInfo of 115 case parseAnnounceRequest $ queryToSimpleQuery queryString of
90 ["announce"] -> 116 Right query -> announceResponse <$> getAnnounceR settings query
91 case parseAnnounceRequest $ queryToSimpleQuery queryString of 117 Left msg -> return $ responseLBS (parseFailureStatus msg) [] ""
92 Right query -> do 118
93 info <- getAnnounceR settings query 119 | rawPathInfo == scrapePath = do
94 return $ responseLBS ok200 [] $ BE.encode info 120 case Right $ parseScrapeQuery $ queryToSimpleQuery queryString of -- TODO
95 Left msg -> 121 Right query -> scrapeResponse <$> getScrapeR settings query
96 return $ responseLBS (parseFailureStatus msg) [] "" 122 Left msg -> return $ responseLBS badRequest400 [] ""
97 123
98 ["scrape"] -> 124 | otherwise = undefined --badPath
99 case Right $ parseScrapeQuery $ queryToSimpleQuery queryString of -- TODO
100 Right query -> do
101 info <- getScrapeR settings query
102 return $ responseLBS ok200 [] $ BE.encode info
103 Left _ ->
104 return $ responseLBS badRequest400 [] ""
105
106 _ -> undefined --badPath