git-annex/Assistant/WebApp/DashBoard.hs

187 lines
5.9 KiB
Haskell
Raw Normal View History

2012-07-31 05:11:32 +00:00
{- git-annex assistant webapp dashboard
-
- Copyright 2012 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
{-# LANGUAGE CPP, TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings, RankNTypes #-}
2012-07-31 05:11:32 +00:00
module Assistant.WebApp.DashBoard where
import Assistant.Common
import Assistant.WebApp
import Assistant.WebApp.SideBar
import Assistant.WebApp.Notifications
import Assistant.WebApp.Configurators
import Assistant.DaemonStatus
import Assistant.TransferQueue
import Utility.NotificationBroadcaster
import Utility.Yesod
import Logs.Transfer
import Utility.Percentage
import Utility.DataUnits
import Types.Key
import qualified Remote
import qualified Git
2012-07-31 05:11:32 +00:00
import Yesod
import Text.Hamlet
import qualified Data.Map as M
import Control.Concurrent
import System.Posix.Signals (signalProcessGroup, sigTERM, sigKILL)
import System.Posix.Process (getProcessGroupIDOf)
2012-07-31 05:11:32 +00:00
{- A display of currently running and queued transfers.
-
- Or, if there have never been any this run, an intro display. -}
transfersDisplay :: Bool -> Widget
transfersDisplay warnNoScript = do
webapp <- lift getYesod
current <- lift $ runAnnex [] $
2012-07-31 05:11:32 +00:00
M.toList . currentTransfers
<$> liftIO (getDaemonStatus $ daemonStatus webapp)
queued <- liftIO $ getTransferQueue $ transferQueue webapp
let ident = "transfers"
autoUpdate ident NotifierTransfersR (10 :: Int) (10 :: Int)
2012-08-10 19:54:12 +00:00
let transfers = current ++ queued
2012-07-31 05:11:32 +00:00
if null transfers
then ifM (lift $ showIntro <$> getWebAppState)
( introDisplay ident
2012-07-31 05:24:49 +00:00
, $(widgetFile "dashboard/transfers")
2012-07-31 05:11:32 +00:00
)
2012-07-31 05:24:49 +00:00
else $(widgetFile "dashboard/transfers")
2012-07-31 05:11:32 +00:00
{- Called by client to get a display of currently in process transfers.
-
- Returns a div, which will be inserted into the calling page.
-
- Note that the head of the widget is not included, only its
- body is. To get the widget head content, the widget is also
- inserted onto the getHomeR page.
-}
getTransfersR :: NotificationId -> Handler RepHtml
getTransfersR nid = do
waitNotifier transferNotifier nid
page <- widgetToPageContent $ transfersDisplay False
hamletToRepHtml $ [hamlet|^{pageBody page}|]
{- The main dashboard. -}
dashboard :: Bool -> Widget
dashboard warnNoScript = do
2012-08-04 00:40:34 +00:00
sideBarDisplay
2012-07-31 05:11:32 +00:00
let content = transfersDisplay warnNoScript
2012-07-31 05:24:49 +00:00
$(widgetFile "dashboard/main")
2012-07-31 05:11:32 +00:00
getHomeR :: Handler RepHtml
2012-07-31 18:23:17 +00:00
getHomeR = ifM (inFirstRun)
( redirect ConfigR
, bootstrap (Just DashBoard) $ dashboard True
)
{- Same as HomeR, except no autorefresh at all (and no noscript warning). -}
getNoScriptR :: Handler RepHtml
2012-07-31 18:23:17 +00:00
getNoScriptR = bootstrap (Just DashBoard) $ dashboard False
2012-07-31 05:11:32 +00:00
{- Same as HomeR, except with autorefreshing via meta refresh. -}
getNoScriptAutoR :: Handler RepHtml
getNoScriptAutoR = bootstrap (Just DashBoard) $ do
2012-07-31 05:11:32 +00:00
let ident = NoScriptR
let delayseconds = 3 :: Int
let this = NoScriptAutoR
2012-07-31 05:24:49 +00:00
toWidgetHead $(hamletFile $ hamletTemplate "dashboard/metarefresh")
2012-07-31 05:11:32 +00:00
dashboard False
{- The javascript code does a post. -}
postFileBrowserR :: Handler ()
postFileBrowserR = void openFileBrowser
{- Used by non-javascript browsers, where clicking on the link actually
- opens this page, so we redirect back to the referrer. -}
getFileBrowserR :: Handler ()
getFileBrowserR = whenM openFileBrowser $ redirectBack
redirectBack :: Handler ()
redirectBack = do
clearUltDest
setUltDestReferer
redirectUltDest HomeR
{- Opens the system file browser on the repo, or, as a fallback,
- goes to a file:// url. Returns True if it's ok to redirect away
- from the page (ie, the system file browser was opened).
-
- Note that the command is opened using a different thread, to avoid
- blocking the response to the browser on it. -}
openFileBrowser :: Handler Bool
openFileBrowser = do
path <- runAnnex (error "no configured repository") $
fromRepo Git.repoPath
ifM (liftIO $ inPath cmd <&&> inPath cmd)
( do
void $ liftIO $ forkIO $ void $
boolSystem cmd [Param path]
return True
, do
clearUltDest
setUltDest $ "file://" ++ path
void $ redirectUltDest HomeR
return False
)
where
#if OSX
cmd = "open"
#else
cmd = "xdg-open"
#endif
{- Transfer controls. The GET is done in noscript mode and redirects back
- to the referring page. The POST is called by javascript. -}
getPauseTransferR :: Transfer -> Handler ()
getPauseTransferR t = pauseTransfer t >> redirectBack
postPauseTransferR :: Transfer -> Handler ()
postPauseTransferR t = pauseTransfer t
getStartTransferR :: Transfer -> Handler ()
getStartTransferR t = startTransfer t >> redirectBack
postStartTransferR :: Transfer -> Handler ()
postStartTransferR t = startTransfer t
getCancelTransferR :: Transfer -> Handler ()
getCancelTransferR t = cancelTransfer t >> redirectBack
postCancelTransferR :: Transfer -> Handler ()
postCancelTransferR t = cancelTransfer t
pauseTransfer :: Transfer -> Handler ()
pauseTransfer t = liftIO $ putStrLn "pause"
startTransfer :: Transfer -> Handler ()
startTransfer t = liftIO $ putStrLn "start"
cancelTransfer :: Transfer -> Handler ()
cancelTransfer t = do
webapp <- getYesod
{- remove queued transfer -}
void $ liftIO $ dequeueTransfer (transferQueue webapp) t
{- stop running transfer -}
maybe noop (void . liftIO . stop webapp) =<< running webapp
where
running webapp = liftIO $ M.lookup t . currentTransfers
<$> getDaemonStatus (daemonStatus webapp)
stop webapp info = do
putStrLn $ "stopping transfer " ++ show info
{- When there's a thread associated with the
- transfer, it's killed first, to avoid it
- displaying any alert about the transfer having
- failed when the transfer process is killed. -}
maybe noop killThread $ transferTid info
maybe noop killproc $ transferPid info
removeTransfer (daemonStatus webapp) t
{- In order to stop helper processes like rsync,
- kill the whole process group of the process running the
- transfer. -}
killproc pid = do
g <- getProcessGroupIDOf pid
void $ tryIO $ signalProcessGroup sigTERM g
threadDelay 100000 -- 0.1 second grace period
void $ tryIO $ signalProcessGroup sigKILL g