summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Exchange/Assembler.hs
blob: aa009f493184ca0f4e506d7205e69236dfc1c7b9 (plain)
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
-- |
--   Copyright   :  (c) Sam Truzjan 2013
--   License     :  BSD3
--   Maintainer  :  pxqr.sta@gmail.com
--   Stability   :  experimental
--   Portability :  portable
--
--   Assembler is used to build pieces from blocks. In general
--   'Assembler' should be used to handle 'Transfer' messages when
--
--   A block can have one of the following status:
--
--     1) /not allowed/: Piece is not in download set. 'null' and 'empty'.
--
--
--     2) /waiting/: (allowed?) Block have been allowed to download,
--     but /this/ peer did not send any 'Request' message for this
--     block. To allow some piece use
--     'Network.BitTorrent.Exchange.Selector' and then 'allowedSet'
--     and 'allowPiece'.
--
--     3) /inflight/: (pending?) Block have been requested but
--     /remote/ peer did not send any 'Piece' message for this block.
--     Related functions 'markInflight'
--
--     4) /pending/: (stalled?) Block have have been downloaded
--     Related functions 'insertBlock'.
--
--   Piece status:
--
--     1) /assembled/: (downloaded?) All blocks in piece have been
--     downloaded but the piece did not verified yet.
--
--       * Valid: go to completed;
--
--       * Invalid: go to waiting.
--
--     2) /corrupted/:
--
--     3) /downloaded/: (verified?) A piece have been successfully
--     verified via the hash. Usually the piece should be stored to
--     the 'System.Torrent.Storage' and /this/ peer should send 'Have'
--     messages to the /remote/ peers.
--
{-# LANGUAGE TemplateHaskell #-}
module Network.BitTorrent.Exchange.Assembler
       ( -- * Assembler
         Assembler

         -- * Query
       , Network.BitTorrent.Exchange.Assembler.null
       , Network.BitTorrent.Exchange.Assembler.size

         -- * Construction
       , Network.BitTorrent.Exchange.Assembler.empty
       , Network.BitTorrent.Exchange.Assembler.allowPiece

         -- * Debugging
       , Network.BitTorrent.Exchange.Assembler.valid
       ) where

import Control.Applicative
import Control.Lens
import Data.IntMap.Strict as IM
import Data.List as L
import Data.Map as M
import Data.Maybe
import Data.IP

import Data.Torrent.Piece
import Network.BitTorrent.Core
import Network.BitTorrent.Exchange.Block as B

{-----------------------------------------------------------------------
--  Assembler
-----------------------------------------------------------------------}

type BlockRange = (BlockOffset, BlockSize)
type PieceMap = IntMap

data Assembler = Assembler
  { -- | A set of blocks that have been 'Request'ed but not yet acked.
    _inflight :: Map (PeerAddr IP) (PieceMap [BlockRange])

    -- | A set of blocks that but not yet assembled.
  , _pending  :: PieceMap Bucket

    -- | Used for validation of assembled pieces.
  , info      :: PieceInfo
  }

$(makeLenses ''Assembler)


valid :: Assembler -> Bool
valid = undefined

data Result a
  = Completed   (Piece a)
  | Corrupted    PieceIx
  | NotRequested PieceIx
  | Overlapped   BlockIx

null :: Assembler -> Bool
null = undefined

size :: Assembler -> Bool
size = undefined

empty :: PieceInfo -> Assembler
empty = Assembler M.empty IM.empty

allowPiece :: PieceIx -> Assembler -> Assembler
allowPiece pix a @ Assembler {..}  = over pending (IM.insert pix bkt) a
  where
    bkt = B.empty (piPieceLength info)

allowedSet :: (PeerAddr IP) -> Assembler -> [BlockIx]
allowedSet = undefined

--inflight :: PeerAddr -> BlockIx -> Assembler -> Assembler
--inflight = undefined

--  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 :: (PeerAddr IP) -> Block a -> Assembler -> Assembler
insert = undefined

{-
insert :: Block a -> Assembler a -> (Assembler a, Maybe (Result a))
insert blk @ Block {..} a @ Assembler {..} = undefined
{-
  = let (pending, mpiece) = inserta blk piecePending
    in (Assembler inflightSet pending pieceInfo, f <$> mpiece)
  where
    f p = undefined
--      | checkPieceLazy pieceInfo p = Assembled p
--      |          otherwise         = Corrupted ixPiece
-}


inflightPieces :: Assembler a -> [PieceIx]
inflightPieces Assembler {..} = IM.keys piecePending

completeBlocks :: PieceIx -> Assembler a -> [Block a]
completeBlocks pix Assembler {..}  = fromMaybe [] $ IM.lookup pix piecePending

incompleteBlocks :: PieceIx -> Assembler a -> [BlockIx]
incompleteBlocks = undefined

nextBlock :: Assembler a -> Maybe (Assembler a, BlockIx)
nextBlock Assembler {..} = undefined

inserta :: Block a
        -> PieceMap [Block a]
        -> (PieceMap [Block a], Maybe (Piece a))
inserta = undefined

-}