1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
module Network.BitTorrent.Exchange.Assembler
( Assembler
, insert
-- * Query
, pendingPieces
, completeBlocks
, incompleteBlocks
) where
import Data.IntMap.Strict as IM
import Data.Maybe
import Data.Torrent.Piece
import Data.Torrent.Block
type PieceMap = IntMap
-- TODO move to Data.Torrent.Piece ?
-- assembler is also a block selector?
data Assembler a = Assembler
{ piecePending :: PieceMap [Block a]
, pieceInfo :: PieceInfo
}
data Result a
= Assembled (Piece a)
| Failed PieceIx
-- | You should check if a returned by peer block is actually have
-- been requested and in-flight. This is needed to avoid "I send
-- random corrupted block" attacks.
insert :: Block a -> Assembler a -> (Assembler a, Maybe (Result a))
insert Block {..} Assembler {..} = undefined
-- updateWithKey bixPiece
pendingPieces :: Assembler a -> [PieceIx]
pendingPieces Assembler {..} = keys piecePending
completeBlocks :: Assembler a -> PieceIx -> [Block a]
completeBlocks Assembler {..} pix = fromMaybe [] $ IM.lookup pix piecePending
incompleteBlocks :: Assembler a -> PieceIx -> [BlockIx]
incompleteBlocks = undefined
-- TODO merge BlockSelector with Assembler?
data BlockSelector a = BlockSelector
{ assembler :: Assembler a -- we do not select already transfered blocks
, inflightSet :: Set BlockIx -- we do not select blocks in flight
}
insert :: BlockSelector -> (BlockSelector a, Maybe (Result a))
insert = undefined
data StorageAdapter = StorageAdapter
{ bitfield :: Bitfield
, requestQ :: Queue PieceIx
}
-- we do select 'incompleteBlocks' that is not in flight
--assembler :: Assembler -> Conduit (Block a) (Result a)
--assembler = undefined
-- by priority
-- foreign request queue (max queue size)
-- assembler block information (max queue size)
-- selection strategies (bitfields)
-- when in flight queue is full we do not use selector
-- in flight queue information (max queue size)
-- piece select is used when
data PieceSelector = Selector
{ forceQueue :: TVar (Queue PieceIx)
, forcePendingQueue :: TVar (Queue PieceIx)
, assembler :: TVar Assembler
, strategy :: Bool
}
select :: Selector -> (Selector, PieceIx)
select = undefined
|