summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Exchange.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/Exchange.hs')
-rw-r--r--src/Network/BitTorrent/Exchange.hs182
1 files changed, 98 insertions, 84 deletions
diff --git a/src/Network/BitTorrent/Exchange.hs b/src/Network/BitTorrent/Exchange.hs
index 4fe90cda..b23ca667 100644
--- a/src/Network/BitTorrent/Exchange.hs
+++ b/src/Network/BitTorrent/Exchange.hs
@@ -11,6 +11,7 @@
11{-# LANGUAGE RecordWildCards #-} 11{-# LANGUAGE RecordWildCards #-}
12module Network.BitTorrent.Exchange 12module Network.BitTorrent.Exchange
13 ( P2P, withPeer 13 ( P2P, withPeer
14 , awaitEvent, signalEvent
14 ) where 15 ) where
15 16
16import Control.Applicative 17import Control.Applicative
@@ -41,117 +42,130 @@ import Network.BitTorrent.Peer
41import Data.Bitfield as BF 42import Data.Bitfield as BF
42import Data.Torrent 43import Data.Torrent
43 44
44{-----------------------------------------------------------------------
45 P2P monad
46-----------------------------------------------------------------------}
47
48type PeerWire = ConduitM Message Message IO
49
50waitMessage :: PeerWire Message
51waitMessage = await >>= maybe waitMessage return
52
53signalMessage :: Message -> PeerWire ()
54signalMessage = C.yield
55
56newtype P2P a = P2P {
57 runP2P :: ReaderT PeerSession PeerWire a
58 } deriving (Monad, MonadReader PeerSession, MonadIO)
59
60instance MonadState Bitfield P2P where
61
62runConduit :: Socket -> Conduit Message IO Message -> IO ()
63runConduit sock p2p =
64 sourceSocket sock $=
65 conduitGet S.get $=
66 forever p2p $=
67 conduitPut S.put $$
68 sinkSocket sock
69
70withPeer :: SwarmSession -> PeerAddr -> P2P () -> IO ()
71withPeer se addr p2p =
72 withPeerSession se addr $ \(sock, pses) -> do
73 runConduit sock (runReaderT (runP2P p2p) pses)
74 45
75data Event = Available Bitfield 46data Event = Available Bitfield
76 | Want 47 | Want
77 | Block 48 | Block
78 49
50{-----------------------------------------------------------------------
51 Peer wire
52-----------------------------------------------------------------------}
79 53
54type PeerWire = ConduitM Message Message IO
80 55
81waitForEvent :: P2P Event 56waitMessage :: PeerSession -> PeerWire Message
82waitForEvent = P2P (ReaderT nextEvent) 57waitMessage se = do
83 where 58 mmsg <- await
84 nextEvent se @ PeerSession {..} = waitMessage >>= diff 59 case mmsg of
85 where 60 Nothing -> waitMessage se
86 -- diff finds difference between 61 Just msg -> do
87 diff KeepAlive = do 62 liftIO $ updateIncoming se
88 signalMessage KeepAlive 63 return msg
89 nextEvent se
90 64
91 handleMessage Choke = do 65signalMessage :: Message -> PeerSession -> PeerWire ()
92 SessionStatus {..} <- liftIO $ readIORef peerSessionStatus 66signalMessage msg se = do
93 if psChoking sePeerStatus 67 C.yield msg
94 then nextEvent se 68 liftIO $ updateOutcoming se
95 else undefined
96 69
97 handleMessage Unchoke = return $ Available BF.difference
98 70
99 handleMessage Interested = return undefined 71getPieceCount :: PeerSession -> IO PieceCount
100 handleMessage NotInterested = return undefined 72getPieceCount = undefined
101 73
102 handleMessage (Have ix) = do 74nextEvent :: PeerSession -> PeerWire Event
75nextEvent se @ PeerSession {..} = waitMessage se >>= diff
76 where
77 -- diff finds difference between
78-- diff KeepAlive = nextEvent se
79 diff msg = do
80 liftIO $ print (ppMessage msg)
81 nextEvent se
82
83 handleMessage Choke = do
84 SessionStatus {..} <- liftIO $ readIORef peerSessionStatus
85 if psChoking sePeerStatus
86 then nextEvent se
87 else undefined
88
89 handleMessage Unchoke = undefined
90 --return $ Available BF.difference
91
92 handleMessage Interested = return undefined
93 handleMessage NotInterested = return undefined
94 handleMessage (Have ix) = do
95 pc <- liftIO $ getPieceCount se
96 haveMessage $ have ix (haveNone pc) -- TODO singleton
97
98 handleMessage (Bitfield bf) = undefined
99 handleMessage (Request bix) = do
100 undefined
101
102 handleMessage msg @ (Piece blk) = undefined
103 handleMessage msg @ (Port _)
104 = checkExtension msg ExtDHT $ do
105 undefined
106
107 handleMessage msg @ HaveAll
108 = checkExtension msg ExtFast $ do
103 pc <- liftIO $ getPieceCount se 109 pc <- liftIO $ getPieceCount se
104 haveMessage $ have ix (haveNone pc) -- TODO singleton 110 haveMessage (haveAll pc)
105
106 handleMessage (Bitfield bf) = undefined
107 handleMessage (Request bix) = do
108 undefined
109
110 handleMessage (Piece blk) = undefined
111 handleMessage (Port _)
112 = checkExtension msg ExtDHT $ do
113 undefined
114 111
115 handleMessage msg @ HaveAll 112 handleMessage msg @ HaveNone
116 = checkExtension msg ExtFast $ do 113 = checkExtension msg ExtFast $ do
117 pc <- liftIO $ getPieceCount se 114 pc <- liftIO $ getPieceCount se
118 haveMessage (haveAll pc) 115 haveMessage (haveNone pc)
119
120 handleMessage msg @ HaveNone
121 = checkExtension msg ExtFast $ do
122 pc <- liftIO $ getPieceCount se
123 haveMessage (haveNone pc)
124 116
125 handleMessage msg @ (SuggestPiece ix) 117 handleMessage msg @ (SuggestPiece ix)
126 = checkExtension msg ExtFast $ do 118 = checkExtension msg ExtFast $ do
127 undefined 119 undefined
128 120
129 handleMessage msg @ (RejectRequest ix) 121 handleMessage msg @ (RejectRequest ix)
130 = checkExtension msg ExtFast $ do 122 = checkExtension msg ExtFast $ do
131 undefined 123 undefined
132 124
133 handleMessage msg @ (AllowedFast pix) 125 handleMessage msg @ (AllowedFast pix)
134 = checkExtension msg ExtFast $ do 126 = checkExtension msg ExtFast $ do
135 undefined 127 undefined
136 128
137 haveMessage bf = do 129 haveMessage bf = do
138 cbf <- liftIO $ readIORef $ clientBitfield swarmSession 130 cbf <- liftIO $ readIORef $ clientBitfield swarmSession
139 if undefined -- ix `member` bf 131 if undefined -- ix `member` bf
140 then nextEvent se 132 then nextEvent se
141 else return $ Available diff 133 else undefined -- return $ Available diff
142 134
143 checkExtension msg requredExtension action 135 checkExtension msg requredExtension action
144 | requredExtension `elem` enabledExtensions = action 136 | requredExtension `elem` enabledExtensions = action
145 | otherwise = liftIO $ throwIO $ userError errorMsg 137 | otherwise = liftIO $ throwIO $ userError errorMsg
146 where 138 where
147 errorMsg = show (ppExtension requredExtension) 139 errorMsg = show (ppExtension requredExtension)
148 ++ "not enabled, but peer sent" 140 ++ "not enabled, but peer sent"
149 ++ show (ppMessage msg) 141 ++ show (ppMessage msg)
150 142
143{-----------------------------------------------------------------------
144 P2P monad
145-----------------------------------------------------------------------}
151 146
147newtype P2P a = P2P {
148 runP2P :: ReaderT PeerSession PeerWire a
149 } deriving (Monad, MonadReader PeerSession, MonadIO)
152 150
153getPieceCount :: PeerSession -> IO PieceCount 151instance MonadState Bitfield P2P where
154getPieceCount = undefined 152
153runConduit :: Socket -> Conduit Message IO Message -> IO ()
154runConduit sock p2p =
155 sourceSocket sock $=
156 conduitGet S.get $=
157 forever p2p $=
158 conduitPut S.put $$
159 sinkSocket sock
160
161withPeer :: SwarmSession -> PeerAddr -> P2P () -> IO ()
162withPeer se addr p2p =
163 withPeerSession se addr $ \(sock, pses) -> do
164 runConduit sock (runReaderT (runP2P p2p) pses)
165
166
167awaitEvent :: P2P Event
168awaitEvent = P2P (ReaderT nextEvent)
155 169
156signalEvent :: Event -> P2P () 170signalEvent :: Event -> P2P ()
157signalEvent = undefined 171signalEvent = undefined