aboutsummaryrefslogtreecommitdiff
path: root/Assistant/Threads
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2012-10-26 12:55:29 -0400
committerGravatar Joey Hess <joey@kitenet.net>2012-10-26 12:55:29 -0400
commit71a94e5cc6b1249998fe305a971604501e027c7b (patch)
tree287df99eb08831c11841dd3f93ecc157bbec66b0 /Assistant/Threads
parent89a33e4ce1219dff81f6c5fd296b6e6ba6866ea3 (diff)
hook up SRV lookups for XMPP
Diffstat (limited to 'Assistant/Threads')
-rw-r--r--Assistant/Threads/PushNotifier.hs62
1 files changed, 42 insertions, 20 deletions
diff --git a/Assistant/Threads/PushNotifier.hs b/Assistant/Threads/PushNotifier.hs
index 088e97ec4..2784012f2 100644
--- a/Assistant/Threads/PushNotifier.hs
+++ b/Assistant/Threads/PushNotifier.hs
@@ -16,15 +16,17 @@ import Assistant.DaemonStatus
import Assistant.Pushes
import Assistant.Sync
import qualified Remote
+import Utility.FileMode
+import Utility.SRV
import Network.Protocol.XMPP
import Network
import Control.Concurrent
import qualified Data.Text as T
import qualified Data.Set as S
-import Utility.FileMode
import qualified Git.Branch
import Data.XML.Types
+import Control.Exception as E
thisThread :: ThreadName
thisThread = "PushNotifier"
@@ -33,27 +35,16 @@ pushNotifierThread :: ThreadState -> DaemonStatusHandle -> PushNotifier -> Named
pushNotifierThread st dstatus pushnotifier = NamedThread thisThread $ do
v <- runThreadState st $ getXMPPCreds
case v of
- Nothing -> nocreds
- Just c -> case parseJID (xmppJID c) of
- Nothing -> nocreds
- Just jid -> void $ client c jid
- where
- nocreds = do
- error "no creds" -- TODO alert
- return () -- exit thread
-
- client c jid = runClient server jid (xmppUsername c) (xmppPassword c) $ do
- void $ bindJID jid
+ Nothing -> do
+ return () -- no creds? exit thread
+ Just c -> void $ connectXMPP c $ \jid -> do
+ fulljid <- bindJID jid
+ liftIO $ debug thisThread ["XMPP connected", show fulljid]
s <- getSession
_ <- liftIO $ forkOS $ void $ runXMPP s $
receivenotifications
sendnotifications
- where
- server = Server
- (JID Nothing (jidDomain jid) Nothing)
- (xmppHostname c)
- (PortNumber $ fromIntegral $ xmppPort c)
-
+ where
sendnotifications = forever $ do
us <- liftIO $ waitPush pushnotifier
let payload = [extendedAway, encodePushNotification us]
@@ -78,12 +69,43 @@ data XMPPCreds = XMPPCreds
, xmppPassword :: T.Text
, xmppHostname :: HostName
, xmppPort :: Int
- {- Something like username@hostname, but not necessarily the same
- - username or hostname used to connect to the server. -}
, xmppJID :: T.Text
}
deriving (Read, Show)
+{- Note that this must be run in a bound thread; gnuTLS requires it. -}
+connectXMPP :: XMPPCreds -> (JID -> XMPP a) -> IO (Either SomeException ())
+connectXMPP c a = case parseJID (xmppJID c) of
+ Nothing -> error "bad JID"
+ Just jid -> connectXMPP' jid c a
+
+{- Do a SRV lookup, but if it fails, fall back to the cached xmppHostname. -}
+connectXMPP' :: JID -> XMPPCreds -> (JID -> XMPP a) -> IO (Either SomeException ())
+connectXMPP' jid c a = go =<< lookupSRV srvrecord
+ where
+ srvrecord = "_xmpp-client._tcp." ++ (T.unpack $ strDomain $ jidDomain jid)
+ serverjid = JID Nothing (jidDomain jid) Nothing
+
+ go [] = run (xmppHostname c)
+ (PortNumber $ fromIntegral $ xmppPort c)
+ (a jid)
+ go ((h,p):rest) = do
+ {- Try each SRV record in turn, until one connects,
+ - at which point the MVar will be full. -}
+ mv <- newEmptyMVar
+ r <- run h p $ do
+ liftIO $ putMVar mv ()
+ a jid
+ ifM (isEmptyMVar mv) (go rest, return r)
+
+ run h p a' = do
+ liftIO $ debug thisThread ["XMPP trying", h]
+ E.try (runClientError (Server serverjid h p) jid (xmppUsername c) (xmppPassword c) (void a')) :: IO (Either SomeException ())
+
+{- XMPP runClient, that throws errors rather than returning an Either -}
+runClientError :: Server -> JID -> T.Text -> T.Text -> XMPP a -> IO a
+runClientError s j u p x = either (error . show) return =<< runClient s j u p x
+
getXMPPCreds :: Annex (Maybe XMPPCreds)
getXMPPCreds = do
f <- xmppCredsFile