Assistant monad, stage 2.5

Converted several threads to run in the monad.

Added a lot of useful combinators for working with the monad.

Now the monad includes the name of the thread.

Some debugging messages are disabled pending converting other threads.
This commit is contained in:
Joey Hess 2012-10-29 02:21:04 -04:00
parent 4e765327ca
commit 4dbdc2b666
29 changed files with 299 additions and 280 deletions

View file

@ -179,7 +179,7 @@ startAssistant assistant daemonize webappwaiter = withThreadState $ \st -> do
go = do go = do
d <- getAssistant id d <- getAssistant id
st <- getAssistant threadState st <- getAssistant threadState
dstatus <- getAssistant daemonStatus dstatus <- getAssistant daemonStatusHandle
changechan <- getAssistant changeChan changechan <- getAssistant changeChan
commitchan <- getAssistant commitChan commitchan <- getAssistant commitChan
pushmap <- getAssistant failedPushMap pushmap <- getAssistant failedPushMap
@ -189,7 +189,7 @@ startAssistant assistant daemonize webappwaiter = withThreadState $ \st -> do
branchhandle <- getAssistant branchChangeHandle branchhandle <- getAssistant branchChangeHandle
pushnotifier <- getAssistant pushNotifier pushnotifier <- getAssistant pushNotifier
#ifdef WITH_WEBAPP #ifdef WITH_WEBAPP
urlrenderer <- liftIO $ newUrlRenderer urlrenderer <- liftIO newUrlRenderer
#endif #endif
mapM_ (startthread d) mapM_ (startthread d)
[ watch $ commitThread st changechan commitchan transferqueue dstatus [ watch $ commitThread st changechan commitchan transferqueue dstatus
@ -203,13 +203,13 @@ startAssistant assistant daemonize webappwaiter = withThreadState $ \st -> do
, assist $ pushRetryThread st dstatus pushmap pushnotifier , assist $ pushRetryThread st dstatus pushmap pushnotifier
, assist $ mergeThread st dstatus transferqueue branchhandle , assist $ mergeThread st dstatus transferqueue branchhandle
, assist $ transferWatcherThread st dstatus transferqueue , assist $ transferWatcherThread st dstatus transferqueue
, assist $ transferPollerThread st dstatus , assist $ transferPollerThread
, assist $ transfererThread st dstatus transferqueue transferslots commitchan , assist $ transfererThread st dstatus transferqueue transferslots commitchan
, assist $ daemonStatusThread st dstatus , assist $ daemonStatusThread
, assist $ sanityCheckerThread st dstatus transferqueue changechan , assist $ sanityCheckerThread
, assist $ mountWatcherThread st dstatus scanremotes pushnotifier , assist $ mountWatcherThread st dstatus scanremotes pushnotifier
, assist $ netWatcherThread st dstatus scanremotes pushnotifier , assist $ netWatcherThread
, assist $ netWatcherFallbackThread st dstatus scanremotes pushnotifier , assist $ netWatcherFallbackThread
, assist $ transferScannerThread st dstatus scanremotes transferqueue , assist $ transferScannerThread st dstatus scanremotes transferqueue
, assist $ configMonitorThread st dstatus branchhandle commitchan , assist $ configMonitorThread st dstatus branchhandle commitchan
#ifdef WITH_XMPP #ifdef WITH_XMPP

View file

@ -10,7 +10,8 @@ module Assistant.Common (
ThreadName, ThreadName,
NamedThread(..), NamedThread(..),
runNamedThread, runNamedThread,
debug debug,
brokendebug
) where ) where
import Common.Annex as X import Common.Annex as X
@ -22,25 +23,28 @@ import System.Log.Logger
import qualified Control.Exception as E import qualified Control.Exception as E
type ThreadName = String type ThreadName = String
data NamedThread = NamedThread ThreadName (IO ()) data NamedThread = NamedThread ThreadName (Assistant ())
debug :: ThreadName -> [String] -> IO () brokendebug :: ThreadName -> [String] -> IO ()
debug threadname ws = debugM threadname $ unwords $ (threadname ++ ":") : ws brokendebug _ _ = noop -- TODO remove this
debug :: [String] -> Assistant ()
debug ws = do
name <- getAssistant threadName
liftIO $ debugM name $ unwords $ (name ++ ":") : ws
runNamedThread :: NamedThread -> Assistant () runNamedThread :: NamedThread -> Assistant ()
runNamedThread (NamedThread name a) = liftIO . go =<< getAssistant daemonStatus runNamedThread (NamedThread name a) = do
where d <- getAssistant id
go dstatus = do liftIO . go $ d { threadName = name }
r <- E.try a :: IO (Either E.SomeException ()) where
case r of go d = do
Right _ -> noop r <- E.try (runAssistant a d) :: IO (Either E.SomeException ())
Left e -> do case r of
let msg = unwords Right _ -> noop
[ name Left e -> do
, "crashed:" let msg = unwords [name, "crashed:", show e]
, show e hPutStrLn stderr msg
] -- TODO click to restart
hPutStrLn stderr msg void $ addAlert (daemonStatusHandle d) $
-- TODO click to restart warningAlert name msg
void $ addAlert dstatus $
warningAlert name msg

View file

@ -181,8 +181,8 @@ adjustTransfersSTM dstatus a = do
putTMVar dstatus $ s { currentTransfers = a (currentTransfers s) } putTMVar dstatus $ s { currentTransfers = a (currentTransfers s) }
{- Alters a transfer's info, if the transfer is in the map. -} {- Alters a transfer's info, if the transfer is in the map. -}
alterTransferInfo :: DaemonStatusHandle -> Transfer -> (TransferInfo -> TransferInfo) -> IO () alterTransferInfo :: Transfer -> (TransferInfo -> TransferInfo) -> DaemonStatusHandle -> IO ()
alterTransferInfo dstatus t a = updateTransferInfo' dstatus $ M.adjust a t alterTransferInfo t a dstatus = updateTransferInfo' dstatus $ M.adjust a t
{- Updates a transfer's info. Adds the transfer to the map if necessary, {- Updates a transfer's info. Adds the transfer to the map if necessary,
- or if already present, updates it while preserving the old transferTid, - or if already present, updates it while preserving the old transferTid,

View file

@ -13,7 +13,12 @@ module Assistant.Monad (
newAssistantData, newAssistantData,
runAssistant, runAssistant,
getAssistant, getAssistant,
liftAnnex liftAnnex,
(<~>),
(<<~),
daemonStatus,
asIO,
asIO2,
) where ) where
import "mtl" Control.Monad.Reader import "mtl" Control.Monad.Reader
@ -43,8 +48,9 @@ instance MonadBase IO Assistant where
liftBase = Assistant . liftBase liftBase = Assistant . liftBase
data AssistantData = AssistantData data AssistantData = AssistantData
{ threadState :: ThreadState { threadName :: String
, daemonStatus :: DaemonStatusHandle , threadState :: ThreadState
, daemonStatusHandle :: DaemonStatusHandle
, scanRemoteMap :: ScanRemoteMap , scanRemoteMap :: ScanRemoteMap
, transferQueue :: TransferQueue , transferQueue :: TransferQueue
, transferSlots :: TransferSlots , transferSlots :: TransferSlots
@ -57,7 +63,8 @@ data AssistantData = AssistantData
newAssistantData :: ThreadState -> DaemonStatusHandle -> IO AssistantData newAssistantData :: ThreadState -> DaemonStatusHandle -> IO AssistantData
newAssistantData st dstatus = AssistantData newAssistantData st dstatus = AssistantData
<$> pure st <$> pure "main"
<*> pure st
<*> pure dstatus <*> pure dstatus
<*> newScanRemoteMap <*> newScanRemoteMap
<*> newTransferQueue <*> newTransferQueue
@ -81,3 +88,28 @@ liftAnnex :: Annex a -> Assistant a
liftAnnex a = do liftAnnex a = do
st <- reader threadState st <- reader threadState
liftIO $ runThreadState st a liftIO $ runThreadState st a
{- Runs an IO action, passing it an IO action that runs an Assistant action. -}
(<~>) :: (IO a -> IO b) -> Assistant a -> Assistant b
io <~> a = do
d <- reader id
liftIO $ io $ runAssistant a d
{- Creates an IO action that will run an Assistant action when run. -}
asIO :: (a -> Assistant b) -> Assistant (a -> IO b)
asIO a = do
d <- reader id
return $ \v -> runAssistant (a v) d
{- Creates an IO action that will run an Assistant action when run. -}
asIO2 :: (a -> b -> Assistant c) -> Assistant (a -> b -> IO c)
asIO2 a = do
d <- reader id
return $ \v1 v2 -> runAssistant (a v1 v2) d
{- Runs an IO action on a selected field of the AssistantData. -}
(<<~) :: (a -> IO b) -> (AssistantData -> a) -> Assistant b
io <<~ v = reader v >>= liftIO . io
daemonStatus :: Assistant DaemonStatus
daemonStatus = getDaemonStatus <<~ daemonStatusHandle

View file

@ -93,7 +93,7 @@ pushToRemotes threadname now st mpushnotifier mpushmap remotes = do
where where
go _ Nothing _ _ _ = return True -- no branch, so nothing to do go _ Nothing _ _ _ = return True -- no branch, so nothing to do
go shouldretry (Just branch) g u rs = do go shouldretry (Just branch) g u rs = do
debug threadname brokendebug threadname
[ "pushing to" [ "pushing to"
, show rs , show rs
] ]
@ -117,12 +117,12 @@ pushToRemotes threadname now st mpushnotifier mpushmap remotes = do
makemap l = M.fromList $ zip l (repeat now) makemap l = M.fromList $ zip l (repeat now)
retry branch g u rs = do retry branch g u rs = do
debug threadname [ "trying manual pull to resolve failed pushes" ] brokendebug threadname [ "trying manual pull to resolve failed pushes" ]
void $ manualPull st (Just branch) rs void $ manualPull st (Just branch) rs
go False (Just branch) g u rs go False (Just branch) g u rs
fallback branch g u rs = do fallback branch g u rs = do
debug threadname brokendebug threadname
[ "fallback pushing to" [ "fallback pushing to"
, show rs , show rs
] ]

View file

@ -42,7 +42,7 @@ thisThread = "Committer"
{- This thread makes git commits at appropriate times. -} {- This thread makes git commits at appropriate times. -}
commitThread :: ThreadState -> ChangeChan -> CommitChan -> TransferQueue -> DaemonStatusHandle -> NamedThread commitThread :: ThreadState -> ChangeChan -> CommitChan -> TransferQueue -> DaemonStatusHandle -> NamedThread
commitThread st changechan commitchan transferqueue dstatus = thread $ do commitThread st changechan commitchan transferqueue dstatus = thread $ liftIO $ do
delayadd <- runThreadState st $ delayadd <- runThreadState st $
maybe delayaddDefault (Just . Seconds) . readish maybe delayaddDefault (Just . Seconds) . readish
<$> getConfig (annexConfig "delayadd") "" <$> getConfig (annexConfig "delayadd") ""
@ -58,7 +58,7 @@ commitThread st changechan commitchan transferqueue dstatus = thread $ do
readychanges <- handleAdds delayadd st changechan transferqueue dstatus changes readychanges <- handleAdds delayadd st changechan transferqueue dstatus changes
if shouldCommit time readychanges if shouldCommit time readychanges
then do then do
debug thisThread brokendebug thisThread
[ "committing" [ "committing"
, show (length readychanges) , show (length readychanges)
, "changes" , "changes"
@ -72,7 +72,7 @@ commitThread st changechan commitchan transferqueue dstatus = thread $ do
thread = NamedThread thisThread thread = NamedThread thisThread
refill [] = noop refill [] = noop
refill cs = do refill cs = do
debug thisThread brokendebug thisThread
[ "delaying commit of" [ "delaying commit of"
, show (length cs) , show (length cs)
, "changes" , "changes"

View file

@ -38,7 +38,7 @@ thisThread = "ConfigMonitor"
- be detected immediately. - be detected immediately.
-} -}
configMonitorThread :: ThreadState -> DaemonStatusHandle -> BranchChangeHandle -> CommitChan -> NamedThread configMonitorThread :: ThreadState -> DaemonStatusHandle -> BranchChangeHandle -> CommitChan -> NamedThread
configMonitorThread st dstatus branchhandle commitchan = thread $ do configMonitorThread st dstatus branchhandle commitchan = thread $ liftIO $ do
r <- runThreadState st Annex.gitRepo r <- runThreadState st Annex.gitRepo
go r =<< getConfigs r go r =<< getConfigs r
where where
@ -50,7 +50,7 @@ configMonitorThread st dstatus branchhandle commitchan = thread $ do
new <- getConfigs r new <- getConfigs r
when (old /= new) $ do when (old /= new) $ do
let changedconfigs = new `S.difference` old let changedconfigs = new `S.difference` old
debug thisThread $ "reloading config" : brokendebug thisThread $ "reloading config" :
map fst (S.toList changedconfigs) map fst (S.toList changedconfigs)
reloadConfigs st dstatus changedconfigs reloadConfigs st dstatus changedconfigs
{- Record a commit to get this config {- Record a commit to get this config

View file

@ -9,28 +9,21 @@ module Assistant.Threads.DaemonStatus where
import Assistant.Common import Assistant.Common
import Assistant.DaemonStatus import Assistant.DaemonStatus
import Assistant.ThreadedMonad
import Utility.ThreadScheduler import Utility.ThreadScheduler
import Utility.NotificationBroadcaster import Utility.NotificationBroadcaster
thisThread :: ThreadName
thisThread = "DaemonStatus"
{- This writes the daemon status to disk, when it changes, but no more {- This writes the daemon status to disk, when it changes, but no more
- frequently than once every ten minutes. - frequently than once every ten minutes.
-} -}
daemonStatusThread :: ThreadState -> DaemonStatusHandle -> NamedThread daemonStatusThread :: NamedThread
daemonStatusThread st dstatus = thread $ do daemonStatusThread = NamedThread "DaemonStatus" $ do
notifier <- newNotificationHandle notifier <- liftIO . newNotificationHandle
=<< changeNotifier <$> getDaemonStatus dstatus =<< changeNotifier <$> daemonStatus
checkpoint checkpoint
runEvery (Seconds tenMinutes) $ do runEvery (Seconds tenMinutes) <~> do
waitNotification notifier liftIO $ waitNotification notifier
checkpoint checkpoint
where where
thread = NamedThread thisThread checkpoint = do
checkpoint = do file <- liftAnnex $ fromRepo gitAnnexDaemonStatusFile
status <- getDaemonStatus dstatus liftIO . writeDaemonStatusFile file =<< daemonStatus
file <- runThreadState st $ fromRepo gitAnnexDaemonStatusFile
writeDaemonStatusFile file status

View file

@ -25,7 +25,7 @@ thisThread = "Merger"
{- This thread watches for changes to .git/refs/, and handles incoming {- This thread watches for changes to .git/refs/, and handles incoming
- pushes. -} - pushes. -}
mergeThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> BranchChangeHandle -> NamedThread mergeThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> BranchChangeHandle -> NamedThread
mergeThread st dstatus transferqueue branchchange = thread $ do mergeThread st dstatus transferqueue branchchange = thread $ liftIO $ do
g <- runThreadState st gitRepo g <- runThreadState st gitRepo
let dir = Git.localGitDir g </> "refs" let dir = Git.localGitDir g </> "refs"
createDirectoryIfMissing True dir createDirectoryIfMissing True dir
@ -35,7 +35,7 @@ mergeThread st dstatus transferqueue branchchange = thread $ do
, errHook = hook onErr , errHook = hook onErr
} }
void $ watchDir dir (const False) hooks id void $ watchDir dir (const False) hooks id
debug thisThread ["watching", dir] brokendebug thisThread ["watching", dir]
where where
thread = NamedThread thisThread thread = NamedThread thisThread
@ -81,7 +81,7 @@ onAdd st dstatus transferqueue branchchange file _
changedbranch = fileToBranch file changedbranch = fileToBranch file
mergecurrent (Just current) mergecurrent (Just current)
| equivBranches changedbranch current = do | equivBranches changedbranch current = do
liftIO $ debug thisThread liftIO $ brokendebug thisThread
[ "merging" [ "merging"
, show changedbranch , show changedbranch
, "into" , "into"

View file

@ -40,7 +40,7 @@ thisThread :: ThreadName
thisThread = "MountWatcher" thisThread = "MountWatcher"
mountWatcherThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> NamedThread mountWatcherThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> NamedThread
mountWatcherThread st handle scanremotes pushnotifier = thread $ mountWatcherThread st handle scanremotes pushnotifier = thread $ liftIO $
#if WITH_DBUS #if WITH_DBUS
dbusThread st handle scanremotes pushnotifier dbusThread st handle scanremotes pushnotifier
#else #else
@ -93,7 +93,7 @@ checkMountMonitor client = do
case running of case running of
[] -> startOneService client startableservices [] -> startOneService client startableservices
(service:_) -> do (service:_) -> do
debug thisThread [ "Using running DBUS service" brokendebug thisThread [ "Using running DBUS service"
, service , service
, "to monitor mount events." , "to monitor mount events."
] ]
@ -111,7 +111,7 @@ startOneService client (x:xs) = do
[toVariant x, toVariant (0 :: Word32)] [toVariant x, toVariant (0 :: Word32)]
ifM (elem x <$> listServiceNames client) ifM (elem x <$> listServiceNames client)
( do ( do
debug thisThread [ "Started DBUS service" brokendebug thisThread [ "Started DBUS service"
, x , x
, "to monitor mount events." , "to monitor mount events."
] ]
@ -160,7 +160,7 @@ handleMounts st dstatus scanremotes pushnotifier wasmounted nowmounted =
handleMount :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> FilePath -> IO () handleMount :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> FilePath -> IO ()
handleMount st dstatus scanremotes pushnotifier dir = do handleMount st dstatus scanremotes pushnotifier dir = do
debug thisThread ["detected mount of", dir] brokendebug thisThread ["detected mount of", dir]
reconnectRemotes thisThread st dstatus scanremotes (Just pushnotifier) reconnectRemotes thisThread st dstatus scanremotes (Just pushnotifier)
=<< filter (Git.repoIsLocal . Remote.repo) =<< filter (Git.repoIsLocal . Remote.repo)
<$> remotesUnder st dstatus dir <$> remotesUnder st dstatus dir

View file

@ -11,9 +11,6 @@
module Assistant.Threads.NetWatcher where module Assistant.Threads.NetWatcher where
import Assistant.Common import Assistant.Common
import Assistant.ThreadedMonad
import Assistant.DaemonStatus
import Assistant.ScanRemotes
import Assistant.Sync import Assistant.Sync
import Assistant.Pushes import Assistant.Pushes
import Utility.ThreadScheduler import Utility.ThreadScheduler
@ -29,72 +26,67 @@ import Data.Word (Word32)
#warning Building without dbus support; will poll for network connection changes #warning Building without dbus support; will poll for network connection changes
#endif #endif
thisThread :: ThreadName netWatcherThread :: NamedThread
thisThread = "NetWatcher"
netWatcherThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> NamedThread
#if WITH_DBUS #if WITH_DBUS
netWatcherThread st dstatus scanremotes pushnotifier = thread $ netWatcherThread = thread dbusThread
dbusThread st dstatus scanremotes pushnotifier
#else #else
netWatcherThread _ _ _ _ = thread noop netWatcherThread = thread noop
#endif #endif
where where
thread = NamedThread thisThread thread = NamedThread "NetWatcher"
{- This is a fallback for when dbus cannot be used to detect {- This is a fallback for when dbus cannot be used to detect
- network connection changes, but it also ensures that - network connection changes, but it also ensures that
- any networked remotes that may have not been routable for a - any networked remotes that may have not been routable for a
- while (despite the local network staying up), are synced with - while (despite the local network staying up), are synced with
- periodically. -} - periodically. -}
netWatcherFallbackThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> NamedThread netWatcherFallbackThread :: NamedThread
netWatcherFallbackThread st dstatus scanremotes pushnotifier = thread $ netWatcherFallbackThread = NamedThread "NetWatcherFallback" $
runEvery (Seconds 3600) $ runEvery (Seconds 3600) <~> handleConnection
handleConnection st dstatus scanremotes pushnotifier
where
thread = NamedThread thisThread
#if WITH_DBUS #if WITH_DBUS
dbusThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> IO () dbusThread :: Assistant ()
dbusThread st dstatus scanremotes pushnotifier = dbusThread = do
persistentClient getSystemAddress () onerr go handleerr <- asIO2 onerr
where runclient <- asIO go
go client = ifM (checkNetMonitor client) liftIO $ persistentClient getSystemAddress () handleerr runclient
( do where
listenNMConnections client handleconn go client = ifM (checkNetMonitor client)
listenWicdConnections client handleconn ( do
, do listenNMConnections client <~> handleconn
runThreadState st $ listenWicdConnections client <~> handleconn
warning "No known network monitor available through dbus; falling back to polling" , do
) liftAnnex $
handleconn = do warning "No known network monitor available through dbus; falling back to polling"
debug thisThread ["detected network connection"] )
notifyRestart pushnotifier handleconn = do
handleConnection st dstatus scanremotes pushnotifier debug ["detected network connection"]
onerr e _ = do notifyRestart <<~ pushNotifier
runThreadState st $ handleConnection
warning $ "lost dbus connection; falling back to polling (" ++ show e ++ ")" onerr e _ = do
{- Wait, in hope that dbus will come back -} liftAnnex $
threadDelaySeconds (Seconds 60) warning $ "lost dbus connection; falling back to polling (" ++ show e ++ ")"
{- Wait, in hope that dbus will come back -}
liftIO $ threadDelaySeconds (Seconds 60)
{- Examine the list of services connected to dbus, to see if there {- Examine the list of services connected to dbus, to see if there
- are any we can use to monitor network connections. -} - are any we can use to monitor network connections. -}
checkNetMonitor :: Client -> IO Bool checkNetMonitor :: Client -> Assistant Bool
checkNetMonitor client = do checkNetMonitor client = do
running <- filter (`elem` [networkmanager, wicd]) running <- liftIO $ filter (`elem` [networkmanager, wicd])
<$> listServiceNames client <$> listServiceNames client
case running of case running of
[] -> return False [] -> return False
(service:_) -> do (service:_) -> do
debug thisThread [ "Using running DBUS service" debug [ "Using running DBUS service"
, service , service
, "to monitor network connection events." , "to monitor network connection events."
] ]
return True return True
where where
networkmanager = "org.freedesktop.NetworkManager" networkmanager = "org.freedesktop.NetworkManager"
wicd = "org.wicd.daemon" wicd = "org.wicd.daemon"
{- Listens for new NetworkManager connections. -} {- Listens for new NetworkManager connections. -}
listenNMConnections :: Client -> IO () -> IO () listenNMConnections :: Client -> IO () -> IO ()
@ -102,18 +94,18 @@ listenNMConnections client callback =
listen client matcher $ \event -> listen client matcher $ \event ->
when (Just True == anyM activeconnection (signalBody event)) $ when (Just True == anyM activeconnection (signalBody event)) $
callback callback
where where
matcher = matchAny matcher = matchAny
{ matchInterface = Just "org.freedesktop.NetworkManager.Connection.Active" { matchInterface = Just "org.freedesktop.NetworkManager.Connection.Active"
, matchMember = Just "PropertiesChanged" , matchMember = Just "PropertiesChanged"
} }
nm_connection_activated = toVariant (2 :: Word32) nm_connection_activated = toVariant (2 :: Word32)
nm_state_key = toVariant ("State" :: String) nm_state_key = toVariant ("State" :: String)
activeconnection v = do activeconnection v = do
m <- fromVariant v m <- fromVariant v
vstate <- lookup nm_state_key $ dictionaryItems m vstate <- lookup nm_state_key $ dictionaryItems m
state <- fromVariant vstate state <- fromVariant vstate
return $ state == nm_connection_activated return $ state == nm_connection_activated
{- Listens for new Wicd connections. -} {- Listens for new Wicd connections. -}
listenWicdConnections :: Client -> IO () -> IO () listenWicdConnections :: Client -> IO () -> IO ()
@ -121,21 +113,23 @@ listenWicdConnections client callback =
listen client matcher $ \event -> listen client matcher $ \event ->
when (any (== wicd_success) (signalBody event)) $ when (any (== wicd_success) (signalBody event)) $
callback callback
where where
matcher = matchAny matcher = matchAny
{ matchInterface = Just "org.wicd.daemon" { matchInterface = Just "org.wicd.daemon"
, matchMember = Just "ConnectResultsSent" , matchMember = Just "ConnectResultsSent"
} }
wicd_success = toVariant ("success" :: String) wicd_success = toVariant ("success" :: String)
#endif #endif
handleConnection :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PushNotifier -> IO () handleConnection :: Assistant ()
handleConnection st dstatus scanremotes pushnotifier = handleConnection = do
reconnectRemotes thisThread st dstatus scanremotes (Just pushnotifier) d <- getAssistant id
=<< networkRemotes st liftIO . reconnectRemotes (threadName d) (threadState d)
(daemonStatusHandle d) (scanRemoteMap d) (Just $ pushNotifier d)
=<< networkRemotes
{- Finds network remotes. -} {- Finds network remotes. -}
networkRemotes :: ThreadState -> IO [Remote] networkRemotes :: Assistant [Remote]
networkRemotes st = runThreadState st $ networkRemotes = liftAnnex $
filter (isNothing . Remote.localpath) <$> remoteList filter (isNothing . Remote.localpath) <$> remoteList

View file

@ -28,7 +28,7 @@ thisThread :: ThreadName
thisThread = "PairListener" thisThread = "PairListener"
pairListenerThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> UrlRenderer -> NamedThread pairListenerThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> UrlRenderer -> NamedThread
pairListenerThread st dstatus scanremotes urlrenderer = thread $ withSocketsDo $ pairListenerThread st dstatus scanremotes urlrenderer = thread $ liftIO $ withSocketsDo $
runEvery (Seconds 1) $ void $ tryIO $ do runEvery (Seconds 1) $ void $ tryIO $ do
sock <- getsock sock <- getsock
go sock [] [] go sock [] []

View file

@ -35,7 +35,7 @@ controllerThread pushnotifier a = forever $ do
killThread tid killThread tid
pushNotifierThread :: ThreadState -> DaemonStatusHandle -> PushNotifier -> NamedThread pushNotifierThread :: ThreadState -> DaemonStatusHandle -> PushNotifier -> NamedThread
pushNotifierThread st dstatus pushnotifier = NamedThread thisThread $ pushNotifierThread st dstatus pushnotifier = NamedThread thisThread $ liftIO $
controllerThread pushnotifier $ do controllerThread pushnotifier $ do
v <- runThreadState st $ getXMPPCreds v <- runThreadState st $ getXMPPCreds
case v of case v of
@ -45,7 +45,7 @@ pushNotifierThread st dstatus pushnotifier = NamedThread thisThread $
loop c starttime = do loop c starttime = do
void $ connectXMPP c $ \jid -> do void $ connectXMPP c $ \jid -> do
fulljid <- bindJID jid fulljid <- bindJID jid
liftIO $ debug thisThread ["XMPP connected", show fulljid] liftIO $ brokendebug thisThread ["XMPP connected", show fulljid]
putStanza $ gitAnnexPresence gitAnnexSignature putStanza $ gitAnnexPresence gitAnnexSignature
s <- getSession s <- getSession
_ <- liftIO $ forkIO $ void $ runXMPP s $ _ <- liftIO $ forkIO $ void $ runXMPP s $
@ -54,10 +54,10 @@ pushNotifierThread st dstatus pushnotifier = NamedThread thisThread $
now <- getCurrentTime now <- getCurrentTime
if diffUTCTime now starttime > 300 if diffUTCTime now starttime > 300
then do then do
debug thisThread ["XMPP connection lost; reconnecting"] brokendebug thisThread ["XMPP connection lost; reconnecting"]
loop c now loop c now
else do else do
debug thisThread ["XMPP connection failed; will retry"] brokendebug thisThread ["XMPP connection failed; will retry"]
threadDelaySeconds (Seconds 300) threadDelaySeconds (Seconds 300)
loop c =<< getCurrentTime loop c =<< getCurrentTime
@ -67,7 +67,7 @@ pushNotifierThread st dstatus pushnotifier = NamedThread thisThread $
receivenotifications = forever $ do receivenotifications = forever $ do
s <- getStanza s <- getStanza
liftIO $ debug thisThread ["received XMPP:", show s] liftIO $ brokendebug thisThread ["received XMPP:", show s]
case s of case s of
ReceivedPresence p@(Presence { presenceType = PresenceAvailable }) -> ReceivedPresence p@(Presence { presenceType = PresenceAvailable }) ->
liftIO $ pull st dstatus $ liftIO $ pull st dstatus $
@ -93,7 +93,7 @@ pull :: ThreadState -> DaemonStatusHandle -> [UUID] -> IO ()
pull _ _ [] = noop pull _ _ [] = noop
pull st dstatus us = do pull st dstatus us = do
rs <- filter matching . syncRemotes <$> getDaemonStatus dstatus rs <- filter matching . syncRemotes <$> getDaemonStatus dstatus
debug thisThread $ "push notification for" : brokendebug thisThread $ "push notification for" :
map (fromUUID . Remote.uuid ) rs map (fromUUID . Remote.uuid ) rs
pullone rs =<< runThreadState st (inRepo Git.Branch.current) pullone rs =<< runThreadState st (inRepo Git.Branch.current)
where where

View file

@ -25,12 +25,12 @@ thisThread = "Pusher"
{- This thread retries pushes that failed before. -} {- This thread retries pushes that failed before. -}
pushRetryThread :: ThreadState -> DaemonStatusHandle -> FailedPushMap -> PushNotifier -> NamedThread pushRetryThread :: ThreadState -> DaemonStatusHandle -> FailedPushMap -> PushNotifier -> NamedThread
pushRetryThread st dstatus pushmap pushnotifier = thread $ runEvery (Seconds halfhour) $ do pushRetryThread st dstatus pushmap pushnotifier = thread $ liftIO $ runEvery (Seconds halfhour) $ do
-- We already waited half an hour, now wait until there are failed -- We already waited half an hour, now wait until there are failed
-- pushes to retry. -- pushes to retry.
topush <- getFailedPushesBefore pushmap (fromIntegral halfhour) topush <- getFailedPushesBefore pushmap (fromIntegral halfhour)
unless (null topush) $ do unless (null topush) $ do
debug thisThread brokendebug thisThread
[ "retrying" [ "retrying"
, show (length topush) , show (length topush)
, "failed pushes" , "failed pushes"
@ -44,7 +44,7 @@ pushRetryThread st dstatus pushmap pushnotifier = thread $ runEvery (Seconds hal
{- This thread pushes git commits out to remotes soon after they are made. -} {- This thread pushes git commits out to remotes soon after they are made. -}
pushThread :: ThreadState -> DaemonStatusHandle -> CommitChan -> FailedPushMap -> PushNotifier -> NamedThread pushThread :: ThreadState -> DaemonStatusHandle -> CommitChan -> FailedPushMap -> PushNotifier -> NamedThread
pushThread st dstatus commitchan pushmap pushnotifier = thread $ runEvery (Seconds 2) $ do pushThread st dstatus commitchan pushmap pushnotifier = thread $ liftIO $ runEvery (Seconds 2) $ do
-- We already waited two seconds as a simple rate limiter. -- We already waited two seconds as a simple rate limiter.
-- Next, wait until at least one commit has been made -- Next, wait until at least one commit has been made
commits <- getCommits commitchan commits <- getCommits commitchan
@ -58,7 +58,7 @@ pushThread st dstatus commitchan pushmap pushnotifier = thread $ runEvery (Secon
void $ alertWhile dstatus (pushAlert remotes) $ void $ alertWhile dstatus (pushAlert remotes) $
pushToRemotes thisThread now st (Just pushnotifier) (Just pushmap) remotes pushToRemotes thisThread now st (Just pushnotifier) (Just pushmap) remotes
else do else do
debug thisThread brokendebug thisThread
[ "delaying push of" [ "delaying push of"
, show (length commits) , show (length commits)
, "commits" , "commits"

View file

@ -11,60 +11,56 @@ module Assistant.Threads.SanityChecker (
import Assistant.Common import Assistant.Common
import Assistant.DaemonStatus import Assistant.DaemonStatus
import Assistant.ThreadedMonad
import Assistant.Changes
import Assistant.Alert import Assistant.Alert
import Assistant.TransferQueue
import qualified Git.LsFiles import qualified Git.LsFiles
import Utility.ThreadScheduler import Utility.ThreadScheduler
import qualified Assistant.Threads.Watcher as Watcher import qualified Assistant.Threads.Watcher as Watcher
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
thisThread :: ThreadName
thisThread = "SanityChecker"
{- This thread wakes up occasionally to make sure the tree is in good shape. -} {- This thread wakes up occasionally to make sure the tree is in good shape. -}
sanityCheckerThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> ChangeChan -> NamedThread sanityCheckerThread :: NamedThread
sanityCheckerThread st dstatus transferqueue changechan = thread $ forever $ do sanityCheckerThread = NamedThread "SanityChecker" $ forever $ do
waitForNextCheck dstatus waitForNextCheck
debug thisThread ["starting sanity check"] debug ["starting sanity check"]
void $ alertWhile dstatus sanityCheckAlert go dstatus <- getAssistant daemonStatusHandle
void $ alertWhile dstatus sanityCheckAlert <~> go
debug thisThread ["sanity check complete"] debug ["sanity check complete"]
where where
thread = NamedThread thisThread go = do
go = do dstatus <- getAssistant daemonStatusHandle
modifyDaemonStatus_ dstatus $ \s -> s liftIO $ modifyDaemonStatus_ dstatus $ \s -> s
{ sanityCheckRunning = True } { sanityCheckRunning = True }
now <- getPOSIXTime -- before check started now <- liftIO $ getPOSIXTime -- before check started
r <- catchIO (check st dstatus transferqueue changechan) r <- either showerr return =<< tryIO <~> check
$ \e -> do
runThreadState st $ warning $ show e
return False
modifyDaemonStatus_ dstatus $ \s -> s liftIO $ modifyDaemonStatus_ dstatus $ \s -> s
{ sanityCheckRunning = False { sanityCheckRunning = False
, lastSanityCheck = Just now , lastSanityCheck = Just now
} }
return r return r
showerr e = do
liftAnnex $ warning $ show e
return False
{- Only run one check per day, from the time of the last check. -} {- Only run one check per day, from the time of the last check. -}
waitForNextCheck :: DaemonStatusHandle -> IO () waitForNextCheck :: Assistant ()
waitForNextCheck dstatus = do waitForNextCheck = do
v <- lastSanityCheck <$> getDaemonStatus dstatus v <- lastSanityCheck <$> daemonStatus
now <- getPOSIXTime now <- liftIO getPOSIXTime
threadDelaySeconds $ Seconds $ calcdelay now v liftIO $ threadDelaySeconds $ Seconds $ calcdelay now v
where where
calcdelay _ Nothing = oneDay calcdelay _ Nothing = oneDay
calcdelay now (Just lastcheck) calcdelay now (Just lastcheck)
| lastcheck < now = max oneDay $ | lastcheck < now = max oneDay $
oneDay - truncate (now - lastcheck) oneDay - truncate (now - lastcheck)
| otherwise = oneDay | otherwise = oneDay
oneDay :: Int oneDay :: Int
oneDay = 24 * 60 * 60 oneDay = 24 * 60 * 60
@ -72,29 +68,31 @@ oneDay = 24 * 60 * 60
{- It's important to stay out of the Annex monad as much as possible while {- It's important to stay out of the Annex monad as much as possible while
- running potentially expensive parts of this check, since remaining in it - running potentially expensive parts of this check, since remaining in it
- will block the watcher. -} - will block the watcher. -}
check :: ThreadState -> DaemonStatusHandle -> TransferQueue -> ChangeChan -> IO Bool check :: Assistant Bool
check st dstatus transferqueue changechan = do check = do
g <- runThreadState st gitRepo g <- liftAnnex gitRepo
-- Find old unstaged symlinks, and add them to git. -- Find old unstaged symlinks, and add them to git.
(unstaged, cleanup) <- Git.LsFiles.notInRepo False ["."] g (unstaged, cleanup) <- liftIO $ Git.LsFiles.notInRepo False ["."] g
now <- getPOSIXTime now <- liftIO $ getPOSIXTime
forM_ unstaged $ \file -> do forM_ unstaged $ \file -> do
ms <- catchMaybeIO $ getSymbolicLinkStatus file ms <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus file
case ms of case ms of
Just s | toonew (statusChangeTime s) now -> noop Just s | toonew (statusChangeTime s) now -> noop
| isSymbolicLink s -> | isSymbolicLink s -> addsymlink file ms
addsymlink file ms
_ -> noop _ -> noop
void cleanup liftIO $ void cleanup
return True return True
where where
toonew timestamp now = now < (realToFrac (timestamp + slop) :: POSIXTime) toonew timestamp now = now < (realToFrac (timestamp + slop) :: POSIXTime)
slop = fromIntegral tenMinutes slop = fromIntegral tenMinutes
insanity msg = do insanity msg = do
runThreadState st $ warning msg liftAnnex $ warning msg
void $ addAlert dstatus $ sanityCheckFixAlert msg dstatus <- getAssistant daemonStatusHandle
addsymlink file s = do liftIO $ void $ addAlert dstatus $ sanityCheckFixAlert msg
Watcher.runHandler thisThread st dstatus addsymlink file s = do
transferqueue changechan d <- getAssistant id
Watcher.onAddSymlink file s liftIO $ Watcher.runHandler (threadName d)
insanity $ "found unstaged symlink: " ++ file (threadState d) (daemonStatusHandle d)
(transferQueue d) (changeChan d)
Watcher.onAddSymlink file s
insanity $ "found unstaged symlink: " ++ file

View file

@ -8,7 +8,6 @@
module Assistant.Threads.TransferPoller where module Assistant.Threads.TransferPoller where
import Assistant.Common import Assistant.Common
import Assistant.ThreadedMonad
import Assistant.DaemonStatus import Assistant.DaemonStatus
import Logs.Transfer import Logs.Transfer
import Utility.NotificationBroadcaster import Utility.NotificationBroadcaster
@ -17,46 +16,42 @@ import qualified Assistant.Threads.TransferWatcher as TransferWatcher
import Control.Concurrent import Control.Concurrent
import qualified Data.Map as M import qualified Data.Map as M
thisThread :: ThreadName
thisThread = "TransferPoller"
{- This thread polls the status of ongoing transfers, determining how much {- This thread polls the status of ongoing transfers, determining how much
- of each transfer is complete. -} - of each transfer is complete. -}
transferPollerThread :: ThreadState -> DaemonStatusHandle -> NamedThread transferPollerThread :: NamedThread
transferPollerThread st dstatus = thread $ do transferPollerThread = NamedThread "TransferPoller" $ do
g <- runThreadState st gitRepo g <- liftAnnex gitRepo
tn <- newNotificationHandle =<< tn <- liftIO . newNotificationHandle =<<
transferNotifier <$> getDaemonStatus dstatus transferNotifier <$> daemonStatus
forever $ do forever $ do
threadDelay 500000 -- 0.5 seconds liftIO $ threadDelay 500000 -- 0.5 seconds
ts <- currentTransfers <$> getDaemonStatus dstatus ts <- currentTransfers <$> daemonStatus
if M.null ts if M.null ts
then waitNotification tn -- block until transfers running -- block until transfers running
then liftIO $ waitNotification tn
else mapM_ (poll g) $ M.toList ts else mapM_ (poll g) $ M.toList ts
where where
thread = NamedThread thisThread poll g (t, info)
poll g (t, info) {- Downloads are polled by checking the size of the
{- Downloads are polled by checking the size of the - temp file being used for the transfer. -}
- temp file being used for the transfer. -} | transferDirection t == Download = do
| transferDirection t == Download = do let f = gitAnnexTmpLocation (transferKey t) g
let f = gitAnnexTmpLocation (transferKey t) g sz <- liftIO $ catchMaybeIO $
sz <- catchMaybeIO $ fromIntegral . fileSize <$> getFileStatus f
fromIntegral . fileSize newsize t info sz
<$> getFileStatus f {- Uploads don't need to be polled for when the TransferWatcher
newsize t info sz - thread can track file modifications. -}
{- Uploads don't need to be polled for when the | TransferWatcher.watchesTransferSize = noop
- TransferWatcher thread can track file {- Otherwise, this code polls the upload progress
- modifications. -} - by reading the transfer info file. -}
| TransferWatcher.watchesTransferSize = noop | otherwise = do
{- Otherwise, this code polls the upload progress let f = transferFile t g
- by reading the transfer info file. -} mi <- liftIO $ catchDefaultIO Nothing $
| otherwise = do readTransferInfoFile Nothing f
let f = transferFile t g maybe noop (newsize t info . bytesComplete) mi
mi <- catchDefaultIO Nothing $
readTransferInfoFile Nothing f newsize t info sz
maybe noop (newsize t info . bytesComplete) mi | bytesComplete info /= sz && isJust sz =
newsize t info sz alterTransferInfo t (\i -> i { bytesComplete = sz })
| bytesComplete info /= sz && isJust sz = <<~ daemonStatusHandle
alterTransferInfo dstatus t $ | otherwise = noop
\i -> i { bytesComplete = sz }
| otherwise = noop

View file

@ -34,7 +34,7 @@ thisThread = "TransferScanner"
- that need to be made, to keep data in sync. - that need to be made, to keep data in sync.
-} -}
transferScannerThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> TransferQueue -> NamedThread transferScannerThread :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> TransferQueue -> NamedThread
transferScannerThread st dstatus scanremotes transferqueue = thread $ do transferScannerThread st dstatus scanremotes transferqueue = thread $ liftIO $ do
startupScan startupScan
go S.empty go S.empty
where where
@ -100,7 +100,7 @@ failedTransferScan st dstatus transferqueue r = do
-} -}
expensiveScan :: ThreadState -> DaemonStatusHandle -> TransferQueue -> [Remote] -> IO () expensiveScan :: ThreadState -> DaemonStatusHandle -> TransferQueue -> [Remote] -> IO ()
expensiveScan st dstatus transferqueue rs = unless onlyweb $ do expensiveScan st dstatus transferqueue rs = unless onlyweb $ do
liftIO $ debug thisThread ["starting scan of", show visiblers] brokendebug thisThread ["starting scan of", show visiblers]
void $ alertWhile dstatus (scanAlert visiblers) $ do void $ alertWhile dstatus (scanAlert visiblers) $ do
g <- runThreadState st gitRepo g <- runThreadState st gitRepo
(files, cleanup) <- LsFiles.inRepo [] g (files, cleanup) <- LsFiles.inRepo [] g
@ -110,13 +110,13 @@ expensiveScan st dstatus transferqueue rs = unless onlyweb $ do
mapM_ (enqueue f) ts mapM_ (enqueue f) ts
void cleanup void cleanup
return True return True
liftIO $ debug thisThread ["finished scan of", show visiblers] brokendebug thisThread ["finished scan of", show visiblers]
where where
onlyweb = all (== webUUID) $ map Remote.uuid rs onlyweb = all (== webUUID) $ map Remote.uuid rs
visiblers = let rs' = filter (not . Remote.readonly) rs visiblers = let rs' = filter (not . Remote.readonly) rs
in if null rs' then rs else rs' in if null rs' then rs else rs'
enqueue f (r, t) = do enqueue f (r, t) = do
debug thisThread ["queuing", show t] brokendebug thisThread ["queuing", show t]
queueTransferWhenSmall transferqueue dstatus (Just f) t r queueTransferWhenSmall transferqueue dstatus (Just f) t r
findtransfers f (key, _) = do findtransfers f (key, _) = do
locs <- loggedLocations key locs <- loggedLocations key

View file

@ -26,7 +26,7 @@ thisThread = "TransferWatcher"
{- This thread watches for changes to the gitAnnexTransferDir, {- This thread watches for changes to the gitAnnexTransferDir,
- and updates the DaemonStatus's map of ongoing transfers. -} - and updates the DaemonStatus's map of ongoing transfers. -}
transferWatcherThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> NamedThread transferWatcherThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> NamedThread
transferWatcherThread st dstatus transferqueue = thread $ do transferWatcherThread st dstatus transferqueue = thread $ liftIO $ do
g <- runThreadState st gitRepo g <- runThreadState st gitRepo
let dir = gitAnnexTransferDir g let dir = gitAnnexTransferDir g
createDirectoryIfMissing True dir createDirectoryIfMissing True dir
@ -38,7 +38,7 @@ transferWatcherThread st dstatus transferqueue = thread $ do
, errHook = hook onErr , errHook = hook onErr
} }
void $ watchDir dir (const False) hooks id void $ watchDir dir (const False) hooks id
debug thisThread ["watching for transfers"] brokendebug thisThread ["watching for transfers"]
where where
thread = NamedThread thisThread thread = NamedThread thisThread
@ -66,7 +66,7 @@ onAdd st dstatus _ file _ = case parseTransferFile file of
where where
go _ Nothing = noop -- transfer already finished go _ Nothing = noop -- transfer already finished
go t (Just info) = do go t (Just info) = do
debug thisThread brokendebug thisThread
[ "transfer starting:" [ "transfer starting:"
, show t , show t
] ]
@ -87,8 +87,9 @@ onModify _ dstatus _ file _ = do
Just t -> go t =<< readTransferInfoFile Nothing file Just t -> go t =<< readTransferInfoFile Nothing file
where where
go _ Nothing = noop go _ Nothing = noop
go t (Just newinfo) = alterTransferInfo dstatus t $ \info -> go t (Just newinfo) = alterTransferInfo t
info { bytesComplete = bytesComplete newinfo } (\i -> i { bytesComplete = bytesComplete newinfo })
dstatus
{- This thread can only watch transfer sizes when the DirWatcher supports {- This thread can only watch transfer sizes when the DirWatcher supports
- tracking modificatons to files. -} - tracking modificatons to files. -}
@ -100,7 +101,7 @@ onDel :: Handler
onDel st dstatus transferqueue file _ = case parseTransferFile file of onDel st dstatus transferqueue file _ = case parseTransferFile file of
Nothing -> noop Nothing -> noop
Just t -> do Just t -> do
debug thisThread brokendebug thisThread
[ "transfer finishing:" [ "transfer finishing:"
, show t , show t
] ]

View file

@ -32,7 +32,7 @@ maxTransfers = 1
{- Dispatches transfers from the queue. -} {- Dispatches transfers from the queue. -}
transfererThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> TransferSlots -> CommitChan -> NamedThread transfererThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> TransferSlots -> CommitChan -> NamedThread
transfererThread st dstatus transferqueue slots commitchan = thread $ go =<< readProgramFile transfererThread st dstatus transferqueue slots commitchan = thread $ liftIO $ go =<< readProgramFile
where where
thread = NamedThread thisThread thread = NamedThread thisThread
go program = forever $ inTransferSlot dstatus slots $ go program = forever $ inTransferSlot dstatus slots $
@ -47,11 +47,11 @@ startTransfer :: ThreadState -> DaemonStatusHandle -> CommitChan -> FilePath ->
startTransfer st dstatus commitchan program t info = case (transferRemote info, associatedFile info) of startTransfer st dstatus commitchan program t info = case (transferRemote info, associatedFile info) of
(Just remote, Just file) -> ifM (runThreadState st $ shouldTransfer t info) (Just remote, Just file) -> ifM (runThreadState st $ shouldTransfer t info)
( do ( do
debug thisThread [ "Transferring:" , show t ] brokendebug thisThread [ "Transferring:" , show t ]
notifyTransfer dstatus notifyTransfer dstatus
return $ Just (t, info, transferprocess remote file) return $ Just (t, info, transferprocess remote file)
, do , do
debug thisThread [ "Skipping unnecessary transfer:" , show t ] brokendebug thisThread [ "Skipping unnecessary transfer:" , show t ]
void $ removeTransfer dstatus t void $ removeTransfer dstatus t
return Nothing return Nothing
) )

View file

@ -56,9 +56,9 @@ needLsof = error $ unlines
] ]
watchThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> ChangeChan -> NamedThread watchThread :: ThreadState -> DaemonStatusHandle -> TransferQueue -> ChangeChan -> NamedThread
watchThread st dstatus transferqueue changechan = NamedThread thisThread $ do watchThread st dstatus transferqueue changechan = NamedThread thisThread $ liftIO $ do
void $ watchDir "." ignored hooks startup void $ watchDir "." ignored hooks startup
debug thisThread [ "watching", "."] brokendebug thisThread [ "watching", "."]
where where
startup = startupScan st dstatus startup = startupScan st dstatus
hook a = Just $ runHandler thisThread st dstatus transferqueue changechan a hook a = Just $ runHandler thisThread st dstatus transferqueue changechan a
@ -132,7 +132,7 @@ onAddSymlink threadname file filestatus dstatus transferqueue = go =<< Backend.l
checkcontent key s checkcontent key s
ensurestaged link s ensurestaged link s
, do , do
liftIO $ debug threadname ["fix symlink", file] liftIO $ brokendebug threadname ["fix symlink", file]
liftIO $ removeFile file liftIO $ removeFile file
liftIO $ createSymbolicLink link file liftIO $ createSymbolicLink link file
checkcontent key =<< liftIO (getDaemonStatus dstatus) checkcontent key =<< liftIO (getDaemonStatus dstatus)
@ -162,7 +162,7 @@ onAddSymlink threadname file filestatus dstatus transferqueue = go =<< Backend.l
{- For speed, tries to reuse the existing blob for symlink target. -} {- For speed, tries to reuse the existing blob for symlink target. -}
addlink link = do addlink link = do
liftIO $ debug threadname ["add symlink", file] liftIO $ brokendebug threadname ["add symlink", file]
v <- catObjectDetails $ Ref $ ':':file v <- catObjectDetails $ Ref $ ':':file
case v of case v of
Just (currlink, sha) Just (currlink, sha)
@ -187,7 +187,7 @@ onAddSymlink threadname file filestatus dstatus transferqueue = go =<< Backend.l
onDel :: Handler onDel :: Handler
onDel threadname file _ _dstatus _ = do onDel threadname file _ _dstatus _ = do
liftIO $ debug threadname ["file deleted", file] liftIO $ brokendebug threadname ["file deleted", file]
Annex.Queue.addUpdateIndex =<< Annex.Queue.addUpdateIndex =<<
inRepo (Git.UpdateIndex.unstageFile file) inRepo (Git.UpdateIndex.unstageFile file)
madeChange file RmChange madeChange file RmChange
@ -201,7 +201,7 @@ onDel threadname file _ _dstatus _ = do
- just as good. -} - just as good. -}
onDelDir :: Handler onDelDir :: Handler
onDelDir threadname dir _ _dstatus _ = do onDelDir threadname dir _ _dstatus _ = do
liftIO $ debug threadname ["directory deleted", dir] liftIO $ brokendebug threadname ["directory deleted", dir]
Annex.Queue.addCommand "rm" Annex.Queue.addCommand "rm"
[Params "--quiet -r --cached --ignore-unmatch --"] [dir] [Params "--quiet -r --cached --ignore-unmatch --"] [dir]
madeChange dir RmDirChange madeChange dir RmDirChange

View file

@ -52,7 +52,7 @@ webAppThread
-> Maybe (IO String) -> Maybe (IO String)
-> Maybe (Url -> FilePath -> IO ()) -> Maybe (Url -> FilePath -> IO ())
-> NamedThread -> NamedThread
webAppThread assistantdata urlrenderer noannex postfirstrun onstartup = thread $ do webAppThread assistantdata urlrenderer noannex postfirstrun onstartup = thread $ liftIO $ do
webapp <- WebApp webapp <- WebApp
<$> pure assistantdata <$> pure assistantdata
<*> (pack <$> genRandomToken) <*> (pack <$> genRandomToken)
@ -83,7 +83,7 @@ webAppThread assistantdata urlrenderer noannex postfirstrun onstartup = thread $
(relHome =<< absPath (relHome =<< absPath
=<< runThreadState (threadState assistantdata) (fromRepo repoPath)) =<< runThreadState (threadState assistantdata) (fromRepo repoPath))
go port webapp htmlshim urlfile = do go port webapp htmlshim urlfile = do
debug thisThread ["running on port", show port] brokendebug thisThread ["running on port", show port]
let url = myUrl webapp port let url = myUrl webapp port
maybe noop (`writeFile` url) urlfile maybe noop (`writeFile` url) urlfile
writeHtmlShim url htmlshim writeHtmlShim url htmlshim

View file

@ -76,7 +76,7 @@ getAssistantY :: forall sub a. (AssistantData -> a) -> GHandler sub WebApp a
getAssistantY f = f <$> (assistantData <$> getYesod) getAssistantY f = f <$> (assistantData <$> getYesod)
getDaemonStatusY :: forall sub. GHandler sub WebApp DaemonStatus getDaemonStatusY :: forall sub. GHandler sub WebApp DaemonStatus
getDaemonStatusY = liftIO . getDaemonStatus =<< getAssistantY daemonStatus getDaemonStatusY = liftIO . getDaemonStatus =<< getAssistantY daemonStatusHandle
getWebAppState :: forall sub. GHandler sub WebApp WebAppState getWebAppState :: forall sub. GHandler sub WebApp WebAppState
getWebAppState = liftIO . atomically . readTMVar =<< webAppState <$> getYesod getWebAppState = liftIO . atomically . readTMVar =<< webAppState <$> getYesod

View file

@ -69,7 +69,7 @@ setRepoConfig uuid mremote oldc newc = do
when (repoSyncable oldc /= repoSyncable newc) $ when (repoSyncable oldc /= repoSyncable newc) $
changeSyncable mremote (repoSyncable newc) changeSyncable mremote (repoSyncable newc)
when (isJust mremote && repoName oldc /= repoName newc) $ do when (isJust mremote && repoName oldc /= repoName newc) $ do
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
runAnnex undefined $ do runAnnex undefined $ do
name <- fromRepo $ uniqueRemoteName (T.unpack $ repoName newc) 0 name <- fromRepo $ uniqueRemoteName (T.unpack $ repoName newc) 0
inRepo $ Git.Command.run "remote" inRepo $ Git.Command.run "remote"

View file

@ -87,7 +87,7 @@ getInprogressPairR _ = noPairing
-} -}
startPairing :: PairStage -> IO () -> (AlertButton -> Alert) -> Maybe UUID -> Text -> Secret -> Widget startPairing :: PairStage -> IO () -> (AlertButton -> Alert) -> Maybe UUID -> Text -> Secret -> Widget
startPairing stage oncancel alert muuid displaysecret secret = do startPairing stage oncancel alert muuid displaysecret secret = do
dstatus <- lift $ getAssistantY daemonStatus dstatus <- lift $ getAssistantY daemonStatusHandle
urlrender <- lift getUrlRender urlrender <- lift getUrlRender
reldir <- fromJust . relDir <$> lift getYesod reldir <- fromJust . relDir <$> lift getYesod

View file

@ -124,5 +124,5 @@ makeS3Remote (S3Creds ak sk) name setup config = do
makeSpecialRemote name S3.remote config makeSpecialRemote name S3.remote config
return remotename return remotename
setup r setup r
liftIO $ syncNewRemote st (daemonStatus d) (scanRemoteMap d) r liftIO $ syncNewRemote st (daemonStatusHandle d) (scanRemoteMap d) r
redirect $ EditNewCloudRepositoryR $ Remote.uuid r redirect $ EditNewCloudRepositoryR $ Remote.uuid r

View file

@ -286,7 +286,7 @@ makeSshRepo forcersync setup sshdata = do
d <- getAssistantY id d <- getAssistantY id
r <- liftIO $ makeSshRemote r <- liftIO $ makeSshRemote
(threadState d) (threadState d)
(daemonStatus d) (daemonStatusHandle d)
(scanRemoteMap d) (scanRemoteMap d)
forcersync sshdata forcersync sshdata
setup r setup r

View file

@ -34,7 +34,7 @@ import qualified Data.Text as T
{- Displays an alert suggesting to configure XMPP, with a button. -} {- Displays an alert suggesting to configure XMPP, with a button. -}
xmppNeeded :: Handler () xmppNeeded :: Handler ()
xmppNeeded = whenM (isNothing <$> runAnnex Nothing getXMPPCreds) $ do xmppNeeded = whenM (isNothing <$> runAnnex Nothing getXMPPCreds) $ do
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
urlrender <- getUrlRender urlrender <- getUrlRender
void $ liftIO $ addAlert dstatus $ xmppNeededAlert $ AlertButton void $ liftIO $ addAlert dstatus $ xmppNeededAlert $ AlertButton
{ buttonLabel = "Configure a Jabber account" { buttonLabel = "Configure a Jabber account"

View file

@ -73,7 +73,7 @@ getSideBarR nid = do
{- Called by the client to close an alert. -} {- Called by the client to close an alert. -}
getCloseAlert :: AlertId -> Handler () getCloseAlert :: AlertId -> Handler ()
getCloseAlert i = do getCloseAlert i = do
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
liftIO $ removeAlert dstatus i liftIO $ removeAlert dstatus i
{- When an alert with a button is clicked on, the button takes us here. -} {- When an alert with a button is clicked on, the button takes us here. -}

View file

@ -37,7 +37,7 @@ changeSyncable (Just r) True = do
changeSyncable (Just r) False = do changeSyncable (Just r) False = do
changeSyncFlag r False changeSyncFlag r False
d <- getAssistantY id d <- getAssistantY id
let dstatus = daemonStatus d let dstatus = daemonStatusHandle d
let st = threadState d let st = threadState d
liftIO $ runThreadState st $ updateSyncRemotes dstatus liftIO $ runThreadState st $ updateSyncRemotes dstatus
{- Stop all transfers to or from this remote. {- Stop all transfers to or from this remote.
@ -65,7 +65,7 @@ syncRemote remote = do
d <- getAssistantY id d <- getAssistantY id
liftIO $ syncNewRemote liftIO $ syncNewRemote
(threadState d) (threadState d)
(daemonStatus d) (daemonStatusHandle d)
(scanRemoteMap d) (scanRemoteMap d)
remote remote
@ -74,7 +74,7 @@ pauseTransfer = cancelTransfer True
cancelTransfer :: Bool -> Transfer -> Handler () cancelTransfer :: Bool -> Transfer -> Handler ()
cancelTransfer pause t = do cancelTransfer pause t = do
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
tq <- getAssistantY transferQueue tq <- getAssistantY transferQueue
m <- getCurrentTransfers m <- getCurrentTransfers
liftIO $ do liftIO $ do
@ -94,8 +94,9 @@ cancelTransfer pause t = do
maybe noop killproc $ transferPid info maybe noop killproc $ transferPid info
if pause if pause
then void $ then void $
alterTransferInfo dstatus t $ \i -> i alterTransferInfo t
{ transferPaused = True } (\i -> i { transferPaused = True })
dstatus
else void $ else void $
removeTransfer dstatus t removeTransfer dstatus t
signalthread tid signalthread tid
@ -117,19 +118,20 @@ startTransfer t = do
where where
go info = maybe (start info) resume $ transferTid info go info = maybe (start info) resume $ transferTid info
startqueued = do startqueued = do
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
q <- getAssistantY transferQueue q <- getAssistantY transferQueue
is <- liftIO $ map snd <$> getMatchingTransfers q dstatus (== t) is <- liftIO $ map snd <$> getMatchingTransfers q dstatus (== t)
maybe noop start $ headMaybe is maybe noop start $ headMaybe is
resume tid = do resume tid = do
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
liftIO $ do liftIO $ do
alterTransferInfo dstatus t $ \i -> i alterTransferInfo t
{ transferPaused = False } (\i -> i { transferPaused = False })
dstatus
throwTo tid ResumeTransfer throwTo tid ResumeTransfer
start info = do start info = do
st <- getAssistantY threadState st <- getAssistantY threadState
dstatus <- getAssistantY daemonStatus dstatus <- getAssistantY daemonStatusHandle
slots <- getAssistantY transferSlots slots <- getAssistantY transferSlots
commitchan <- getAssistantY commitChan commitchan <- getAssistantY commitChan
liftIO $ inImmediateTransferSlot dstatus slots $ do liftIO $ inImmediateTransferSlot dstatus slots $ do