diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-02-06 03:37:01 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-02-06 03:37:01 +0400 |
commit | 24ecfb12c6e2c1d8948f6a250d3332af50eab08e (patch) | |
tree | f35e54ee14eebf14f1ec15fca88e640b356888d9 /src/Network/BitTorrent/Tracker | |
parent | 7fefe66f1a3cb2f6f0a80383424592697f79b8b2 (diff) |
Add HTTP tracker RpcExceptions
Diffstat (limited to 'src/Network/BitTorrent/Tracker')
-rw-r--r-- | src/Network/BitTorrent/Tracker/RPC/HTTP.hs | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/src/Network/BitTorrent/Tracker/RPC/HTTP.hs b/src/Network/BitTorrent/Tracker/RPC/HTTP.hs index 0a7e9a08..32a5e79c 100644 --- a/src/Network/BitTorrent/Tracker/RPC/HTTP.hs +++ b/src/Network/BitTorrent/Tracker/RPC/HTTP.hs | |||
@@ -13,6 +13,7 @@ | |||
13 | -- For more information see: | 13 | -- For more information see: |
14 | -- <https://wiki.theory.org/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol> | 14 | -- <https://wiki.theory.org/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol> |
15 | -- | 15 | -- |
16 | {-# LANGUAGE DeriveDataTypeable #-} | ||
16 | module Network.BitTorrent.Tracker.RPC.HTTP | 17 | module Network.BitTorrent.Tracker.RPC.HTTP |
17 | ( -- * Manager | 18 | ( -- * Manager |
18 | Options (..) | 19 | Options (..) |
@@ -22,6 +23,7 @@ module Network.BitTorrent.Tracker.RPC.HTTP | |||
22 | , withManager | 23 | , withManager |
23 | 24 | ||
24 | -- * RPC | 25 | -- * RPC |
26 | , RpcException (..) | ||
25 | , announce | 27 | , announce |
26 | , scrape | 28 | , scrape |
27 | , scrapeOne | 29 | , scrapeOne |
@@ -37,6 +39,7 @@ import Data.ByteString.Lazy as BL | |||
37 | import Data.Default | 39 | import Data.Default |
38 | import Data.List as L | 40 | import Data.List as L |
39 | import Data.Monoid | 41 | import Data.Monoid |
42 | import Data.Typeable | ||
40 | import Network.URI | 43 | import Network.URI |
41 | import Network.HTTP.Conduit hiding | 44 | import Network.HTTP.Conduit hiding |
42 | (Manager, newManager, closeManager, withManager) | 45 | (Manager, newManager, closeManager, withManager) |
@@ -50,6 +53,22 @@ import Network.BitTorrent.Core.Fingerprint (libUserAgent) | |||
50 | import Network.BitTorrent.Tracker.Message | 53 | import Network.BitTorrent.Tracker.Message |
51 | 54 | ||
52 | {----------------------------------------------------------------------- | 55 | {----------------------------------------------------------------------- |
56 | -- Exceptions | ||
57 | -----------------------------------------------------------------------} | ||
58 | |||
59 | data RpcException | ||
60 | = RequestFailed HttpException -- ^ failed HTTP request. | ||
61 | | ParserFailure String -- ^ unable to decode tracker response; | ||
62 | | ScrapelessTracker -- ^ tracker do not support scraping; | ||
63 | | BadScrape -- ^ unable to find info hash in response dict; | ||
64 | deriving (Show, Typeable) | ||
65 | |||
66 | instance Exception RpcException | ||
67 | |||
68 | packHttpException :: IO a -> IO a | ||
69 | packHttpException m = try m >>= either (throwIO . RequestFailed) return | ||
70 | |||
71 | {----------------------------------------------------------------------- | ||
53 | -- Manager | 72 | -- Manager |
54 | -----------------------------------------------------------------------} | 73 | -----------------------------------------------------------------------} |
55 | 74 | ||
@@ -109,9 +128,9 @@ fillRequest Options {..} q r = r | |||
109 | httpTracker :: BEncode a => Manager -> URI -> SimpleQuery -> IO a | 128 | httpTracker :: BEncode a => Manager -> URI -> SimpleQuery -> IO a |
110 | httpTracker Manager {..} uri q = do | 129 | httpTracker Manager {..} uri q = do |
111 | request <- fillRequest options q <$> setUri def uri | 130 | request <- fillRequest options q <$> setUri def uri |
112 | response <- runResourceT $ httpLbs request httpMgr | 131 | response <- packHttpException $ runResourceT $ httpLbs request httpMgr |
113 | case BE.decode $ BL.toStrict $ responseBody response of | 132 | case BE.decode $ BL.toStrict $ responseBody response of |
114 | Left msg -> error $ "httpTracker: " ++ msg | 133 | Left msg -> throwIO (ParserFailure msg) |
115 | Right info -> return info | 134 | Right info -> return info |
116 | 135 | ||
117 | {----------------------------------------------------------------------- | 136 | {----------------------------------------------------------------------- |
@@ -121,6 +140,8 @@ httpTracker Manager {..} uri q = do | |||
121 | -- | Send request and receive response from the tracker specified in | 140 | -- | Send request and receive response from the tracker specified in |
122 | -- announce list. | 141 | -- announce list. |
123 | -- | 142 | -- |
143 | -- This function can throw 'RpcException'. | ||
144 | -- | ||
124 | announce :: Manager -> URI -> AnnounceQuery -> IO AnnounceInfo | 145 | announce :: Manager -> URI -> AnnounceQuery -> IO AnnounceInfo |
125 | announce mgr uri q = httpTracker mgr uri (renderAnnounceRequest uriQ) | 146 | announce mgr uri q = httpTracker mgr uri (renderAnnounceRequest uriQ) |
126 | where | 147 | where |
@@ -148,17 +169,21 @@ scrapeURL uri = do | |||
148 | -- However if the info hash list is 'null', the tracker should list | 169 | -- However if the info hash list is 'null', the tracker should list |
149 | -- all available torrents. | 170 | -- all available torrents. |
150 | -- | 171 | -- |
172 | -- This function can throw 'RpcException'. | ||
173 | -- | ||
151 | scrape :: Manager -> URI -> ScrapeQuery -> IO ScrapeInfo | 174 | scrape :: Manager -> URI -> ScrapeQuery -> IO ScrapeInfo |
152 | scrape m u q = do | 175 | scrape m u q = do |
153 | case scrapeURL u of | 176 | case scrapeURL u of |
154 | Nothing -> error "Tracker do not support scraping" | 177 | Nothing -> throwIO ScrapelessTracker |
155 | Just uri -> httpTracker m uri (renderScrapeQuery q) | 178 | Just uri -> httpTracker m uri (renderScrapeQuery q) |
156 | 179 | ||
157 | -- | More particular version of 'scrape', just for one torrent. | 180 | -- | More particular version of 'scrape', just for one torrent. |
158 | -- | 181 | -- |
182 | -- This function can throw RpcException. | ||
183 | -- | ||
159 | scrapeOne :: Manager -> URI -> InfoHash -> IO ScrapeEntry | 184 | scrapeOne :: Manager -> URI -> InfoHash -> IO ScrapeEntry |
160 | scrapeOne m uri ih = do | 185 | scrapeOne m uri ih = do |
161 | xs <- scrape m uri [ih] | 186 | xs <- scrape m uri [ih] |
162 | case L.lookup ih xs of | 187 | case L.lookup ih xs of |
163 | Nothing -> error "unable to find info hash in response dict" | 188 | Nothing -> throwIO BadScrape |
164 | Just a -> return a | 189 | Just a -> return a |