summaryrefslogtreecommitdiff
path: root/ToxManager.hs
diff options
context:
space:
mode:
Diffstat (limited to 'ToxManager.hs')
-rw-r--r--ToxManager.hs154
1 files changed, 154 insertions, 0 deletions
diff --git a/ToxManager.hs b/ToxManager.hs
new file mode 100644
index 00000000..81def17f
--- /dev/null
+++ b/ToxManager.hs
@@ -0,0 +1,154 @@
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE NamedFieldPuns #-}
4module ToxManager where
5
6import Announcer
7import Connection
8-- import Control.Concurrent
9import Control.Concurrent.STM
10import Control.Monad
11import Crypto.Tox
12import Data.HashMap.Strict as HashMap
13import Data.Maybe
14import qualified Data.Set as Set
15import qualified Data.Text as T
16import Data.Time.Clock.POSIX
17import Network.Address
18import Network.Kademlia.Routing as R
19import Network.Kademlia.Search
20import qualified Network.Tox as Tox
21import Network.Tox.ContactInfo as Tox
22import qualified Network.Tox.Crypto.Handlers as Tox
23-- import qualified Network.Tox.DHT.Handlers as Tox
24import qualified Network.Tox.DHT.Transport as Tox
25import qualified Network.Tox.Onion.Handlers as Tox
26import qualified Network.Tox.Onion.Transport as Tox
27import Presence
28import System.IO
29import Text.Read
30import ToxToXMPP
31import XMPPServer (ConnectionKey)
32
33#ifdef THREAD_DEBUG
34import Control.Concurrent.Lifted.Instrument
35#else
36import Control.Concurrent.Lifted
37import GHC.Conc (labelThread)
38#endif
39
40toxAnnounceInterval :: POSIXTime
41toxAnnounceInterval = 15
42
43toxAnnounceSendData :: Tox.Tox -> PublicKey
44 -> Nonce32
45 -> Maybe Tox.NodeInfo
46 -> IO (Maybe (Tox.Rendezvous, Tox.AnnounceResponse))
47toxAnnounceSendData tox pubkey token = \case
48 Just ni -> Tox.putRendezvous (Tox.onionTimeout tox)
49 (Tox.toxCryptoKeys tox)
50 (Tox.toxOnion tox)
51 (pubkey :: PublicKey)
52 (token :: Nonce32)
53 ni
54 Nothing -> return Nothing
55
56
57toxQSearch :: Tox.Tox -> Search Tox.NodeId (IP, PortNumber) Nonce32 Tox.NodeInfo Tox.Rendezvous
58toxQSearch tox = Tox.toxidSearch (Tox.onionTimeout tox) (Tox.toxCryptoKeys tox) (Tox.toxOnion tox)
59
60-- |
61--
62-- These hooks will be invoked in order to connect to *.tox hosts in a user's
63-- XMPP roster.
64toxman :: Announcer -> [(String,TVar (BucketList Tox.NodeInfo))] -> Tox.Tox -> PresenceState -> ToxManager ConnectionKey
65toxman announcer toxbkts tox presence = ToxManager
66 { activateAccount = \k pubname seckey -> do
67 hPutStrLn stderr $ "toxman ACTIVATE " ++ show (Tox.key2id $ toPublic seckey)
68 let ContactInfo{ accounts } = Tox.toxContactInfo tox
69 pub = toPublic seckey
70 pubid = Tox.key2id pub
71 (acnt,newlyActive) <- atomically $ do
72 macnt <- HashMap.lookup pubid <$> readTVar accounts
73 acnt <- maybe (newAccount seckey) return macnt
74 rs <- readTVar $ clientRefs acnt
75 writeTVar (clientRefs acnt) $! Set.insert k rs
76 modifyTVar accounts (HashMap.insert pubid acnt)
77 if not (Set.null rs)
78 then return (acnt,[])
79 else do
80 fmap ((,) acnt) $ forM toxbkts $ \(nm,bkts) -> do
81 akey <- packAnnounceKey announcer (nm ++ "id:" ++ show pubid)
82 return (akey,bkts)
83 forM_ newlyActive $ \(akey,bkts) -> do
84 -- Schedule recurring announce.
85 --
86 schedule announcer
87 akey
88 (AnnounceMethod (toxQSearch tox)
89 (Right $ toxAnnounceSendData tox)
90 bkts
91 pubid
92 toxAnnounceInterval)
93 pub
94
95 forkAccountWatcher acnt tox presence
96 return ()
97
98 , deactivateAccount = \k pubname -> do
99 hPutStrLn stderr $ "toxman DECTIVATE (todo) 1 " ++ show pubname
100 let ContactInfo{ accounts } = Tox.toxContactInfo tox
101 mpubid = readMaybe $ T.unpack $ T.take 43 pubname
102 bStopped <- fmap (fromMaybe Nothing) $ atomically $ do
103 forM mpubid $ \pubid -> do
104 refs <- do
105 macnt <- HashMap.lookup pubid <$> readTVar accounts
106 rs <- fromMaybe Set.empty <$> mapM (readTVar . clientRefs) macnt
107 forM_ macnt $ \acnt -> do
108 modifyTVar' (clientRefs acnt) $ Set.delete k
109 return rs
110 if (Set.null $ refs Set.\\ Set.singleton k) then do
111 -- TODO
112 -- If this is the last reference to a non-connected contact:
113 -- Stop the recurring search for that contact
114 --
115 -- Stop recurring announce.
116 fmap Just $ forM toxbkts $ \(nm,bkts) -> do
117 akey <- packAnnounceKey announcer (nm ++ "id:" ++ show pubid)
118 return (akey,bkts)
119 else return Nothing
120 forM_ bStopped $ \kbkts -> do
121 hPutStrLn stderr $ "toxman DECTIVATE (todo) 3 " ++ show pubname
122 let Just pubid = mpubid
123 pub = Tox.id2key pubid
124 forM_ kbkts $ \(akey,bkts) -> do
125 cancel announcer
126 akey
127 (AnnounceMethod (toxQSearch tox)
128 (Right $ toxAnnounceSendData tox)
129 bkts
130 pubid
131 toxAnnounceInterval)
132 pub
133
134 , setToxConnectionPolicy = \me them p -> do
135 let m = do meid <- readMaybe $ T.unpack $ T.take 43 me
136 themid <- readMaybe $ T.unpack $ T.take 43 them
137 return $ Tox.Key meid themid
138 hPutStrLn stderr $ "toxman ConnectionPolicy " ++ show (me,them,p,fmap (const ()) m)
139 forM_ m $ \k -> do
140 setPolicy (Tox.toxMgr tox) k p
141 case p of
142 TryingToConnect -> do
143 let db@ContactInfo{ accounts } = Tox.toxContactInfo tox
144 sequence_ $ do
145 let Tox.Key meid themid = k
146 Just $ atomically $ do
147 accs <- readTVar accounts
148 case HashMap.lookup meid accs of
149 Nothing -> return () -- Unknown account.
150 Just acc -> setContactPolicy (Tox.id2key themid) TryingToConnect acc
151 -- If unscheduled and unconnected, schedule recurring search for this contact.
152 _ -> return () -- Remove contact.
153 }
154