diff options
Diffstat (limited to 'src/Network/BitTorrent/Peer')
-rw-r--r-- | src/Network/BitTorrent/Peer/Addr.hs | 83 | ||||
-rw-r--r-- | src/Network/BitTorrent/Peer/ClientInfo.hs | 289 | ||||
-rw-r--r-- | src/Network/BitTorrent/Peer/ID.hs | 168 | ||||
-rw-r--r-- | src/Network/BitTorrent/Peer/Status.hs | 65 |
4 files changed, 0 insertions, 605 deletions
diff --git a/src/Network/BitTorrent/Peer/Addr.hs b/src/Network/BitTorrent/Peer/Addr.hs deleted file mode 100644 index 5c05180a..00000000 --- a/src/Network/BitTorrent/Peer/Addr.hs +++ /dev/null | |||
@@ -1,83 +0,0 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam T. 2013 | ||
3 | -- License : MIT | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : non-portable | ||
7 | -- | ||
8 | {-# LANGUAGE OverloadedStrings #-} | ||
9 | {-# LANGUAGE RecordWildCards #-} | ||
10 | {-# OPTIONS -fno-warn-orphans #-} | ||
11 | module Network.BitTorrent.Peer.Addr | ||
12 | ( PeerAddr(..) | ||
13 | , peerSockAddr, connectToPeer | ||
14 | , ppPeer | ||
15 | ) where | ||
16 | |||
17 | import Control.Applicative | ||
18 | import Data.BEncode | ||
19 | import Data.Bits | ||
20 | import Data.Word | ||
21 | import Text.PrettyPrint | ||
22 | import Network | ||
23 | import Network.Socket | ||
24 | |||
25 | import Network.BitTorrent.Peer.ID | ||
26 | import Network.BitTorrent.Peer.ClientInfo | ||
27 | |||
28 | |||
29 | data PeerAddr = PeerAddr { | ||
30 | peerID :: Maybe PeerID | ||
31 | , peerIP :: HostAddress | ||
32 | , peerPort :: PortNumber | ||
33 | } deriving (Show, Eq) | ||
34 | |||
35 | instance BEncodable PortNumber where | ||
36 | toBEncode = toBEncode . fromEnum | ||
37 | fromBEncode b = toEnum <$> fromBEncode b | ||
38 | |||
39 | instance BEncodable PeerAddr where | ||
40 | toBEncode (PeerAddr pid pip pport) = fromAssocs | ||
41 | [ "peer id" -->? pid | ||
42 | , "ip" --> pip | ||
43 | , "port" --> pport | ||
44 | ] | ||
45 | |||
46 | fromBEncode (BDict d) = | ||
47 | PeerAddr <$> d >--? "peer id" | ||
48 | <*> d >-- "ip" | ||
49 | <*> d >-- "port" | ||
50 | |||
51 | fromBEncode _ = decodingError "PeerAddr" | ||
52 | |||
53 | |||
54 | -- TODO make platform independent, clarify htonl | ||
55 | -- | Convert peer info from tracker response to socket address. | ||
56 | -- Used for establish connection between peers. | ||
57 | -- | ||
58 | peerSockAddr :: PeerAddr -> SockAddr | ||
59 | peerSockAddr = SockAddrInet <$> (g . peerPort) <*> (htonl . peerIP) | ||
60 | where | ||
61 | htonl :: Word32 -> Word32 | ||
62 | htonl d = | ||
63 | ((d .&. 0xff) `shiftL` 24) .|. | ||
64 | (((d `shiftR` 8 ) .&. 0xff) `shiftL` 16) .|. | ||
65 | (((d `shiftR` 16) .&. 0xff) `shiftL` 8) .|. | ||
66 | ((d `shiftR` 24) .&. 0xff) | ||
67 | |||
68 | g :: PortNumber -> PortNumber | ||
69 | g = id | ||
70 | |||
71 | -- | Tries to connect to peer using reasonable default parameters. | ||
72 | connectToPeer :: PeerAddr -> IO Socket | ||
73 | connectToPeer p = do | ||
74 | sock <- socket AF_INET Stream Network.Socket.defaultProtocol | ||
75 | connect sock (peerSockAddr p) | ||
76 | return sock | ||
77 | |||
78 | ppPeer :: PeerAddr -> Doc | ||
79 | ppPeer p @ PeerAddr {..} = case peerID of | ||
80 | Just pid -> ppClientInfo (clientInfo pid) <+> "at" <+> paddr | ||
81 | Nothing -> paddr | ||
82 | where | ||
83 | paddr = text (show (peerSockAddr p)) | ||
diff --git a/src/Network/BitTorrent/Peer/ClientInfo.hs b/src/Network/BitTorrent/Peer/ClientInfo.hs deleted file mode 100644 index 7200471a..00000000 --- a/src/Network/BitTorrent/Peer/ClientInfo.hs +++ /dev/null | |||
@@ -1,289 +0,0 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam T. 2013 | ||
3 | -- License : MIT | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | -- This module detect client information such as version and | ||
9 | -- implementation that can be later printed in human frienly | ||
10 | -- form. Useful for debugging and logging. | ||
11 | -- | ||
12 | -- See <http://bittorrent.org/beps/bep_0020.html> for more | ||
13 | -- information. | ||
14 | -- | ||
15 | {-# LANGUAGE OverloadedStrings #-} | ||
16 | {-# LANGUAGE RecordWildCards #-} | ||
17 | module Network.BitTorrent.Peer.ClientInfo | ||
18 | ( -- * Info | ||
19 | ClientInfo(..), clientInfo, ppClientInfo, unknownClient | ||
20 | |||
21 | -- * Version | ||
22 | , ClientVersion, ppClientVersion | ||
23 | |||
24 | -- * Implementation | ||
25 | , ClientImpl(..), ppClientImpl | ||
26 | |||
27 | -- , mkEnumTyDef, mkPars, nameMap | ||
28 | ) where | ||
29 | |||
30 | import Control.Applicative | ||
31 | --import Data.List | ||
32 | import Data.ByteString (ByteString) | ||
33 | import qualified Data.ByteString.Char8 as BC | ||
34 | import Data.Serialize.Get | ||
35 | import Text.PrettyPrint | ||
36 | |||
37 | import Network.BitTorrent.Peer.ID | ||
38 | |||
39 | |||
40 | -- | All known client versions. | ||
41 | data ClientImpl = | ||
42 | IUnknown | ||
43 | | IAres | ||
44 | | IArctic | ||
45 | | IAvicora | ||
46 | | IBitPump | ||
47 | | IAzureus | ||
48 | | IBitBuddy | ||
49 | | IBitComet | ||
50 | | IBitflu | ||
51 | | IBTG | ||
52 | | IBitRocket | ||
53 | | IBTSlave | ||
54 | | IBittorrentX | ||
55 | | IEnhancedCTorrent | ||
56 | | ICTorrent | ||
57 | | IDelugeTorrent | ||
58 | | IPropagateDataClient | ||
59 | | IEBit | ||
60 | | IElectricSheep | ||
61 | | IFoxTorrent | ||
62 | | IGSTorrent | ||
63 | | IHalite | ||
64 | | IlibHSbittorrent | ||
65 | | IHydranode | ||
66 | | IKGet | ||
67 | | IKTorrent | ||
68 | | ILH_ABC | ||
69 | | ILphant | ||
70 | | ILibtorrent | ||
71 | | ILibTorrent | ||
72 | | ILimeWire | ||
73 | | IMonoTorrent | ||
74 | | IMooPolice | ||
75 | | IMiro | ||
76 | | IMoonlightTorrent | ||
77 | | INetTransport | ||
78 | | IPando | ||
79 | | IqBittorrent | ||
80 | | IQQDownload | ||
81 | | IQt4TorrentExample | ||
82 | | IRetriever | ||
83 | | IShareaza | ||
84 | | ISwiftbit | ||
85 | | ISwarmScope | ||
86 | | ISymTorrent | ||
87 | | Isharktorrent | ||
88 | | ITorrentDotNET | ||
89 | | ITransmission | ||
90 | | ITorrentstorm | ||
91 | | ITuoTu | ||
92 | | IuLeecher | ||
93 | | IuTorrent | ||
94 | | IVagaa | ||
95 | | IBitLet | ||
96 | | IFireTorrent | ||
97 | | IXunlei | ||
98 | | IXanTorrent | ||
99 | | IXtorrent | ||
100 | | IZipTorrent | ||
101 | deriving (Show, Eq, Ord) | ||
102 | |||
103 | parseImpl :: ByteString -> ClientImpl | ||
104 | parseImpl = f . BC.unpack | ||
105 | where | ||
106 | f "AG" = IAres | ||
107 | f "A~" = IAres | ||
108 | f "AR" = IArctic | ||
109 | f "AV" = IAvicora | ||
110 | f "AX" = IBitPump | ||
111 | f "AZ" = IAzureus | ||
112 | f "BB" = IBitBuddy | ||
113 | f "BC" = IBitComet | ||
114 | f "BF" = IBitflu | ||
115 | f "BG" = IBTG | ||
116 | f "BR" = IBitRocket | ||
117 | f "BS" = IBTSlave | ||
118 | f "BX" = IBittorrentX | ||
119 | f "CD" = IEnhancedCTorrent | ||
120 | f "CT" = ICTorrent | ||
121 | f "DE" = IDelugeTorrent | ||
122 | f "DP" = IPropagateDataClient | ||
123 | f "EB" = IEBit | ||
124 | f "ES" = IElectricSheep | ||
125 | f "FT" = IFoxTorrent | ||
126 | f "GS" = IGSTorrent | ||
127 | f "HL" = IHalite | ||
128 | f "HS" = IlibHSbittorrent | ||
129 | f "HN" = IHydranode | ||
130 | f "KG" = IKGet | ||
131 | f "KT" = IKTorrent | ||
132 | f "LH" = ILH_ABC | ||
133 | f "LP" = ILphant | ||
134 | f "LT" = ILibtorrent | ||
135 | f "lt" = ILibTorrent | ||
136 | f "LW" = ILimeWire | ||
137 | f "MO" = IMonoTorrent | ||
138 | f "MP" = IMooPolice | ||
139 | f "MR" = IMiro | ||
140 | f "MT" = IMoonlightTorrent | ||
141 | f "NX" = INetTransport | ||
142 | f "PD" = IPando | ||
143 | f "qB" = IqBittorrent | ||
144 | f "QD" = IQQDownload | ||
145 | f "QT" = IQt4TorrentExample | ||
146 | f "RT" = IRetriever | ||
147 | f "S~" = IShareaza | ||
148 | f "SB" = ISwiftbit | ||
149 | f "SS" = ISwarmScope | ||
150 | f "ST" = ISymTorrent | ||
151 | f "st" = Isharktorrent | ||
152 | f "SZ" = IShareaza | ||
153 | f "TN" = ITorrentDotNET | ||
154 | f "TR" = ITransmission | ||
155 | f "TS" = ITorrentstorm | ||
156 | f "TT" = ITuoTu | ||
157 | f "UL" = IuLeecher | ||
158 | f "UT" = IuTorrent | ||
159 | f "VG" = IVagaa | ||
160 | f "WT" = IBitLet | ||
161 | f "WY" = IFireTorrent | ||
162 | f "XL" = IXunlei | ||
163 | f "XT" = IXanTorrent | ||
164 | f "XX" = IXtorrent | ||
165 | f "ZT" = IZipTorrent | ||
166 | f _ = IUnknown | ||
167 | |||
168 | -- | Format client implementation info in human readable form. | ||
169 | ppClientImpl :: ClientImpl -> Doc | ||
170 | ppClientImpl = text . tail . show | ||
171 | |||
172 | unknownImpl :: ClientImpl | ||
173 | unknownImpl = IUnknown | ||
174 | |||
175 | |||
176 | |||
177 | type ClientVersion = ByteString | ||
178 | |||
179 | -- | Format client implementation version in human readable form. | ||
180 | ppClientVersion :: ClientVersion -> Doc | ||
181 | ppClientVersion = text . BC.unpack | ||
182 | |||
183 | unknownVersion :: ClientVersion | ||
184 | unknownVersion = "0000" | ||
185 | |||
186 | |||
187 | -- | All useful infomation that can be obtained from a peer | ||
188 | -- identifier. | ||
189 | data ClientInfo = ClientInfo { | ||
190 | ciImpl :: ClientImpl | ||
191 | , ciVersion :: ClientVersion | ||
192 | } deriving (Show, Eq, Ord) | ||
193 | |||
194 | -- | Format client implementation in human readable form. | ||
195 | ppClientInfo :: ClientInfo -> Doc | ||
196 | ppClientInfo ClientInfo {..} = | ||
197 | ppClientImpl ciImpl <+> "version" <+> ppClientVersion ciVersion | ||
198 | |||
199 | |||
200 | -- | Unrecognized client implementation. | ||
201 | unknownClient :: ClientInfo | ||
202 | unknownClient = ClientInfo unknownImpl unknownVersion | ||
203 | |||
204 | -- | Tries to extract meaningful information from peer ID bytes. If | ||
205 | -- peer id uses unknown coding style then client info returned is | ||
206 | -- 'unknownClient'. | ||
207 | -- | ||
208 | clientInfo :: PeerID -> ClientInfo | ||
209 | clientInfo pid = either (const unknownClient) id $ runGet getCI (getPeerID pid) | ||
210 | where -- TODO other styles | ||
211 | getCI = do | ||
212 | _ <- getWord8 | ||
213 | ClientInfo <$> (parseImpl <$> getByteString 2) <*> getByteString 4 | ||
214 | |||
215 | |||
216 | {- | ||
217 | -- code used for generation; remove it later on | ||
218 | |||
219 | mkEnumTyDef :: NM -> String | ||
220 | mkEnumTyDef = unlines . map (" | I" ++) . nub . map snd | ||
221 | |||
222 | mkPars :: NM -> String | ||
223 | mkPars = unlines . map (\(code, impl) -> " f \"" ++ code ++ "\" = " ++ "I" ++ impl) | ||
224 | |||
225 | type NM = [(String, String)] | ||
226 | nameMap :: NM | ||
227 | nameMap = | ||
228 | [ ("AG", "Ares") | ||
229 | , ("A~", "Ares") | ||
230 | , ("AR", "Arctic") | ||
231 | , ("AV", "Avicora") | ||
232 | , ("AX", "BitPump") | ||
233 | , ("AZ", "Azureus") | ||
234 | , ("BB", "BitBuddy") | ||
235 | , ("BC", "BitComet") | ||
236 | , ("BF", "Bitflu") | ||
237 | , ("BG", "BTG") | ||
238 | , ("BR", "BitRocket") | ||
239 | , ("BS", "BTSlave") | ||
240 | , ("BX", "BittorrentX") | ||
241 | , ("CD", "EnhancedCTorrent") | ||
242 | , ("CT", "CTorrent") | ||
243 | , ("DE", "DelugeTorrent") | ||
244 | , ("DP", "PropagateDataClient") | ||
245 | , ("EB", "EBit") | ||
246 | , ("ES", "ElectricSheep") | ||
247 | , ("FT", "FoxTorrent") | ||
248 | , ("GS", "GSTorrent") | ||
249 | , ("HL", "Halite") | ||
250 | , ("HS", "libHSnetwork_bittorrent") | ||
251 | , ("HN", "Hydranode") | ||
252 | , ("KG", "KGet") | ||
253 | , ("KT", "KTorrent") | ||
254 | , ("LH", "LH_ABC") | ||
255 | , ("LP", "Lphant") | ||
256 | , ("LT", "Libtorrent") | ||
257 | , ("lt", "LibTorrent") | ||
258 | , ("LW", "LimeWire") | ||
259 | , ("MO", "MonoTorrent") | ||
260 | , ("MP", "MooPolice") | ||
261 | , ("MR", "Miro") | ||
262 | , ("MT", "MoonlightTorrent") | ||
263 | , ("NX", "NetTransport") | ||
264 | , ("PD", "Pando") | ||
265 | , ("qB", "qBittorrent") | ||
266 | , ("QD", "QQDownload") | ||
267 | , ("QT", "Qt4TorrentExample") | ||
268 | , ("RT", "Retriever") | ||
269 | , ("S~", "Shareaza") | ||
270 | , ("SB", "Swiftbit") | ||
271 | , ("SS", "SwarmScope") | ||
272 | , ("ST", "SymTorrent") | ||
273 | , ("st", "sharktorrent") | ||
274 | , ("SZ", "Shareaza") | ||
275 | , ("TN", "TorrentDotNET") | ||
276 | , ("TR", "Transmission") | ||
277 | , ("TS", "Torrentstorm") | ||
278 | , ("TT", "TuoTu") | ||
279 | , ("UL", "uLeecher") | ||
280 | , ("UT", "uTorrent") | ||
281 | , ("VG", "Vagaa") | ||
282 | , ("WT", "BitLet") | ||
283 | , ("WY", "FireTorrent") | ||
284 | , ("XL", "Xunlei") | ||
285 | , ("XT", "XanTorrent") | ||
286 | , ("XX", "Xtorrent") | ||
287 | , ("ZT", "ZipTorrent") | ||
288 | ] | ||
289 | -} \ No newline at end of file | ||
diff --git a/src/Network/BitTorrent/Peer/ID.hs b/src/Network/BitTorrent/Peer/ID.hs deleted file mode 100644 index 9bf0ae31..00000000 --- a/src/Network/BitTorrent/Peer/ID.hs +++ /dev/null | |||
@@ -1,168 +0,0 @@ | |||
1 | -- TODO: tests | ||
2 | -- | | ||
3 | -- Copyright : (c) Sam T. 2013 | ||
4 | -- License : MIT | ||
5 | -- Maintainer : pxqr.sta@gmail.com | ||
6 | -- Stability : experimental | ||
7 | -- Portability : non-portable | ||
8 | -- | ||
9 | -- This module provides 'Peer' and 'PeerID' datatypes and all related | ||
10 | -- operations. | ||
11 | -- | ||
12 | -- Recommended method for generation of the peer ID's is 'newPeerID', | ||
13 | -- though this module exports some other goodies for custom generation. | ||
14 | -- | ||
15 | {-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-} | ||
16 | module Network.BitTorrent.Peer.ID | ||
17 | ( -- * Peer identification | ||
18 | PeerID (getPeerID), ppPeerID | ||
19 | |||
20 | -- ** Encoding styles | ||
21 | , azureusStyle, shadowStyle | ||
22 | |||
23 | -- ** Defaults | ||
24 | , defaultClientID, defaultVersionNumber | ||
25 | |||
26 | -- ** Generation | ||
27 | , newPeerID, timestampByteString | ||
28 | -- ** Extra | ||
29 | |||
30 | , byteStringPadded | ||
31 | ) where | ||
32 | |||
33 | import Control.Applicative | ||
34 | import Data.BEncode | ||
35 | import Data.ByteString (ByteString) | ||
36 | import qualified Data.ByteString as B | ||
37 | import qualified Data.ByteString.Char8 as BC | ||
38 | import qualified Data.ByteString.Lazy as BL | ||
39 | import qualified Data.ByteString.Builder as B | ||
40 | import Data.Foldable (foldMap) | ||
41 | import Data.Monoid ((<>)) | ||
42 | import Data.Serialize | ||
43 | import Data.URLEncoded | ||
44 | import Data.Version (Version(Version), versionBranch) | ||
45 | import Data.Time.Clock (getCurrentTime) | ||
46 | import Data.Time.Format (formatTime) | ||
47 | import Text.PrettyPrint (text, Doc) | ||
48 | import System.Locale (defaultTimeLocale) | ||
49 | |||
50 | |||
51 | -- TODO we have linker error here, so manual hardcoded version for a while. | ||
52 | -- import Paths_network_bittorrent (version) | ||
53 | version :: Version | ||
54 | version = Version [0, 10, 0, 0] [] | ||
55 | |||
56 | |||
57 | -- | Peer identifier is exactly 20 bytes long bytestring. | ||
58 | newtype PeerID = PeerID { getPeerID :: ByteString } | ||
59 | deriving (Show, Eq, Ord, BEncodable) | ||
60 | |||
61 | instance Serialize PeerID where | ||
62 | put = putByteString . getPeerID | ||
63 | get = PeerID <$> getBytes 20 | ||
64 | |||
65 | instance URLShow PeerID where | ||
66 | urlShow = BC.unpack . getPeerID | ||
67 | |||
68 | ppPeerID :: PeerID -> Doc | ||
69 | ppPeerID = text . BC.unpack . getPeerID | ||
70 | |||
71 | |||
72 | -- | Azureus-style encoding have the following layout: | ||
73 | -- | ||
74 | -- * 1 byte : '-' | ||
75 | -- | ||
76 | -- * 2 bytes: client id | ||
77 | -- | ||
78 | -- * 4 bytes: version number | ||
79 | -- | ||
80 | -- * 1 byte : '-' | ||
81 | -- | ||
82 | -- * 12 bytes: random number | ||
83 | -- | ||
84 | azureusStyle :: ByteString -- ^ 2 character client ID, padded with 'H'. | ||
85 | -> ByteString -- ^ Version number, padded with 'X'. | ||
86 | -> ByteString -- ^ Random number, padded with '0'. | ||
87 | -> PeerID -- ^ Azureus-style encoded peer ID. | ||
88 | azureusStyle cid ver rnd = PeerID $ BL.toStrict $ B.toLazyByteString $ | ||
89 | B.char8 '-' <> | ||
90 | byteStringPadded cid 2 'H' <> | ||
91 | byteStringPadded ver 4 'X' <> | ||
92 | B.char8 '-' <> | ||
93 | byteStringPadded rnd 12 '0' | ||
94 | |||
95 | -- | Shadow-style encoding have the following layout: | ||
96 | -- | ||
97 | -- * 1 byte : client id. | ||
98 | -- | ||
99 | -- * 0-4 bytes: version number. If less than 4 then padded with '-' char. | ||
100 | -- | ||
101 | -- * 15 bytes : random number. If length is less than 15 then padded with '0' char. | ||
102 | -- | ||
103 | shadowStyle :: Char -- ^ Client ID. | ||
104 | -> ByteString -- ^ Version number. | ||
105 | -> ByteString -- ^ Random number. | ||
106 | -> PeerID -- ^ Shadow style encoded peer ID. | ||
107 | shadowStyle cid ver rnd = PeerID $ BL.toStrict $ B.toLazyByteString $ | ||
108 | B.char8 cid <> | ||
109 | byteStringPadded ver 4 '-' <> | ||
110 | byteStringPadded rnd 15 '0' | ||
111 | |||
112 | |||
113 | -- | "HS" - 2 bytes long client identifier. | ||
114 | defaultClientID :: ByteString | ||
115 | defaultClientID = "HS" | ||
116 | |||
117 | -- | Gives exactly 4 bytes long version number for any version of the package. | ||
118 | -- Version is taken from .cabal. | ||
119 | defaultVersionNumber :: ByteString | ||
120 | defaultVersionNumber = B.take 4 (BC.pack (foldMap show (versionBranch version))) | ||
121 | |||
122 | -- | Gives 15 characters long decimal timestamp such that: | ||
123 | -- | ||
124 | -- * 6 bytes : first 6 characters from picoseconds obtained with %q. | ||
125 | -- | ||
126 | -- * 1 bytes : character '.' for readability. | ||
127 | -- | ||
128 | -- * 9..* bytes: number of whole seconds since the Unix epoch (!)REVERSED. | ||
129 | -- | ||
130 | -- Can be used both with shadow and azureus style encoding. This format is | ||
131 | -- used to make the ID's readable(for debugging) and more or less random. | ||
132 | -- | ||
133 | timestampByteString :: IO ByteString | ||
134 | timestampByteString = (BC.pack . format) <$> getCurrentTime | ||
135 | where | ||
136 | format t = take 6 (formatTime defaultTimeLocale "%q" t) ++ "." ++ | ||
137 | take 9 (reverse (formatTime defaultTimeLocale "%s" t)) | ||
138 | |||
139 | -- | Here we use Azureus-style encoding with the following args: | ||
140 | -- | ||
141 | -- * 'HS' for the client id. | ||
142 | -- | ||
143 | -- * Version of the package for the version number | ||
144 | -- | ||
145 | -- * UTC time day ++ day time for the random number. | ||
146 | -- | ||
147 | newPeerID :: IO PeerID | ||
148 | newPeerID = azureusStyle defaultClientID defaultVersionNumber | ||
149 | <$> timestampByteString | ||
150 | |||
151 | -- | Pad bytestring so it's becomes exactly request length. Conversion is done | ||
152 | -- like so: | ||
153 | -- | ||
154 | -- * length < size: Complete bytestring by given charaters. | ||
155 | -- | ||
156 | -- * length = size: Output bytestring as is. | ||
157 | -- | ||
158 | -- * length > size: Drop last (length - size) charaters from a given bytestring. | ||
159 | -- | ||
160 | byteStringPadded :: ByteString -- ^ bytestring to be padded. | ||
161 | -> Int -- ^ size of result builder. | ||
162 | -> Char -- ^ character used for padding. | ||
163 | -> B.Builder | ||
164 | byteStringPadded bs s c = | ||
165 | B.byteString (B.take s bs) <> | ||
166 | B.byteString (BC.replicate padLen c) | ||
167 | where | ||
168 | padLen = s - min (B.length bs) s \ No newline at end of file | ||
diff --git a/src/Network/BitTorrent/Peer/Status.hs b/src/Network/BitTorrent/Peer/Status.hs deleted file mode 100644 index 806ba77d..00000000 --- a/src/Network/BitTorrent/Peer/Status.hs +++ /dev/null | |||
@@ -1,65 +0,0 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam T. 2013 | ||
3 | -- License : MIT | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | module Network.BitTorrent.Peer.Status | ||
9 | ( PeerStatus(..) | ||
10 | , setChoking, setInterested | ||
11 | , initPeerStatus | ||
12 | |||
13 | , SessionStatus(..) | ||
14 | , initSessionStatus | ||
15 | , setClientStatus, setPeerStatus | ||
16 | , canUpload, canDownload | ||
17 | |||
18 | -- * Defaults | ||
19 | , defaultUnchokeSlots | ||
20 | ) where | ||
21 | |||
22 | data PeerStatus = PeerStatus { | ||
23 | psChoking :: Bool | ||
24 | , psInterested :: Bool | ||
25 | } | ||
26 | |||
27 | -- | Any session between peers starts as choking and not interested. | ||
28 | initPeerStatus :: PeerStatus | ||
29 | initPeerStatus = PeerStatus True False | ||
30 | |||
31 | setChoking :: Bool -> PeerStatus -> PeerStatus | ||
32 | setChoking b ps = ps { psChoking = b } | ||
33 | |||
34 | setInterested :: Bool -> PeerStatus -> PeerStatus | ||
35 | setInterested b ps = ps { psInterested = b } | ||
36 | |||
37 | |||
38 | |||
39 | data SessionStatus = SessionStatus { | ||
40 | seClientStatus :: PeerStatus | ||
41 | , sePeerStatus :: PeerStatus | ||
42 | } | ||
43 | |||
44 | initSessionStatus :: SessionStatus | ||
45 | initSessionStatus = SessionStatus initPeerStatus initPeerStatus | ||
46 | |||
47 | setClientStatus :: (PeerStatus -> PeerStatus) -> SessionStatus -> SessionStatus | ||
48 | setClientStatus f ss = ss { seClientStatus = f (seClientStatus ss) } | ||
49 | |||
50 | setPeerStatus :: (PeerStatus -> PeerStatus) -> SessionStatus -> SessionStatus | ||
51 | setPeerStatus f ss = ss { sePeerStatus = f (sePeerStatus ss) } | ||
52 | |||
53 | -- | Can the /client/ to upload to the /peer/? | ||
54 | canUpload :: SessionStatus -> Bool | ||
55 | canUpload SessionStatus { seClientStatus = client, sePeerStatus = peer} = | ||
56 | psInterested peer && not (psChoking client) | ||
57 | |||
58 | -- | Can the /client/ download from the /peer/? | ||
59 | canDownload :: SessionStatus -> Bool | ||
60 | canDownload SessionStatus { seClientStatus = client, sePeerStatus = peer } = | ||
61 | psInterested client && not (psChoking peer) | ||
62 | |||
63 | -- | Indicates have many peers are allowed to download from the client. | ||
64 | defaultUnchokeSlots :: Int | ||
65 | defaultUnchokeSlots = 4 \ No newline at end of file | ||