diff options
author | joe <joe@jerkface.net> | 2017-07-16 18:14:38 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-07-16 18:14:38 -0400 |
commit | 22b6b27c52b5848ed79789b5d5a948b841daaa83 (patch) | |
tree | d252f6d2d58a5130ca6be6070314381c88446ad4 | |
parent | b4349ffe0a8ceed841cfc3941b024afe7183c10d (diff) |
Progress on polymorphic kademlia implementation.
-rw-r--r-- | Kademlia.hs | 91 |
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 | ||
104 | quietInsertions = InsertionReporter | ||
105 | { reportArrival = \_ _ _ -> return () | ||
106 | , reportPingResult = \_ _ _ -> return () | ||
107 | } | ||
108 | |||
104 | contramapIR f ir = InsertionReporter | 109 | contramapIR 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 | ||
114 | contramapKS f ks = KademliaSpace | 119 | contramapKS 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. |
119 | insertNode :: | 124 | data 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 | 148 | data Kademlia nid ni = Kademlia (InsertionReporter ni) |
136 | -> (ni -> IO Bool) | 149 | (KademliaSpace nid ni) |
150 | (TableStateIO nid ni) | ||
137 | 151 | ||
138 | -- info | 152 | insertNode :: |
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 | 157 | insertNode (Kademlia reporter space io) node = do | |
147 | insertNode | ||
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 () |