summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/BitTorrent/Core/Node.hs108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/Network/BitTorrent/Core/Node.hs b/src/Network/BitTorrent/Core/Node.hs
new file mode 100644
index 00000000..e93c3586
--- /dev/null
+++ b/src/Network/BitTorrent/Core/Node.hs
@@ -0,0 +1,108 @@
1{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE TemplateHaskell #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4module Network.BitTorrent.Core.Node
5 ( -- * Node ID
6 NodeId
7 , genNodeId
8
9 -- * Node address
10 , NodeAddr (..)
11
12 -- * Node info
13 , NodeInfo (..)
14 ) where
15
16import Control.Applicative
17import Data.Aeson (ToJSON, FromJSON)
18import Data.Aeson.TH
19import Data.ByteString as BS
20import Data.BEncode as BE
21import Data.Serialize as S
22import Network
23import System.Entropy
24
25import Data.Torrent.JSON
26import Network.BitTorrent.Core.PeerAddr ()
27
28{-----------------------------------------------------------------------
29-- Node id
30-----------------------------------------------------------------------}
31
32-- | Normally, /this/ node id should we saved between invocations of
33-- the client software.
34newtype NodeId = NodeId ByteString
35 deriving (Show, Eq, FromJSON, ToJSON)
36
37nodeIdSize :: Int
38nodeIdSize = 20
39
40instance Serialize NodeId where
41 get = NodeId <$> getByteString nodeIdSize
42 {-# INLINE get #-}
43 put (NodeId bs) = putByteString bs
44 {-# INLINE put #-}
45
46-- TODO WARN is the 'system' random suitable for this?
47-- | Generate random NodeID used for the entire session.
48-- Distribution of ID's should be as uniform as possible.
49--
50genNodeId :: IO NodeId
51genNodeId = NodeId <$> getEntropy nodeIdSize
52
53type Distance = NodeId
54
55{-----------------------------------------------------------------------
56-- Node address
57-----------------------------------------------------------------------}
58
59data NodeAddr a = NodeAddr
60 { nodeHost :: !a
61 , nodePort :: {-# UNPACK #-} !PortNumber
62 } deriving (Show, Eq)
63
64$(deriveJSON omitRecordPrefix ''NodeAddr)
65
66-- | KRPC compatible encoding.
67instance Serialize a => Serialize (NodeAddr a) where
68 get = NodeAddr <$> get <*> get
69 put NodeAddr {..} = put nodeHost >> put nodePort
70
71-- | Torrent file compatible encoding.
72instance BEncode a => BEncode (NodeAddr a) where
73 toBEncode NodeAddr {..} = toBEncode (nodeHost, nodePort)
74 {-# INLINE toBEncode #-}
75 fromBEncode b = uncurry NodeAddr <$> fromBEncode b
76 {-# INLINE fromBEncode #-}
77
78{-----------------------------------------------------------------------
79-- Node info
80-----------------------------------------------------------------------}
81
82data NodeInfo a = NodeInfo
83 { nodeId :: !NodeId
84 , nodeAddr :: !(NodeAddr a)
85 } deriving (Show, Eq)
86
87$(deriveJSON omitRecordPrefix ''NodeInfo)
88
89-- | KRPC 'compact list' compatible encoding.
90instance Serialize a => Serialize (NodeInfo a) where
91 get = NodeInfo <$> get <*> get
92 put NodeInfo {..} = put nodeId >> put nodeAddr
93
94type CompactInfo = ByteString
95
96data NodeList a = CompactNodeList [NodeInfo a]
97
98decodeCompact :: Serialize a => CompactInfo -> [NodeInfo a]
99decodeCompact = either (const []) id . S.runGet (many get)
100
101encodeCompact :: [NodeId] -> CompactInfo
102encodeCompact = S.runPut . mapM_ put
103
104--decodePeerList :: [BEncode] -> [PeerAddr]
105--decodePeerList = undefined
106
107--encodePeerList :: [PeerAddr] -> [BEncode]
108--encodePeerList = undefined