summaryrefslogtreecommitdiff
path: root/Kademlia.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Kademlia.hs')
-rw-r--r--Kademlia.hs91
1 files changed, 47 insertions, 44 deletions
diff --git a/Kademlia.hs b/Kademlia.hs
index d29a3240..40874078 100644
--- a/Kademlia.hs
+++ b/Kademlia.hs
@@ -101,6 +101,11 @@ data InsertionReporter ni = InsertionReporter
101 -> IO () 101 -> IO ()
102 } 102 }
103 103
104quietInsertions = InsertionReporter
105 { reportArrival = \_ _ _ -> return ()
106 , reportPingResult = \_ _ _ -> return ()
107 }
108
104contramapIR f ir = InsertionReporter 109contramapIR f ir = InsertionReporter
105 { reportArrival = \tm ni nis -> reportArrival ir tm (f ni) (map f nis) 110 { reportArrival = \tm ni nis -> reportArrival ir tm (f ni) (map f nis)
106 , reportPingResult = \tm ni b -> reportPingResult ir tm (f ni) b 111 , reportPingResult = \tm ni b -> reportPingResult ir tm (f ni) b
@@ -111,72 +116,70 @@ data KademliaSpace nid ni = KademliaSpace
111 , kademliaTestBit :: nid -> Word -> Bool 116 , kademliaTestBit :: nid -> Word -> Bool
112 } 117 }
113 118
114contramapKS f ks = KademliaSpace 119contramapKS f ks = ks
115 { kademliaLocation = kademliaLocation ks . f 120 { kademliaLocation = kademliaLocation ks . f
116 } 121 }
117 122
118-- insertNode param@TableParameters{..} state info witnessed_ip0 = do 123-- | All the IO operations neccessary to maintain a Kademlia routing table.
119insertNode :: 124data TableStateIO nid ni = TableStateIO
120 forall ni nid. 125 { -- | Write the routing table. Typically 'writeTVar'.
121 (Ord ni) => 126 tblWrite :: R.Table ni nid -> STM ()
122 127
123 -- reporter 128 -- | Read the routing table. Typically 'readTVar'.
124 InsertionReporter ni 129 , tblRead :: STM (R.Table ni nid)
125 130
126 -- nil 131 -- | Issue a ping to a remote node and report 'True' if the node
127 -> R.Info ni nid 132 -- responded within an acceptable time and 'False' otherwise.
128 133 , tblPing :: ni -> IO Bool
129 -- k 134
130 -> KademliaSpace nid ni 135 -- | Convenience method provided to assist in maintaining state
131 136 -- consistent with the routing table. It will be invoked in the same
132 -- changed 137 -- transaction that 'tblRead'\/'tblWrite' occured but only when there was
133 -> (RoutingTableChanged ni -> STM (IO ())) 138 -- an interesting change. The returned IO action will be triggered soon
139 -- afterward.
140 --
141 -- It is not necessary to do anything interesting here. The following
142 -- trivial implementation is fine:
143 --
144 -- > tblChanged = const $ return $ return ()
145 , tblChanged :: RoutingTableChanged ni -> STM (IO ())
146 }
134 147
135 -- pingProbe 148data Kademlia nid ni = Kademlia (InsertionReporter ni)
136 -> (ni -> IO Bool) 149 (KademliaSpace nid ni)
150 (TableStateIO nid ni)
137 151
138 -- info 152insertNode ::
153 forall ni nid. Ord ni =>
154 Kademlia nid ni
139 -> ni 155 -> ni
140
141 -- var
142 -> TVar (Maybe (R.Info ni nid))
143
144
145 -> IO () 156 -> IO ()
146 157insertNode (Kademlia reporter space io) node = do
147insertNode
148 reporter
149 nil
150 k
151 changed
152 pingProbe
153 info
154 var = do
155 158
156 tm <- utcTimeToPOSIXSeconds <$> getCurrentTime 159 tm <- utcTimeToPOSIXSeconds <$> getCurrentTime
157 160
158 (ps,reaction) <- atomically $ do 161 (ps,reaction) <- atomically $ do
159 tbl <- fromMaybe nil <$> readTVar var 162 tbl <- tblRead io
160 let (inserted, ps,t') = R.updateForInbound (kademliaTestBit k) (kademliaLocation k) tm info $ myBuckets tbl 163 let (inserted, ps,t') = R.updateForInbound (kademliaTestBit space) (kademliaLocation space) tm node tbl
164 tblWrite io t'
161 reaction <- if inserted 165 reaction <- if inserted
162 then changed $ RoutingTableChanged Nothing info tm 166 then tblChanged io $ RoutingTableChanged Nothing node tm
163 else return $ return () 167 else return $ return ()
164 writeTVar var (Just $ tbl { myBuckets = t' })
165 return (ps, reaction) 168 return (ps, reaction)
166 169
167 reportArrival reporter tm info ps 170 reportArrival reporter tm node ps
168 reaction 171 reaction
169 172
170 _ <- fork $ do 173 _ <- fork $ do
171 myThreadId >>= flip labelThread "pingResults" 174 myThreadId >>= flip labelThread "pingResults"
172 forM_ ps $ \n -> do 175 forM_ ps $ \n -> do
173 b <- pingProbe n 176 b <- tblPing io n
174 reportPingResult reporter tm n b 177 reportPingResult reporter tm n b
175 join $ atomically $ do 178 join $ atomically $ do
176 tbl <- fromMaybe nil <$> readTVar var 179 tbl <- tblRead io
177 let (replacements, t') = R.updateForPingResult (kademliaTestBit k) (kademliaLocation k) n b $ myBuckets tbl 180 let (replacements, t') = R.updateForPingResult (kademliaTestBit space) (kademliaLocation space) n b tbl
178 writeTVar var (Just $ tbl { myBuckets = t' }) 181 tblWrite io t'
179 sequence <$> mapM (\(x,(t,y)) -> changed $ RoutingTableChanged (Just x) y t) 182 sequence <$> mapM (\(x,(t,y)) -> tblChanged io $ RoutingTableChanged (Just x) y t)
180 replacements 183 replacements
181 184
182 return () 185 return ()