diff options
author | joe <joe@jerkface.net> | 2017-11-18 22:42:24 -0500 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-11-18 22:42:24 -0500 |
commit | bacefe39096c2c39afb6af7f01e729233a47522d (patch) | |
tree | 23ea204fde593d3d7062fd9fb6bb9327297f95ae | |
parent | 5191d7c488462afd4d97e46865b83e939552c4dd (diff) |
New cli "c" interface to Connection.Manager.
-rw-r--r-- | Connection.hs | 6 | ||||
-rw-r--r-- | examples/dhtd.hs | 136 |
2 files changed, 56 insertions, 86 deletions
diff --git a/Connection.hs b/Connection.hs index 22c5b1da..3287bc1b 100644 --- a/Connection.hs +++ b/Connection.hs | |||
@@ -35,6 +35,12 @@ data Manager status k = Manager | |||
35 | , showKey :: k -> String | 35 | , showKey :: k -> String |
36 | } | 36 | } |
37 | 37 | ||
38 | showStatus :: Manager status k -> Status status -> String | ||
39 | showStatus mgr Dormant = "dormant" | ||
40 | showStatus mgr Established = "established" | ||
41 | showStatus mgr (InProgress s) = "in progress ("++showProgress mgr s++")" | ||
42 | |||
43 | |||
38 | addManagers :: (Ord kA, Ord kB) => | 44 | addManagers :: (Ord kA, Ord kB) => |
39 | Manager statusA kA | 45 | Manager statusA kA |
40 | -> Manager statusB kB | 46 | -> Manager statusB kB |
diff --git a/examples/dhtd.hs b/examples/dhtd.hs index abf0c297..219221e5 100644 --- a/examples/dhtd.hs +++ b/examples/dhtd.hs | |||
@@ -23,7 +23,6 @@ import Control.Applicative | |||
23 | import Control.Concurrent.STM | 23 | import Control.Concurrent.STM |
24 | import Control.Exception | 24 | import Control.Exception |
25 | import Control.Monad | 25 | import Control.Monad |
26 | import Control.Monad.IO.Class (liftIO) | ||
27 | import Control.Monad.Trans.Resource (runResourceT) | 26 | import Control.Monad.Trans.Resource (runResourceT) |
28 | import Data.Bool | 27 | import Data.Bool |
29 | import Data.Char | 28 | import Data.Char |
@@ -73,6 +72,7 @@ import qualified Data.Aeson as J | |||
73 | import qualified Data.ByteString.Lazy as L | 72 | import qualified Data.ByteString.Lazy as L |
74 | import qualified Data.ByteString.Char8 as B | 73 | import qualified Data.ByteString.Char8 as B |
75 | import Control.Concurrent.Tasks | 74 | import Control.Concurrent.Tasks |
75 | import Control.Monad.Trans.Control | ||
76 | import System.IO.Error | 76 | import System.IO.Error |
77 | import qualified Data.Serialize as S | 77 | import qualified Data.Serialize as S |
78 | import Network.BitTorrent.DHT.ContactInfo as Peers | 78 | import Network.BitTorrent.DHT.ContactInfo as Peers |
@@ -94,6 +94,7 @@ import OnionRouter | |||
94 | import ConsoleWriter | 94 | import ConsoleWriter |
95 | import Presence | 95 | import Presence |
96 | import XMPPServer | 96 | import XMPPServer |
97 | import Connection | ||
97 | 98 | ||
98 | 99 | ||
99 | showReport :: [(String,String)] -> String | 100 | showReport :: [(String,String)] -> String |
@@ -154,21 +155,6 @@ data DHTAnnouncable nid = forall dta tok ni r. | |||
154 | , qresultAddr :: dta -> nid | 155 | , qresultAddr :: dta -> nid |
155 | } | 156 | } |
156 | 157 | ||
157 | data DHTLink = forall status linkid params. | ||
158 | ( Show status | ||
159 | , Show linkid | ||
160 | , Typeable status | ||
161 | , Typeable linkid | ||
162 | , Typeable params | ||
163 | ) => DHTLink | ||
164 | { linkInit :: params -> IO (Either String status) | ||
165 | , linkParamParser :: [String] -> Either String params | ||
166 | , linkStatus :: IO (Either String status) | ||
167 | , showLinkStatus :: status -> String | ||
168 | , linkNewPipe :: String -> linkid -> IO (Either String status) | ||
169 | , linkUnPipe :: linkid -> IO (Either String status) | ||
170 | } | ||
171 | |||
172 | data DHTSearch nid ni = forall addr tok r. DHTSearch | 158 | data DHTSearch nid ni = forall addr tok r. DHTSearch |
173 | { searchThread :: ThreadId | 159 | { searchThread :: ThreadId |
174 | , searchState :: SearchState nid addr tok ni r | 160 | , searchState :: SearchState nid addr tok ni r |
@@ -199,7 +185,6 @@ data DHT = forall nid ni. ( Show ni | |||
199 | , dhtPing :: Map.Map String (DHTPing ni) | 185 | , dhtPing :: Map.Map String (DHTPing ni) |
200 | , dhtQuery :: Map.Map String (DHTQuery nid ni) | 186 | , dhtQuery :: Map.Map String (DHTQuery nid ni) |
201 | , dhtAnnouncables :: Map.Map String (DHTAnnouncable nid) | 187 | , dhtAnnouncables :: Map.Map String (DHTAnnouncable nid) |
202 | , dhtLinks :: Map.Map String DHTLink | ||
203 | , dhtParseId :: String -> Either String nid | 188 | , dhtParseId :: String -> Either String nid |
204 | , dhtSearches :: TVar (Map.Map (String,nid) (DHTSearch nid ni)) | 189 | , dhtSearches :: TVar (Map.Map (String,nid) (DHTSearch nid ni)) |
205 | , dhtFallbackNodes :: IO [ni] | 190 | , dhtFallbackNodes :: IO [ni] |
@@ -383,6 +368,8 @@ reportSearchResults meth h DHTSearch{searchShowTok,searchState,searchResults} = | |||
383 | ns' = map showN ns | 368 | ns' = map showN ns |
384 | reportResult meth id (const Nothing) id h (Right (ns',rs, Just ())) | 369 | reportResult meth id (const Nothing) id h (Right (ns',rs, Just ())) |
385 | 370 | ||
371 | data ConnectionManager = forall status k. ConnectionManager { typedManager :: Connection.Manager status k } | ||
372 | |||
386 | data Session = Session | 373 | data Session = Session |
387 | { netname :: String | 374 | { netname :: String |
388 | , dhts :: Map.Map String DHT | 375 | , dhts :: Map.Map String DHT |
@@ -392,6 +379,7 @@ data Session = Session | |||
392 | , toxkeys :: TVar Tox.AnnouncedKeys | 379 | , toxkeys :: TVar Tox.AnnouncedKeys |
393 | , userkeys :: TVar [(SecretKey,PublicKey)] | 380 | , userkeys :: TVar [(SecretKey,PublicKey)] |
394 | , roster :: Roster | 381 | , roster :: Roster |
382 | , connectionManager :: ConnectionManager | ||
395 | , onionRouter :: OnionRouter | 383 | , onionRouter :: OnionRouter |
396 | , announcer :: Announcer | 384 | , announcer :: Announcer |
397 | , signalQuit :: IO () | 385 | , signalQuit :: IO () |
@@ -641,7 +629,6 @@ clientSession s@Session{..} sock cnum h = do | |||
641 | hPutClientChunk h $ "trampolines: " ++ show (IntMap.size ts) ++ "\n" | 629 | hPutClientChunk h $ "trampolines: " ++ show (IntMap.size ts) ++ "\n" |
642 | hPutClient h $ showColumns $ ["","responses","timeouts"]:r | 630 | hPutClient h $ showColumns $ ["","responses","timeouts"]:r |
643 | 631 | ||
644 | |||
645 | ("g", s) | Just DHT{..} <- Map.lookup netname dhts | 632 | ("g", s) | Just DHT{..} <- Map.lookup netname dhts |
646 | -> cmd0 $ do | 633 | -> cmd0 $ do |
647 | -- arguments: method | 634 | -- arguments: method |
@@ -909,46 +896,29 @@ clientSession s@Session{..} sock cnum h = do | |||
909 | mkentry (k :-> Down tm) = [ show cnt, show k, show (now - tm) ] | 896 | mkentry (k :-> Down tm) = [ show cnt, show k, show (now - tm) ] |
910 | where Just (_,(cnt,_)) = MM.lookup' k (Tox.keyAssoc keydb) | 897 | where Just (_,(cnt,_)) = MM.lookup' k (Tox.keyAssoc keydb) |
911 | hPutClient h $ showColumns entries | 898 | hPutClient h $ showColumns entries |
912 | ("c", s) | "" <- strp s -> cmd0 $ do | 899 | |
913 | let combinedLinkMap = Map.unions $map (dhtLinks . snd) (Map.toList dhts) | 900 | ("c", s) | "" <- strp s -> cmd0 $ join $ atomically $ do |
914 | -- TODO: list all connections | 901 | ConnectionManager mgr <- return connectionManager |
915 | let connections = [[{-TODO-}]] | 902 | cmap <- connections mgr |
916 | hPutClient h $ showColumns connections | 903 | cs <- Map.toList <$> mapM connStatus cmap |
917 | ("c", s) -> cmd0 $ do | 904 | let mkrow = Connection.showKey mgr *** Connection.showStatus mgr |
918 | let combinedLinkMap = Map.unions $map (dhtLinks . snd) (Map.toList dhts) | 905 | rs = map mkrow cs |
919 | -- form new connection according of type corresponding to parameter | 906 | return $ do |
920 | let ws = words s | 907 | hPutClient h $ showReport rs |
921 | result | ||
922 | <- case ws of | ||
923 | (linktype:rest) | ||
924 | -> case (Map.lookup (head ws) combinedLinkMap) of | ||
925 | Nothing -> return . Left $ "I don't know a '" ++ head ws ++ "' link type." | ||
926 | Just l@(DHTLink | ||
927 | { linkInit {- :: params -> IO (Either String status) -} | ||
928 | , linkParamParser {- :: [String] -> Either String params -} | ||
929 | , showLinkStatus {- :: status -> String -} | ||
930 | }) -> case linkParamParser rest of | ||
931 | Left er -> return $ Left er | ||
932 | Right params -> fmap showLinkStatus <$> linkInit params | ||
933 | _ -> return $ Left "parse error" | ||
934 | case result of | ||
935 | Left er -> hPutClient h er | ||
936 | Right statusstr -> hPutClient h statusstr | ||
937 | 908 | ||
938 | ("help", s) | Just DHT{..} <- Map.lookup netname dhts | 909 | ("help", s) | Just DHT{..} <- Map.lookup netname dhts |
939 | -> cmd0 $ do | 910 | -> cmd0 $ do |
940 | let tolist :: a -> [a] | 911 | let tolist :: a -> [a] |
941 | tolist = (:[]) | 912 | tolist = (:[]) |
942 | 913 | ||
943 | dhtkeys, announcables, links, ks, allcommands :: [[String]] | 914 | dhtkeys, announcables, ks, allcommands :: [[String]] |
944 | dhtkeys = map tolist $ Map.keys dhts | 915 | dhtkeys = map tolist $ Map.keys dhts |
945 | queries = map (tolist . ("s "++)) $ Map.keys dhtQuery | 916 | queries = map (tolist . ("s "++)) $ Map.keys dhtQuery |
946 | xs = map (tolist . ("x "++)) $ Map.keys dhtQuery | 917 | xs = map (tolist . ("x "++)) $ Map.keys dhtQuery |
947 | gs = map (tolist . ("g "++)) $ Map.keys dhtQuery | 918 | gs = map (tolist . ("g "++)) $ Map.keys dhtQuery |
948 | announcables = map (tolist . ("p "++)) $ Map.keys dhtAnnouncables | 919 | announcables = map (tolist . ("p "++)) $ Map.keys dhtAnnouncables |
949 | links = map (tolist . ("c "++)) $ Map.keys dhtLinks | ||
950 | ks = [["k gen"],["k public"],["k secret"]] | 920 | ks = [["k gen"],["k public"],["k secret"]] |
951 | allcommands = sortBy (comparing head) $ concat [sessionCommands, dhtkeys, announcables, links, ks, queries, gs,xs] | 921 | allcommands = sortBy (comparing (take 1)) $ concat [sessionCommands, dhtkeys, announcables, ks, queries, gs,xs] |
952 | 922 | ||
953 | hPutClient h ("Available commands:\n" ++ showColumns allcommands) | 923 | hPutClient h ("Available commands:\n" ++ showColumns allcommands) |
954 | 924 | ||
@@ -1013,7 +983,7 @@ noArgPing f [] x = f x | |||
1013 | noArgPing _ _ _ = return Nothing | 983 | noArgPing _ _ _ = return Nothing |
1014 | 984 | ||
1015 | main :: IO () | 985 | main :: IO () |
1016 | main = do | 986 | main = runResourceT $ liftBaseWith $ \resT -> do |
1017 | args <- getArgs | 987 | args <- getArgs |
1018 | let opts = parseArgs args sensibleDefaults | 988 | let opts = parseArgs args sensibleDefaults |
1019 | print opts | 989 | print opts |
@@ -1027,6 +997,18 @@ main = do | |||
1027 | 997 | ||
1028 | announcer <- forkAnnouncer | 998 | announcer <- forkAnnouncer |
1029 | 999 | ||
1000 | -- XMPP initialization | ||
1001 | cw <- newConsoleWriter | ||
1002 | serverVar <- atomically $ newEmptyTMVar | ||
1003 | state <- newPresenceState cw serverVar | ||
1004 | |||
1005 | -- XMPP stanza handling | ||
1006 | sv <- resT $ xmppServer (presenceHooks state (verbosity opts)) | ||
1007 | -- We now have a server object but it's not ready to use until | ||
1008 | -- we put it into the 'server' field of our /state/ record. | ||
1009 | |||
1010 | conns <- xmppConnections sv | ||
1011 | |||
1030 | (quitBt,btdhts,btips,baddrs) <- case portbt opts of | 1012 | (quitBt,btdhts,btips,baddrs) <- case portbt opts of |
1031 | "" -> return (return (), Map.empty,return [],[]) | 1013 | "" -> return (return (), Map.empty,return [],[]) |
1032 | p -> do | 1014 | p -> do |
@@ -1097,9 +1079,6 @@ main = do | |||
1097 | , qresultAddr = const $ Mainline.zeroID | 1079 | , qresultAddr = const $ Mainline.zeroID |
1098 | })] | 1080 | })] |
1099 | 1081 | ||
1100 | , dhtLinks = Map.fromList | ||
1101 | [ {- TODO -} | ||
1102 | ] | ||
1103 | , dhtSecretKey = return Nothing | 1082 | , dhtSecretKey = return Nothing |
1104 | , dhtBootstrap = case wantip of | 1083 | , dhtBootstrap = case wantip of |
1105 | Want_IP4 -> btBootstrap4 | 1084 | Want_IP4 -> btBootstrap4 |
@@ -1279,9 +1258,6 @@ main = do | |||
1279 | 1258 | ||
1280 | , announceInterval = 8 | 1259 | , announceInterval = 8 |
1281 | })] | 1260 | })] |
1282 | , dhtLinks = Map.fromList | ||
1283 | [ {- TODO -} | ||
1284 | ] | ||
1285 | , dhtSecretKey = return $ Just $ transportSecret (Tox.toxCryptoKeys tox) | 1261 | , dhtSecretKey = return $ Just $ transportSecret (Tox.toxCryptoKeys tox) |
1286 | , dhtBootstrap = case wantip of | 1262 | , dhtBootstrap = case wantip of |
1287 | Want_IP4 -> toxStrap4 | 1263 | Want_IP4 -> toxStrap4 |
@@ -1322,6 +1298,7 @@ main = do | |||
1322 | , toxkeys = keysdb | 1298 | , toxkeys = keysdb |
1323 | , userkeys = toxids | 1299 | , userkeys = toxids |
1324 | , roster = rstr | 1300 | , roster = rstr |
1301 | , connectionManager = ConnectionManager conns | ||
1325 | , onionRouter = orouter | 1302 | , onionRouter = orouter |
1326 | , externalAddresses = liftM2 (++) btips toxips | 1303 | , externalAddresses = liftM2 (++) btips toxips |
1327 | , announcer = announcer | 1304 | , announcer = announcer |
@@ -1352,39 +1329,26 @@ main = do | |||
1352 | bootstrap btSaved fallbackNodes | 1329 | bootstrap btSaved fallbackNodes |
1353 | return () | 1330 | return () |
1354 | 1331 | ||
1355 | -- XMPP initialization | 1332 | atomically $ do |
1356 | cw <- newConsoleWriter | 1333 | putTMVar serverVar (sv,conns) -- Okay, now it's ready. :) |
1357 | serverVar <- atomically $ newEmptyTMVar | 1334 | -- FIXME: This is error prone. |
1358 | state <- newPresenceState cw serverVar | 1335 | |
1359 | 1336 | forkIO $ do | |
1360 | -- XMPP stanza handling | 1337 | myThreadId >>= flip labelThread "XMPP.stanzas" |
1361 | runResourceT $ do | 1338 | let console = cwPresenceChan <$> consoleWriter state |
1362 | sv <- xmppServer (presenceHooks state (verbosity opts)) | 1339 | fix $ \loop -> do |
1363 | -- We now have a server object but it's not ready to use until | 1340 | what <- atomically |
1364 | -- we put it into the 'server' field of our /state/ record. | 1341 | $ orElse (do (client,stanza) <- maybe retry takeTMVar console |
1365 | 1342 | return $ do informClientPresence0 state Nothing client stanza | |
1366 | liftIO $ do | 1343 | loop) |
1367 | conns <- xmppConnections sv | 1344 | (checkQuit >> return (return ())) |
1368 | atomically $ do | 1345 | what |
1369 | putTMVar serverVar (sv,conns) -- Okay, now it's ready. :) | 1346 | |
1370 | -- FIXME: This is error prone. | 1347 | hPutStrLn stderr "Started XMPP server." |
1371 | 1348 | ||
1372 | forkIO $ do | 1349 | -- Wait for DHT and XMPP threads to finish. |
1373 | myThreadId >>= flip labelThread "XMPP.stanzas" | 1350 | -- Use ResourceT to clean-up XMPP server. |
1374 | let console = cwPresenceChan <$> consoleWriter state | 1351 | waitForSignal |
1375 | fix $ \loop -> do | ||
1376 | what <- atomically | ||
1377 | $ orElse (do (client,stanza) <- maybe retry takeTMVar console | ||
1378 | return $ do informClientPresence0 state Nothing client stanza | ||
1379 | loop) | ||
1380 | (checkQuit >> return (return ())) | ||
1381 | what | ||
1382 | |||
1383 | hPutStrLn stderr "Started XMPP server." | ||
1384 | |||
1385 | -- Wait for DHT and XMPP threads to finish. | ||
1386 | -- Use ResourceT to clean-up XMPP server. | ||
1387 | waitForSignal | ||
1388 | 1352 | ||
1389 | stopAnnouncer announcer | 1353 | stopAnnouncer announcer |
1390 | quitBt | 1354 | quitBt |