summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r--src/Network/BitTorrent/Core/PeerId.hs18
-rw-r--r--src/Network/BitTorrent/Tracker/Message.hs108
2 files changed, 79 insertions, 47 deletions
diff --git a/src/Network/BitTorrent/Core/PeerId.hs b/src/Network/BitTorrent/Core/PeerId.hs
index 2c79739a..a2b03e92 100644
--- a/src/Network/BitTorrent/Core/PeerId.hs
+++ b/src/Network/BitTorrent/Core/PeerId.hs
@@ -15,6 +15,7 @@
15module Network.BitTorrent.Core.PeerId 15module Network.BitTorrent.Core.PeerId
16 ( -- * PeerId 16 ( -- * PeerId
17 PeerId (getPeerId) 17 PeerId (getPeerId)
18 , byteStringToPeerId
18 19
19 -- * Generation 20 -- * Generation
20 , genPeerId 21 , genPeerId
@@ -60,30 +61,37 @@ import Paths_bittorrent (version)
60 61
61import Data.Torrent.Client 62import Data.Torrent.Client
62 63
63-- TODO use unpacked form (length is known statically) 64-- TODO use unpacked Word160 form (length is known statically)
64 65
65-- | Peer identifier is exactly 20 bytes long bytestring. 66-- | Peer identifier is exactly 20 bytes long bytestring.
66newtype PeerId = PeerId { getPeerId :: ByteString } 67newtype PeerId = PeerId { getPeerId :: ByteString }
67 deriving (Show, Eq, Ord, BEncode, ToJSON, FromJSON) 68 deriving (Show, Eq, Ord, BEncode, ToJSON, FromJSON)
68 69
70peerIdLen :: Int
71peerIdLen = 20
72
69instance Serialize PeerId where 73instance Serialize PeerId where
70 put = putByteString . getPeerId 74 put = putByteString . getPeerId
71 get = PeerId <$> getBytes 20 75 get = PeerId <$> getBytes peerIdLen
72 76
73instance URLShow PeerId where 77instance URLShow PeerId where
74 urlShow = BC.unpack . getPeerId 78 urlShow = BC.unpack . getPeerId
75 79
76instance IsString PeerId where 80instance IsString PeerId where
77 fromString str 81 fromString str
78 | BS.length bs == 20 = PeerId bs 82 | BS.length bs == peerIdLen = PeerId bs
79 | otherwise = error $ "Peer id should be 20 bytes long: " 83 | otherwise = error $ "Peer id should be 20 bytes long: " ++ show str
80 ++ show str
81 where 84 where
82 bs = fromString str 85 bs = fromString str
83 86
84instance Pretty PeerId where 87instance Pretty PeerId where
85 pretty = text . BC.unpack . getPeerId 88 pretty = text . BC.unpack . getPeerId
86 89
90byteStringToPeerId :: BS.ByteString -> Maybe PeerId
91byteStringToPeerId bs
92 | BS.length bs == peerIdLen = Just (PeerId bs)
93 | otherwise = Nothing
94
87{----------------------------------------------------------------------- 95{-----------------------------------------------------------------------
88-- Encoding 96-- Encoding
89-----------------------------------------------------------------------} 97-----------------------------------------------------------------------}
diff --git a/src/Network/BitTorrent/Tracker/Message.hs b/src/Network/BitTorrent/Tracker/Message.hs
index 3447a367..59ef2027 100644
--- a/src/Network/BitTorrent/Tracker/Message.hs
+++ b/src/Network/BitTorrent/Tracker/Message.hs
@@ -52,6 +52,8 @@ import Data.Aeson (ToJSON(..), FromJSON(..))
52import Data.Aeson.TH 52import Data.Aeson.TH
53import Data.BEncode as BE 53import Data.BEncode as BE
54import Data.BEncode.BDict as BE 54import Data.BEncode.BDict as BE
55import Data.ByteString as BS
56import Data.ByteString.Char8 as BC
55import Data.Char as Char 57import Data.Char as Char
56import Data.List as L 58import Data.List as L
57import Data.Map as M 59import Data.Map as M
@@ -64,8 +66,10 @@ import Data.Typeable
64import Data.URLEncoded as URL 66import Data.URLEncoded as URL
65import Data.Word 67import Data.Word
66import Network 68import Network
67import Network.URI 69import Network.HTTP.Types.URI hiding (urlEncode)
68import Network.Socket 70import Network.Socket
71import Network.URI
72import Text.Read (readMaybe)
69 73
70import Data.Torrent.InfoHash 74import Data.Torrent.InfoHash
71import Data.Torrent.Progress 75import Data.Torrent.Progress
@@ -226,63 +230,83 @@ data QueryParam
226 = ParamInfoHash 230 = ParamInfoHash
227 | ParamPeerId 231 | ParamPeerId
228 | ParamPort 232 | ParamPort
229 | ParamProgress 233 | ParamUploaded
234 | ParamLeft
235 | ParamDownloaded
230 | ParamIP 236 | ParamIP
231 | ParamNumWant 237 | ParamNumWant
232 | ParamEvent 238 | ParamEvent
233 deriving (Show, Eq, Ord, Enum) 239 deriving (Show, Eq, Ord, Enum)
234 240
235data ParamParseFailure 241data ParamParseFailure
236 = Missing QueryParam -- ^ param not found in query string; 242 = Missing QueryParam -- ^ param not found in query string;
237 | Invalid QueryParam Text -- ^ param present but not valid. 243 | Invalid QueryParam ByteString -- ^ param present but not valid.
238 deriving (Show, Eq) 244 deriving (Show, Eq)
239 245
240type ParamResult = Either ParamParseFailure 246paramName :: QueryParam -> ByteString
247paramName ParamInfoHash = "info_hash"
248paramName ParamPeerId = "peer_id"
249paramName ParamPort = "port"
250paramName ParamUploaded = "uploaded"
251paramName ParamLeft = "left"
252paramName ParamDownloaded = "downloaded"
253paramName ParamIP = "ip"
254paramName ParamNumWant = "numwant"
255paramName ParamEvent = "event"
256
257class FromParam a where
258 fromParam :: BS.ByteString -> Maybe a
259
260instance FromParam InfoHash where
261 fromParam = byteStringToInfoHash
262
263instance FromParam PeerId where
264 fromParam = byteStringToPeerId
265
266instance FromParam Word32 where
267 fromParam = readMaybe . BC.unpack
268
269instance FromParam Word64 where
270 fromParam = readMaybe . BC.unpack
271
272instance FromParam Int where
273 fromParam = readMaybe . BC.unpack
241 274
242textToPeerId :: Text -> Maybe PeerId 275instance FromParam PortNumber where
243textToPeerId = undefined 276 fromParam bs = fromIntegral <$> (fromParam bs :: Maybe Word32)
244 277
245textToPortNumber :: Text -> Maybe PortNumber 278instance FromParam Event where
246textToPortNumber = undefined 279 fromParam bs = case BC.uncons bs of
280 Nothing -> Nothing
281 Just (x, xs) -> readMaybe $ BC.unpack $ BC.cons (Char.toUpper x) xs
247 282
248textToHostAddress :: Text -> Maybe HostAddress 283withError e = maybe (Left e) Right
249textToHostAddress = undefined
250 284
251textToNumWant :: Text -> Maybe Int 285reqParam param xs = do
252textToNumWant = undefined 286 val <- withError (Missing param) $ L.lookup (paramName param) xs
287 withError (Invalid param val) (fromParam val)
253 288
254textToEvent :: Text -> Maybe Event 289optParam param ps
255textToEvent = undefined 290 | Just x <- L.lookup (paramName param) ps
291 = pure <$> withError (Invalid param x) (fromParam x)
292 | otherwise = pure Nothing
256 293
257paramName :: QueryParam -> Text 294parseProgress :: SimpleQuery -> Either ParamParseFailure Progress
258paramName ParamInfoHash = "info_hash" 295parseProgress params = Progress
259paramName ParamPeerId = "peer_id" 296 <$> reqParam ParamDownloaded params
260paramName ParamPort = "port" 297 <*> reqParam ParamLeft params
298 <*> reqParam ParamUploaded params
261 299
262-- | Parse announce request from a decoded query string. 300-- | Parse announce request from a query string.
263parseAnnounceQuery :: [(Text, Text)] -> Either ParamParseFailure AnnounceQuery 301parseAnnounceQuery :: SimpleQuery -> Either ParamParseFailure AnnounceQuery
264parseAnnounceQuery params = AnnounceQuery 302parseAnnounceQuery params = AnnounceQuery
265 <$> reqParam ParamInfoHash textToInfoHash params 303 <$> reqParam ParamInfoHash params
266 <*> reqParam ParamPeerId textToPeerId params 304 <*> reqParam ParamPeerId params
267 <*> reqParam ParamPort textToPortNumber params 305 <*> reqParam ParamPort params
268 <*> progress params 306 <*> parseProgress params
269 <*> optParam ParamIP textToHostAddress params 307 <*> optParam ParamIP params
270 <*> optParam ParamNumWant textToNumWant params 308 <*> optParam ParamNumWant params
271 <*> optParam ParamEvent textToEvent params 309 <*> optParam ParamEvent params
272 where
273 withError e = maybe (Left e) Right
274 reqParam param p = withError (Missing param) . L.lookup (paramName param)
275 >=> \x -> withError (Invalid param x) (p x)
276
277 optParam param p ps
278 | Just x <- L.lookup (paramName param) ps
279 = pure <$> withError (Invalid param x) (p x)
280 | otherwise = pure Nothing
281
282 progress = undefined
283 ip = undefined
284 numwant = undefined
285 event = undefined
286 310
287-- TODO add extension datatype 311-- TODO add extension datatype
288 312