diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-02-15 04:18:05 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-02-15 04:18:05 +0400 |
commit | 0fa6a0ee5eb1fbf648d3864626430efcbdb4aaae (patch) | |
tree | 7d2c6b8db43943974772069efb22480db8186bb1 /src/Network/BitTorrent/Exchange/Session/Metadata.hs | |
parent | daf978ddd1f0a07ce4711fa97f51d0ec02478f73 (diff) |
Move metadata exchange from Wire to Session
Diffstat (limited to 'src/Network/BitTorrent/Exchange/Session/Metadata.hs')
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session/Metadata.hs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/Network/BitTorrent/Exchange/Session/Metadata.hs b/src/Network/BitTorrent/Exchange/Session/Metadata.hs new file mode 100644 index 00000000..7e14f493 --- /dev/null +++ b/src/Network/BitTorrent/Exchange/Session/Metadata.hs | |||
@@ -0,0 +1,93 @@ | |||
1 | {-# LANGUAGE TemplateHaskell #-} | ||
2 | module Network.BitTorrent.Exchange.Session.Metadata | ||
3 | ( -- * Metadata transfer state | ||
4 | Status | ||
5 | , nullStatus | ||
6 | |||
7 | -- * Metadata updates | ||
8 | , Updates | ||
9 | , runUpdates | ||
10 | |||
11 | -- * Metadata piece control | ||
12 | , scheduleBlock | ||
13 | , resetPending | ||
14 | , cancelPending | ||
15 | , pushBlock | ||
16 | ) where | ||
17 | |||
18 | import Control.Concurrent | ||
19 | import Control.Lens | ||
20 | import Control.Monad.State | ||
21 | import Data.ByteString as BS | ||
22 | import Data.ByteString.Lazy as BL | ||
23 | import Data.List as L | ||
24 | |||
25 | import Data.BEncode as BE | ||
26 | import Data.Torrent | ||
27 | import Data.Torrent.InfoHash | ||
28 | import Data.Torrent.Piece as Torrent | ||
29 | import Network.BitTorrent.Core | ||
30 | import Network.BitTorrent.Exchange.Block as Block | ||
31 | import Network.BitTorrent.Exchange.Message as Message hiding (Status) | ||
32 | |||
33 | |||
34 | data Status = Status | ||
35 | { _pending :: [(PeerAddr IP, PieceIx)] | ||
36 | , _bucket :: Bucket | ||
37 | } | ||
38 | |||
39 | makeLenses ''Status | ||
40 | |||
41 | nullStatus :: PieceSize -> Status | ||
42 | nullStatus ps = Status [] (Block.empty ps) | ||
43 | |||
44 | type Updates a = State Status a | ||
45 | |||
46 | runUpdates :: MVar Status -> Updates a -> IO a | ||
47 | runUpdates v m = undefined | ||
48 | |||
49 | scheduleBlock :: PeerAddr IP -> Updates (Maybe PieceIx) | ||
50 | scheduleBlock addr = do | ||
51 | bkt <- use bucket | ||
52 | case spans metadataPieceSize bkt of | ||
53 | [] -> return Nothing | ||
54 | ((off, _ ) : _) -> do | ||
55 | let pix = undefined | ||
56 | pending %= ((addr, pix) :) | ||
57 | return (Just pix) | ||
58 | |||
59 | cancelPending :: PieceIx -> Updates () | ||
60 | cancelPending pix = pending %= L.filter ((pix ==) . snd) | ||
61 | |||
62 | resetPending :: PeerAddr IP -> Updates () | ||
63 | resetPending addr = pending %= L.filter ((addr ==) . fst) | ||
64 | |||
65 | parseInfoDict :: BS.ByteString -> InfoHash -> Result InfoDict | ||
66 | parseInfoDict chunk topic = | ||
67 | case BE.decode chunk of | ||
68 | Right (infodict @ InfoDict {..}) | ||
69 | | topic == idInfoHash -> return infodict | ||
70 | | otherwise -> Left "broken infodict" | ||
71 | Left err -> Left $ "unable to parse infodict " ++ err | ||
72 | |||
73 | -- todo use incremental parsing to avoid BS.concat call | ||
74 | pushBlock :: PeerAddr IP -> Torrent.Piece BS.ByteString -> InfoHash | ||
75 | -> Updates (Maybe InfoDict) | ||
76 | pushBlock addr Torrent.Piece {..} topic = do | ||
77 | p <- use pending | ||
78 | when ((addr, pieceIndex) `L.notElem` p) $ error "not requested" | ||
79 | cancelPending pieceIndex | ||
80 | |||
81 | bucket %= Block.insert (metadataPieceSize * pieceIndex) pieceData | ||
82 | b <- use bucket | ||
83 | case toPiece b of | ||
84 | Nothing -> return Nothing | ||
85 | Just chunks -> | ||
86 | case parseInfoDict (BL.toStrict chunks) topic of | ||
87 | Right x -> do | ||
88 | pending .= [] | ||
89 | return (Just x) | ||
90 | Left e -> do | ||
91 | pending .= [] | ||
92 | bucket .= Block.empty (Block.size b) | ||
93 | return Nothing | ||