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