diff options
Diffstat (limited to 'src/Network/BitTorrent/Exchange.hs')
-rw-r--r-- | src/Network/BitTorrent/Exchange.hs | 182 |
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 #-} |
12 | module Network.BitTorrent.Exchange | 12 | module Network.BitTorrent.Exchange |
13 | ( P2P, withPeer | 13 | ( P2P, withPeer |
14 | , awaitEvent, signalEvent | ||
14 | ) where | 15 | ) where |
15 | 16 | ||
16 | import Control.Applicative | 17 | import Control.Applicative |
@@ -41,117 +42,130 @@ import Network.BitTorrent.Peer | |||
41 | import Data.Bitfield as BF | 42 | import Data.Bitfield as BF |
42 | import Data.Torrent | 43 | import Data.Torrent |
43 | 44 | ||
44 | {----------------------------------------------------------------------- | ||
45 | P2P monad | ||
46 | -----------------------------------------------------------------------} | ||
47 | |||
48 | type PeerWire = ConduitM Message Message IO | ||
49 | |||
50 | waitMessage :: PeerWire Message | ||
51 | waitMessage = await >>= maybe waitMessage return | ||
52 | |||
53 | signalMessage :: Message -> PeerWire () | ||
54 | signalMessage = C.yield | ||
55 | |||
56 | newtype P2P a = P2P { | ||
57 | runP2P :: ReaderT PeerSession PeerWire a | ||
58 | } deriving (Monad, MonadReader PeerSession, MonadIO) | ||
59 | |||
60 | instance MonadState Bitfield P2P where | ||
61 | |||
62 | runConduit :: Socket -> Conduit Message IO Message -> IO () | ||
63 | runConduit sock p2p = | ||
64 | sourceSocket sock $= | ||
65 | conduitGet S.get $= | ||
66 | forever p2p $= | ||
67 | conduitPut S.put $$ | ||
68 | sinkSocket sock | ||
69 | |||
70 | withPeer :: SwarmSession -> PeerAddr -> P2P () -> IO () | ||
71 | withPeer se addr p2p = | ||
72 | withPeerSession se addr $ \(sock, pses) -> do | ||
73 | runConduit sock (runReaderT (runP2P p2p) pses) | ||
74 | 45 | ||
75 | data Event = Available Bitfield | 46 | data Event = Available Bitfield |
76 | | Want | 47 | | Want |
77 | | Block | 48 | | Block |
78 | 49 | ||
50 | {----------------------------------------------------------------------- | ||
51 | Peer wire | ||
52 | -----------------------------------------------------------------------} | ||
79 | 53 | ||
54 | type PeerWire = ConduitM Message Message IO | ||
80 | 55 | ||
81 | waitForEvent :: P2P Event | 56 | waitMessage :: PeerSession -> PeerWire Message |
82 | waitForEvent = P2P (ReaderT nextEvent) | 57 | waitMessage 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 | 65 | signalMessage :: Message -> PeerSession -> PeerWire () |
92 | SessionStatus {..} <- liftIO $ readIORef peerSessionStatus | 66 | signalMessage 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 | 71 | getPieceCount :: PeerSession -> IO PieceCount |
100 | handleMessage NotInterested = return undefined | 72 | getPieceCount = undefined |
101 | 73 | ||
102 | handleMessage (Have ix) = do | 74 | nextEvent :: PeerSession -> PeerWire Event |
75 | nextEvent 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 | ||
147 | newtype P2P a = P2P { | ||
148 | runP2P :: ReaderT PeerSession PeerWire a | ||
149 | } deriving (Monad, MonadReader PeerSession, MonadIO) | ||
152 | 150 | ||
153 | getPieceCount :: PeerSession -> IO PieceCount | 151 | instance MonadState Bitfield P2P where |
154 | getPieceCount = undefined | 152 | |
153 | runConduit :: Socket -> Conduit Message IO Message -> IO () | ||
154 | runConduit sock p2p = | ||
155 | sourceSocket sock $= | ||
156 | conduitGet S.get $= | ||
157 | forever p2p $= | ||
158 | conduitPut S.put $$ | ||
159 | sinkSocket sock | ||
160 | |||
161 | withPeer :: SwarmSession -> PeerAddr -> P2P () -> IO () | ||
162 | withPeer se addr p2p = | ||
163 | withPeerSession se addr $ \(sock, pses) -> do | ||
164 | runConduit sock (runReaderT (runP2P p2p) pses) | ||
165 | |||
166 | |||
167 | awaitEvent :: P2P Event | ||
168 | awaitEvent = P2P (ReaderT nextEvent) | ||
155 | 169 | ||
156 | signalEvent :: Event -> P2P () | 170 | signalEvent :: Event -> P2P () |
157 | signalEvent = undefined | 171 | signalEvent = undefined |