diff --git a/cardano-tracer/bench/cardano-tracer-bench.hs b/cardano-tracer/bench/cardano-tracer-bench.hs index b91168e086c..03f814681cf 100644 --- a/cardano-tracer/bench/cardano-tracer-bench.hs +++ b/cardano-tracer/bench/cardano-tracer-bench.hs @@ -44,7 +44,7 @@ main = do currentLogLock <- newLock currentDPLock <- newLock - eventsQueues <- initEventsQueues connectedNodesNames dpRequestors currentDPLock + eventsQueues <- initEventsQueues Nothing connectedNodesNames dpRequestors currentDPLock rtViewPageOpened <- newTVarIO False @@ -64,6 +64,7 @@ main = do , teDPRequestors = dpRequestors , teProtocolsBrake = protocolsBrake , teRTViewPageOpened = rtViewPageOpened + , teRTViewStateDir = Nothing } te2 = TracerEnv @@ -81,6 +82,7 @@ main = do , teDPRequestors = dpRequestors , teProtocolsBrake = protocolsBrake , teRTViewPageOpened = rtViewPageOpened + , teRTViewStateDir = Nothing } removePathForcibly root diff --git a/cardano-tracer/src/Cardano/Tracer/CLI.hs b/cardano-tracer/src/Cardano/Tracer/CLI.hs index 221f1886165..ad0b89e8057 100644 --- a/cardano-tracer/src/Cardano/Tracer/CLI.hs +++ b/cardano-tracer/src/Cardano/Tracer/CLI.hs @@ -6,8 +6,9 @@ module Cardano.Tracer.CLI import Options.Applicative -- | CLI parameters required for the tracer. -newtype TracerParams = TracerParams - { tracerConfig :: FilePath +data TracerParams = TracerParams + { tracerConfig :: !FilePath + , stateDir :: !(Maybe FilePath) } -- | Parse CLI parameters for the tracer. @@ -20,3 +21,12 @@ parseTracerParams = TracerParams <> help "Configuration file for cardano-tracer" <> completer (bashCompleter "file") ) + <*> optional + ( + strOption + ( long "state-dir" + <> metavar "FILEPATH" + <> help "If specified, RTView saves its state in this directory" + <> completer (bashCompleter "file") + ) + ) diff --git a/cardano-tracer/src/Cardano/Tracer/Environment.hs b/cardano-tracer/src/Cardano/Tracer/Environment.hs index 67103cf6d1f..580546f87bf 100644 --- a/cardano-tracer/src/Cardano/Tracer/Environment.hs +++ b/cardano-tracer/src/Cardano/Tracer/Environment.hs @@ -27,4 +27,5 @@ data TracerEnv = TracerEnv , teDPRequestors :: !DataPointRequestors , teProtocolsBrake :: !ProtocolsBrake , teRTViewPageOpened :: !WebPageStatus + , teRTViewStateDir :: !(Maybe FilePath) } diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/Metrics/Monitoring.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/Metrics/Monitoring.hs index 7cc49c9819d..debaa0efd78 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/Metrics/Monitoring.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/Metrics/Monitoring.hs @@ -45,7 +45,7 @@ runMonitoringServer runMonitoringServer tracerEnv (Endpoint listHost listPort, monitorEP) = do -- Pause to prevent collision between "Listening"-notifications from servers. sleep 0.2 - (certFile, keyFile) <- placeDefaultSSLFiles + (certFile, keyFile) <- placeDefaultSSLFiles tracerEnv UI.startGUI (config certFile keyFile) $ \window -> do void $ return window # set UI.title "EKG Monitoring Nodes" void $ mkPageBody window tracerEnv monitorEP diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Send.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Send.hs index 993238eca6d..e7c97f01131 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Send.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Send.hs @@ -23,14 +23,16 @@ import Cardano.Tracer.Types import Cardano.Tracer.Utils makeAndSendNotification - :: ConnectedNodesNames + :: Maybe FilePath + -> ConnectedNodesNames -> DataPointRequestors -> Lock -> TVar UTCTime -> EventsQueue -> IO () -makeAndSendNotification connectedNodesNames dpRequestors currentDPLock lastTime eventsQueue = do - emailSettings <- readSavedEmailSettings +makeAndSendNotification rtvSD connectedNodesNames dpRequestors + currentDPLock lastTime eventsQueue = do + emailSettings <- readSavedEmailSettings rtvSD unless (incompleteEmailSettings emailSettings) $ do events <- atomically $ nub <$> flushTBQueue eventsQueue let (nodeIds, tss) = unzip $ nub [(nodeId, ts) | Event nodeId ts _ _ <- events] diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Settings.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Settings.hs index 7d12cba1da1..1e5a8f604b3 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Settings.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Settings.hs @@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -22,12 +23,13 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import qualified Data.Text as T +import Cardano.Tracer.Environment import Cardano.Tracer.Handlers.RTView.Notifications.Types import Cardano.Tracer.Handlers.RTView.System -readSavedEmailSettings :: IO EmailSettings -readSavedEmailSettings = do - (pathToEmailSettings, _) <- getPathsToNotificationsSettings +readSavedEmailSettings :: Maybe FilePath -> IO EmailSettings +readSavedEmailSettings rtvSD = do + (pathToEmailSettings, _) <- getPathsToNotificationsSettings rtvSD try_ (BS.readFile pathToEmailSettings) >>= \case Left _ -> return defaultSettings Right jsonSettings -> @@ -72,9 +74,9 @@ incompleteEmailSettings emailSettings = T.null $ esSMTPHost emailSettings -- key :: BS.ByteString -- key = "n3+d6^jrodGe$1Ljwt;iBtsi_mxzp-47" -readSavedEventsSettings :: IO EventsSettings -readSavedEventsSettings = do - (_, pathToEventsSettings) <- getPathsToNotificationsSettings +readSavedEventsSettings :: Maybe FilePath -> IO EventsSettings +readSavedEventsSettings rtvSD = do + (_, pathToEventsSettings) <- getPathsToNotificationsSettings rtvSD try_ (BS.readFile pathToEventsSettings) >>= \case Left _ -> return defaultSettings Right jsonSettings -> @@ -92,16 +94,16 @@ readSavedEventsSettings = do } defaultState = (False, 1800) -saveEmailSettingsOnDisk :: EmailSettings -> IO () -saveEmailSettingsOnDisk settings = ignore $ do - (pathToEmailSettings, _) <- getPathsToNotificationsSettings +saveEmailSettingsOnDisk :: TracerEnv -> EmailSettings -> IO () +saveEmailSettingsOnDisk TracerEnv{teRTViewStateDir} settings = ignore $ do + (pathToEmailSettings, _) <- getPathsToNotificationsSettings teRTViewStateDir LBS.writeFile pathToEmailSettings $ encode settings -- Encrypt JSON-content to avoid saving user's private data in "plain mode". -- case encryptJSON . LBS.toStrict . encode $ settings of -- Right encryptedJSON -> BS.writeFile pathToEmailSettings encryptedJSON -- Left _ -> return () -saveEventsSettingsOnDisk :: EventsSettings -> IO () -saveEventsSettingsOnDisk settings = ignore $ do - (_, pathToEventsSettings) <- getPathsToNotificationsSettings +saveEventsSettingsOnDisk :: TracerEnv -> EventsSettings -> IO () +saveEventsSettingsOnDisk TracerEnv{teRTViewStateDir} settings = ignore $ do + (_, pathToEventsSettings) <- getPathsToNotificationsSettings teRTViewStateDir encodeFile pathToEventsSettings settings diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Utils.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Utils.hs index 1da1c639d3b..a4e44e3bcfd 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Utils.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Notifications/Utils.hs @@ -24,11 +24,12 @@ import Cardano.Tracer.Handlers.RTView.Update.Utils import Cardano.Tracer.Types initEventsQueues - :: ConnectedNodesNames + :: Maybe FilePath + -> ConnectedNodesNames -> DataPointRequestors -> Lock -> IO EventsQueues -initEventsQueues nodesNames dpReqs curDPLock = do +initEventsQueues rtvSD nodesNames dpReqs curDPLock = do lastTime <- newTVarIO nullTime warnQ <- initEventsQueue @@ -38,7 +39,7 @@ initEventsQueues nodesNames dpReqs curDPLock = do emrgQ <- initEventsQueue nodeDisconQ <- initEventsQueue - settings <- readSavedEventsSettings + settings <- readSavedEventsSettings rtvSD let (warnS, warnP) = evsWarnings settings (errsS, errsP) = evsErrors settings (critS, critP) = evsCriticals settings @@ -46,13 +47,13 @@ initEventsQueues nodesNames dpReqs curDPLock = do (emrgS, emrgP) = evsEmergencies settings (nodeDisconS, nodeDisconP) = evsNodeDisconnected settings - warnT <- mkTimer (makeAndSendNotification nodesNames dpReqs curDPLock lastTime warnQ) warnS warnP - errsT <- mkTimer (makeAndSendNotification nodesNames dpReqs curDPLock lastTime errsQ) errsS errsP - critT <- mkTimer (makeAndSendNotification nodesNames dpReqs curDPLock lastTime critQ) critS critP - alrtT <- mkTimer (makeAndSendNotification nodesNames dpReqs curDPLock lastTime alrtQ) alrtS alrtP - emrgT <- mkTimer (makeAndSendNotification nodesNames dpReqs curDPLock lastTime emrgQ) emrgS emrgP - nodeDisconT <- mkTimer (makeAndSendNotification nodesNames dpReqs curDPLock lastTime nodeDisconQ) - nodeDisconS nodeDisconP + warnT <- mkTimer (makeAndSendNotification rtvSD nodesNames dpReqs curDPLock lastTime warnQ) warnS warnP + errsT <- mkTimer (makeAndSendNotification rtvSD nodesNames dpReqs curDPLock lastTime errsQ) errsS errsP + critT <- mkTimer (makeAndSendNotification rtvSD nodesNames dpReqs curDPLock lastTime critQ) critS critP + alrtT <- mkTimer (makeAndSendNotification rtvSD nodesNames dpReqs curDPLock lastTime alrtQ) alrtS alrtP + emrgT <- mkTimer (makeAndSendNotification rtvSD nodesNames dpReqs curDPLock lastTime emrgQ) emrgS emrgP + nodeDisconT <- + mkTimer (makeAndSendNotification rtvSD nodesNames dpReqs curDPLock lastTime nodeDisconQ) nodeDisconS nodeDisconP newTVarIO $ M.fromList [ (EventWarnings, (warnQ, warnT)) diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Run.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Run.hs index 0736e5f9568..50b68e8785c 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Run.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Run.hs @@ -43,7 +43,7 @@ runRTView tracerEnv = -- Pause to prevent collision between "Listening"-notifications from servers. sleep 0.3 -- Get paths to default SSL files for config. - (certFile, keyFile) <- placeDefaultSSLFiles + (certFile, keyFile) <- placeDefaultSSLFiles tracerEnv -- Initialize displayed stuff outside of main page renderer, -- to be able to update corresponding elements after page reloading. displayedElements <- initDisplayedElements diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/SSL/Certs.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/SSL/Certs.hs index 14d1bb1d839..ea21284bede 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/SSL/Certs.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/SSL/Certs.hs @@ -12,11 +12,12 @@ import qualified Data.ByteString as BS import Data.String.QQ import qualified System.Directory as D +import Cardano.Tracer.Environment import Cardano.Tracer.Handlers.RTView.System -placeDefaultSSLFiles :: IO (FilePath, FilePath) -placeDefaultSSLFiles = do - (pathToCertFile, pathToKeyFile) <- getPathsToSSLCerts +placeDefaultSSLFiles :: TracerEnv -> IO (FilePath, FilePath) +placeDefaultSSLFiles tracerEnv = do + (pathToCertFile, pathToKeyFile) <- getPathsToSSLCerts tracerEnv writeIfNeeded pathToCertFile defaultCert writeIfNeeded pathToKeyFile defaultKey -- Set permissions like 'openssl' does. diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/System.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/System.hs index 3ee54d3eba0..b1cd577b45a 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/System.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/System.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE NamedFieldPuns #-} module Cardano.Tracer.Handlers.RTView.System ( getPathToBackupDir @@ -22,6 +23,8 @@ import System.Posix.Process (getProcessID) import System.Posix.Types (CPid (..)) #endif +import Cardano.Tracer.Environment + getProcessId :: UI Word32 getProcessId = #if defined(mingw32_HOST_OS) @@ -31,53 +34,59 @@ getProcessId = return $ fromIntegral pid #endif -getPathToChartsConfig, getPathToThemeConfig :: IO FilePath +getPathToChartsConfig, getPathToThemeConfig :: TracerEnv -> IO FilePath getPathToChartsConfig = getPathToConfig "charts" getPathToThemeConfig = getPathToConfig "theme" -getPathToConfig :: FilePath -> IO FilePath -getPathToConfig configName = do - configDir <- getPathToConfigDir +getPathToConfig :: FilePath -> TracerEnv -> IO FilePath +getPathToConfig configName TracerEnv{teRTViewStateDir} = do + configDir <- getPathToConfigDir teRTViewStateDir return $ configDir configName -getPathsToSSLCerts :: IO (FilePath, FilePath) -getPathsToSSLCerts = do - configDir <- getPathToConfigDir +getPathsToSSLCerts :: TracerEnv -> IO (FilePath, FilePath) +getPathsToSSLCerts TracerEnv{teRTViewStateDir} = do + configDir <- getPathToConfigDir teRTViewStateDir let pathToSSLSubDir = configDir "ssl" D.createDirectoryIfMissing True pathToSSLSubDir return ( pathToSSLSubDir "cert.pem" , pathToSSLSubDir "key.pem" ) -getPathsToNotificationsSettings :: IO (FilePath, FilePath) -getPathsToNotificationsSettings = do - configDir <- getPathToConfigDir +getPathsToNotificationsSettings :: Maybe FilePath -> IO (FilePath, FilePath) +getPathsToNotificationsSettings rtvSD = do + configDir <- getPathToConfigDir rtvSD let pathToNotifySubDir = configDir "notifications" D.createDirectoryIfMissing True pathToNotifySubDir return ( pathToNotifySubDir "email" , pathToNotifySubDir "events" ) -getPathToConfigDir :: IO FilePath -getPathToConfigDir = do - configDir <- D.getXdgDirectory D.XdgConfig "" +getPathToChartColorsDir :: TracerEnv -> IO FilePath +getPathToChartColorsDir TracerEnv{teRTViewStateDir} = do + configDir <- getPathToConfigDir teRTViewStateDir + let pathToColorsSubDir = configDir "color" + D.createDirectoryIfMissing True pathToColorsSubDir + return pathToColorsSubDir + +getPathToConfigDir :: Maybe FilePath -> IO FilePath +getPathToConfigDir rtvSD = do + configDir <- + case rtvSD of + Nothing -> D.getXdgDirectory D.XdgConfig "" + Just rtViewStateDir -> return $ rtViewStateDir "config" let pathToRTViewConfigDir = configDir rtViewRootDir D.createDirectoryIfMissing True pathToRTViewConfigDir return pathToRTViewConfigDir -getPathToBackupDir :: IO FilePath -getPathToBackupDir = do - dataDir <- D.getXdgDirectory D.XdgData "" +getPathToBackupDir :: TracerEnv -> IO FilePath +getPathToBackupDir TracerEnv{teRTViewStateDir} = do + dataDir <- + case teRTViewStateDir of + Nothing -> D.getXdgDirectory D.XdgData "" + Just rtViewStateDir -> return $ rtViewStateDir "data" let pathToRTViewBackupDir = dataDir rtViewRootDir "backup" D.createDirectoryIfMissing True pathToRTViewBackupDir return pathToRTViewBackupDir -getPathToChartColorsDir :: IO FilePath -getPathToChartColorsDir = do - configDir <- getPathToConfigDir - let pathToColorsSubDir = configDir "color" - D.createDirectoryIfMissing True pathToColorsSubDir - return pathToColorsSubDir - rtViewRootDir :: FilePath rtViewRootDir = "cardano-rt-view" diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Charts.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Charts.hs index 99b0d873646..3edfc372558 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Charts.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Charts.hs @@ -95,11 +95,11 @@ addNodeDatasetsToCharts tracerEnv colors datasetIndices nodeId@(NodeId anId) = d -- If so - we have to take its color again, from the file. -- If not - we have to take the new color for it and save it for the future. colorForNode@(Color code) <- - liftIO (getSavedColorForNode nodeName) >>= \case + liftIO (getSavedColorForNode tracerEnv nodeName) >>= \case Just savedColor -> return savedColor Nothing -> do newColor <- getNewColor - liftIO $ saveColorForNode nodeName newColor + liftIO $ saveColorForNode tracerEnv nodeName newColor return newColor forM_ chartsIds $ \chartId -> case mIx of @@ -194,8 +194,8 @@ replacePointsByAvgPoints points = -- Maximum number of points to calculate avg = 15 s. numberOfPointsToAverage = 15 -restoreChartsSettings :: UI () -restoreChartsSettings = readSavedChartsSettings >>= setCharts +restoreChartsSettings :: TracerEnv -> UI () +restoreChartsSettings tracerEnv = readSavedChartsSettings tracerEnv >>= setCharts where setCharts settings = forM_ settings $ \(chartId, ChartSettings tr up) -> do @@ -204,15 +204,15 @@ restoreChartsSettings = readSavedChartsSettings >>= setCharts Chart.setTimeRange chartId tr when (tr == 0) $ Chart.resetZoomChartJS chartId -saveChartsSettings :: UI () -saveChartsSettings = do +saveChartsSettings :: TracerEnv -> UI () +saveChartsSettings tracerEnv = do settings <- forM chartsIds $ \chartId -> do selectedTR <- getOptionValue $ show chartId <> show TimeRangeSelect selectedUP <- getOptionValue $ show chartId <> show UpdatePeriodSelect return (chartId, ChartSettings selectedTR selectedUP) liftIO . ignore $ do - pathToChartsConfig <- getPathToChartsConfig + pathToChartsConfig <- getPathToChartsConfig tracerEnv encodeFile pathToChartsConfig settings where getOptionValue selectId = do @@ -222,9 +222,9 @@ saveChartsSettings = do Just (valueInS :: Int) -> return valueInS Nothing -> return 0 -readSavedChartsSettings :: UI ChartsSettings -readSavedChartsSettings = liftIO $ - try_ (decodeFileStrict' =<< getPathToChartsConfig) >>= \case +readSavedChartsSettings :: TracerEnv -> UI ChartsSettings +readSavedChartsSettings tracerEnv = liftIO $ + try_ (decodeFileStrict' =<< getPathToChartsConfig tracerEnv) >>= \case Right (Just (settings :: ChartsSettings)) -> return settings _ -> return defaultSettings where @@ -320,9 +320,12 @@ dataNameToChartId dataName = MempoolBytesData -> MempoolBytesChart TxsInMempoolData -> TxsInMempoolChart -getSavedColorForNode :: NodeName -> IO (Maybe Color) -getSavedColorForNode nodeName = do - colorsDir <- getPathToChartColorsDir +getSavedColorForNode + :: TracerEnv + -> NodeName + -> IO (Maybe Color) +getSavedColorForNode tracerEnv nodeName = do + colorsDir <- getPathToChartColorsDir tracerEnv colorFiles <- map (\cf -> colorsDir takeBaseName cf) <$> listFiles colorsDir case find (\cf -> unpack nodeName `isInfixOf` cf) colorFiles of Nothing -> return Nothing @@ -341,7 +344,11 @@ getSavedColorForNode nodeName = do && all (\c -> isDigit c || c `elem` ['a' .. 'f'] ) (tail $ lower code) -saveColorForNode :: NodeName -> Color -> IO () -saveColorForNode nodeName (Color code) = do - colorsDir <- getPathToChartColorsDir +saveColorForNode + :: TracerEnv + -> NodeName + -> Color + -> IO () +saveColorForNode tracerEnv nodeName (Color code) = do + colorsDir <- getPathToChartColorsDir tracerEnv ignore $ writeFile (colorsDir unpack nodeName) code diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Body.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Body.hs index 0b791cd5fcf..279080b0b07 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Body.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Body.hs @@ -458,7 +458,7 @@ mkPageBody tracerEnv networkConfig dsIxs = do -- but for this 'dataName' only! restoreAllHistoryOnChart tracerEnv dataName chartId dsIxs Chart.resetZoomChartJS chartId - saveChartsSettings + saveChartsSettings tracerEnv on UI.selectionChange selectUpdatePeriod . const $ whenJustM (readMaybe <$> get value selectUpdatePeriod) $ \(periodInSec :: Int) -> do @@ -466,7 +466,7 @@ mkPageBody tracerEnv networkConfig dsIxs = do unless (periodInSec == 0) $ do void $ return chartUpdateTimer # set UI.interval (periodInSec * 1000) UI.start chartUpdateTimer - saveChartsSettings + saveChartsSettings tracerEnv UI.div #. "rt-view-chart-container" #+ [ UI.div #. "columns" #+ @@ -488,15 +488,15 @@ mkPageBody tracerEnv networkConfig dsIxs = do ] topNavigation :: TracerEnv -> UI Element -topNavigation TracerEnv{teEventsQueues} = do +topNavigation tracerEnv@TracerEnv{teEventsQueues} = do info <- mkAboutInfo infoIcon <- image "has-tooltip-multiline has-tooltip-bottom rt-view-info-icon mr-1" rtViewInfoSVG ## "info-icon" # set dataTooltip "RTView info" on UI.click infoIcon . const $ fadeInModal info - notificationsEvents <- mkNotificationsEvents teEventsQueues - notificationsSettings <- mkNotificationsSettings + notificationsEvents <- mkNotificationsEvents tracerEnv teEventsQueues + notificationsSettings <- mkNotificationsSettings tracerEnv notificationsEventsItem <- UI.anchor #. "navbar-item" #+ [ image "rt-view-notify-menu-icon" eventsSVG @@ -509,7 +509,7 @@ topNavigation TracerEnv{teEventsQueues} = do on UI.click notificationsEventsItem . const $ fadeInModal notificationsEvents on UI.click notificationsSettingsItem . const $ do - restoreEmailSettings + restoreEmailSettings tracerEnv fadeInModal notificationsSettings notificationsIcon <- image "rt-view-info-icon mr-2" rtViewNotifySVG @@ -518,7 +518,7 @@ topNavigation TracerEnv{teEventsQueues} = do themeIcon <- image "has-tooltip-multiline has-tooltip-bottom rt-view-theme-icon" rtViewThemeToLightSVG ## "theme-icon" # set dataTooltip "Switch to light theme" - on UI.click themeIcon . const $ askWindow >>= switchTheme + on UI.click themeIcon . const $ switchTheme tracerEnv UI.div ## "top-bar" #. "navbar rt-view-top-bar" #+ [ element info diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Main.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Main.hs index adb53d3f8bf..b5977a9d9ad 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Main.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Main.hs @@ -79,10 +79,10 @@ mkMainPage tracerEnv displayedElements nodesEraSettings reloadFlag UI.stop preloaderTimer UI.start preloaderTimer - restoreTheme window - restoreChartsSettings - restoreEmailSettings - restoreEventsSettings + restoreTheme tracerEnv + restoreChartsSettings tracerEnv + restoreEmailSettings tracerEnv + restoreEventsSettings tracerEnv uiNoNodesProgressTimer <- UI.timer # set UI.interval 1000 on UI.tick uiNoNodesProgressTimer . const $ do diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Notifications.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Notifications.hs index 7cf451378aa..eb323beb919 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Notifications.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/HTML/Notifications.hs @@ -13,6 +13,7 @@ import qualified Graphics.UI.Threepenny as UI import Graphics.UI.Threepenny.Core import Text.Read (readMaybe) +import Cardano.Tracer.Environment import Cardano.Tracer.Handlers.RTView.Notifications.Email import Cardano.Tracer.Handlers.RTView.Notifications.Timer import Cardano.Tracer.Handlers.RTView.Notifications.Types @@ -21,8 +22,8 @@ import Cardano.Tracer.Handlers.RTView.UI.Img.Icons import Cardano.Tracer.Handlers.RTView.UI.Notifications import Cardano.Tracer.Handlers.RTView.UI.Utils -mkNotificationsEvents :: EventsQueues -> UI Element -mkNotificationsEvents eventsQueues = do +mkNotificationsEvents :: TracerEnv -> EventsQueues -> UI Element +mkNotificationsEvents tracerEnv eventsQueues = do closeIt <- UI.button #. "delete" (switchAll, switchAllW) <- mkSwitch "switch-all" "All events" "" @@ -89,31 +90,31 @@ mkNotificationsEvents eventsQueues = do on UI.click closeIt . const $ do void $ element notifications #. "modal" - saveEventsSettings + saveEventsSettings tracerEnv on UI.checkedChange switchWarnings $ \state -> do setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ updateNotificationsEvents eventsQueues EventWarnings state on UI.checkedChange switchErrors $ \state -> do setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ updateNotificationsEvents eventsQueues EventErrors state on UI.checkedChange switchCriticals $ \state -> do setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ updateNotificationsEvents eventsQueues EventCriticals state on UI.checkedChange switchAlerts $ \state -> do setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ updateNotificationsEvents eventsQueues EventAlerts state on UI.checkedChange switchEmergencies $ \state -> do setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ updateNotificationsEvents eventsQueues EventEmergencies state on UI.checkedChange switchNodeDiscon $ \state -> do setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ updateNotificationsEvents eventsQueues EventNodeDisconnected state on UI.checkedChange switchAll $ \state -> do @@ -125,7 +126,7 @@ mkNotificationsEvents eventsQueues = do void $ element switchNodeDiscon # set UI.checked state setNotifyIconState - saveEventsSettings + saveEventsSettings tracerEnv liftIO $ do updateNotificationsEvents eventsQueues EventWarnings state @@ -210,8 +211,8 @@ mkSwitch switchId switchName bulmaColorName = do -- | Settings for notifications (email, etc.). -mkNotificationsSettings :: UI Element -mkNotificationsSettings = do +mkNotificationsSettings :: TracerEnv -> UI Element +mkNotificationsSettings tracerEnv = do closeIt <- UI.button #. "delete" sendTestEmail <- UI.button ## "send-test-email" #. "button is-primary" @@ -317,7 +318,7 @@ mkNotificationsSettings = do on UI.click closeIt . const $ do void $ element notifications #. "modal" void $ element sendTestEmailStatus # set text "" - saveEmailSettings + saveEmailSettings tracerEnv on UI.click sendTestEmail . const $ do void $ element sendTestEmailStatus # set text "" diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Notifications.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Notifications.hs index e2387d99097..b61a9216b54 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Notifications.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Notifications.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -20,6 +21,7 @@ import Data.Text.Read (decimal) import qualified Graphics.UI.Threepenny as UI import Graphics.UI.Threepenny.Core +import Cardano.Tracer.Environment import Cardano.Tracer.Handlers.RTView.Notifications.Settings import Cardano.Tracer.Handlers.RTView.Notifications.Timer import Cardano.Tracer.Handlers.RTView.Notifications.Types @@ -28,9 +30,9 @@ import Cardano.Tracer.Handlers.RTView.UI.Utils import Cardano.Tracer.Handlers.RTView.UI.JS.Utils import Cardano.Tracer.Handlers.RTView.Update.Utils -restoreEmailSettings :: UI () -restoreEmailSettings = do - eSettings <- liftIO readSavedEmailSettings +restoreEmailSettings :: TracerEnv -> UI () +restoreEmailSettings TracerEnv{teRTViewStateDir} = do + eSettings <- liftIO $ readSavedEmailSettings teRTViewStateDir setEmailSettings eSettings setStatusTestEmailButton where @@ -49,9 +51,9 @@ restoreEmailSettings = do unless (null elValue || elValue == "-1") $ findAndSet (set value elValue) window elId -restoreEventsSettings :: UI () -restoreEventsSettings = do - eSettings <- liftIO readSavedEventsSettings +restoreEventsSettings :: TracerEnv -> UI () +restoreEventsSettings TracerEnv{teRTViewStateDir} = do + eSettings <- liftIO $ readSavedEventsSettings teRTViewStateDir setEventsSettings eSettings setNotifyIconState setSwitchAllState eSettings @@ -107,11 +109,13 @@ setNotifyIconState = do when noChecked $ findAndSet (set html rtViewNoNotifySVG) window "notifications-icon" findAndSet (set UI.checked allChecked) window "switch-all" -saveEmailSettings :: UI () -saveEmailSettings = (liftIO . saveEmailSettingsOnDisk) =<< getCurrentEmailSettings +saveEmailSettings :: TracerEnv -> UI () +saveEmailSettings tracerEnv = + (liftIO . saveEmailSettingsOnDisk tracerEnv) =<< getCurrentEmailSettings -saveEventsSettings :: UI () -saveEventsSettings = (liftIO . saveEventsSettingsOnDisk) =<< getCurrentEventsSettings +saveEventsSettings :: TracerEnv -> UI () +saveEventsSettings tracerEnv = + (liftIO . saveEventsSettingsOnDisk tracerEnv) =<< getCurrentEventsSettings getCurrentEmailSettings :: UI EmailSettings getCurrentEmailSettings = do diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Theme.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Theme.hs index a92fbea6a3f..2158acb2d72 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Theme.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/UI/Theme.hs @@ -16,49 +16,45 @@ import qualified Data.Text.IO as TIO import qualified Graphics.UI.Threepenny as UI import Graphics.UI.Threepenny.Core +import Cardano.Tracer.Environment import Cardano.Tracer.Handlers.RTView.System import Cardano.Tracer.Handlers.RTView.UI.Charts import Cardano.Tracer.Handlers.RTView.UI.Img.Icons import Cardano.Tracer.Handlers.RTView.UI.Utils -restoreTheme, switchTheme :: UI.Window -> UI () -restoreTheme window = readSavedTheme >>= setThemeAndSave window -switchTheme window = readSavedTheme >>= setThemeAndSave window . switch +restoreTheme, switchTheme :: TracerEnv -> UI () +restoreTheme tracerEnv = readSavedTheme tracerEnv >>= setThemeAndSave tracerEnv +switchTheme tracerEnv = readSavedTheme tracerEnv >>= setThemeAndSave tracerEnv . switch where switch s = if s == darkState then lightState else darkState -isCurrentThemeDark :: UI Bool -isCurrentThemeDark = (== darkState) <$> readSavedTheme +isCurrentThemeDark :: TracerEnv -> UI Bool +isCurrentThemeDark tracerEnv = (== darkState) <$> readSavedTheme tracerEnv setThemeAndSave - :: UI.Window + :: TracerEnv -> String -> UI () -setThemeAndSave window themeToSet = do - changeThemeIcon - changeBodyClass - changeCharts - saveTheme themeToSet - where - toBeLight = themeToSet == lightState +setThemeAndSave tracerEnv themeToSet = do + window <- askWindow + let change elId what = findAndSet what window elId - changeThemeIcon = do - change "theme-icon" $ - set html (if toBeLight then rtViewThemeToDarkSVG else rtViewThemeToLightSVG) - . set dataState (if toBeLight then lightState else darkState) - . set dataTooltip ("Switch to " <> (if toBeLight then "dark" else "light") <> " theme") + change "theme-icon" $ + set html (if toBeLight then rtViewThemeToDarkSVG else rtViewThemeToLightSVG) + . set dataState (if toBeLight then lightState else darkState) + . set dataTooltip ("Switch to " <> (if toBeLight then "dark" else "light") <> " theme") - changeBodyClass = - getElementsByTagName window "body" >>= \case - [body] -> void $ element body # set UI.class_ (if toBeLight then lightState else darkState) - _ -> return () + getElementsByTagName window "body" >>= \case + [body] -> void $ element body # set UI.class_ (if toBeLight then lightState else darkState) + _ -> return () - change elId what = findAndSet what window elId + if toBeLight + then changeChartsToLightTheme + else changeChartsToDarkTheme - changeCharts = - if toBeLight - then changeChartsToLightTheme - else changeChartsToDarkTheme + saveTheme tracerEnv themeToSet + where + toBeLight = themeToSet == lightState lightState, darkState :: String lightState = "light" @@ -66,13 +62,13 @@ darkState = "dark" -- | Every time when the user changed the theme, it should be saved on the file -- for next sessions, both after web-page reload and 'cardano-tracer' restart. -saveTheme :: String -> UI () -saveTheme state = liftIO . ignore $ do - pathToThemeConfig <- getPathToThemeConfig +saveTheme :: TracerEnv -> String -> UI () +saveTheme tracerEnv state = liftIO . ignore $ do + pathToThemeConfig <- getPathToThemeConfig tracerEnv TIO.writeFile pathToThemeConfig $ T.pack state -readSavedTheme :: UI String -readSavedTheme = liftIO $ - try_ (TIO.readFile =<< getPathToThemeConfig) >>= \case +readSavedTheme :: TracerEnv -> UI String +readSavedTheme tracerEnv = liftIO $ + try_ (TIO.readFile =<< getPathToThemeConfig tracerEnv) >>= \case Right saved -> return $ T.unpack saved Left _ -> return darkState -- Use dark theme by default. diff --git a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Update/Historical.hs b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Update/Historical.hs index 100374aa00a..6888c49b168 100644 --- a/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Update/Historical.hs +++ b/cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Update/Historical.hs @@ -92,7 +92,7 @@ backupAllHistory :: TracerEnv -> IO () backupAllHistory tracerEnv@TracerEnv{teConnectedNodes} = do connected <- S.toList <$> readTVarIO teConnectedNodes nodesIdsWithNames <- getNodesIdsWithNames tracerEnv connected - backupDir <- getPathToBackupDir + backupDir <- getPathToBackupDir tracerEnv (cHistory, rHistory, tHistory) <- atomically $ (,,) <$> readTVar chainHistory <*> readTVar resourcesHistory @@ -126,7 +126,7 @@ backupSpecificHistory -> DataName -> IO () backupSpecificHistory tracerEnv history connected dataName = do - backupDir <- getPathToBackupDir + backupDir <- getPathToBackupDir tracerEnv hist <- readTVarIO history forMM_ (getNodesIdsWithNames tracerEnv connected) $ \(nodeId, nodeName) -> do backupHistory backupDir hist nodeId nodeName $ Just dataName @@ -178,7 +178,7 @@ getAllHistoryFromBackup getAllHistoryFromBackup tracerEnv@TracerEnv{teConnectedNodes} dataName = do connected <- S.toList <$> readTVarIO teConnectedNodes nodesIdsWithNames <- getNodesIdsWithNames tracerEnv connected - backupDir <- getPathToBackupDir + backupDir <- getPathToBackupDir tracerEnv forM nodesIdsWithNames $ \(nodeId, nodeName) -> do let nodeSubdir = backupDir T.unpack nodeName doesDirectoryExist nodeSubdir >>= \case @@ -218,7 +218,7 @@ getLastHistoryFromBackups' -> [NodeId] -> IO [(NodeId, [(DataName, [HistoricalPoint])])] getLastHistoryFromBackups' tracerEnv nodeIds = do - backupDir <- getPathToBackupDir + backupDir <- getPathToBackupDir tracerEnv forMM (getNodesIdsWithNames tracerEnv nodeIds) $ \(nodeId, nodeName) -> do let nodeSubdir = backupDir T.unpack nodeName doesDirectoryExist nodeSubdir >>= \case diff --git a/cardano-tracer/src/Cardano/Tracer/Run.hs b/cardano-tracer/src/Cardano/Tracer/Run.hs index 2451f6a4b7b..f84df7d7f1d 100644 --- a/cardano-tracer/src/Cardano/Tracer/Run.hs +++ b/cardano-tracer/src/Cardano/Tracer/Run.hs @@ -25,19 +25,20 @@ import Cardano.Tracer.Utils -- | Top-level run function, called by 'cardano-tracer' app. runCardanoTracer :: TracerParams -> IO () -runCardanoTracer TracerParams{tracerConfig} = do +runCardanoTracer TracerParams{tracerConfig, stateDir} = do config <- readTracerConfig tracerConfig brake <- initProtocolsBrake dpRequestors <- initDataPointRequestors - doRunCardanoTracer config brake dpRequestors + doRunCardanoTracer config stateDir brake dpRequestors -- | Runs all internal services of the tracer. doRunCardanoTracer :: TracerConfig -- ^ Tracer's configuration. + -> Maybe FilePath -- ^ Path to RTView's internal state files. -> ProtocolsBrake -- ^ The flag we use to stop all the protocols. -> DataPointRequestors -- ^ The DataPointRequestors to ask 'DataPoint's. -> IO () -doRunCardanoTracer config protocolsBrake dpRequestors = do +doRunCardanoTracer config rtViewStateDir protocolsBrake dpRequestors = do connectedNodes <- initConnectedNodes connectedNodesNames <- initConnectedNodesNames acceptedMetrics <- initAcceptedMetrics @@ -49,7 +50,7 @@ doRunCardanoTracer config protocolsBrake dpRequestors = do currentLogLock <- newLock currentDPLock <- newLock - eventsQueues <- initEventsQueues connectedNodesNames dpRequestors currentDPLock + eventsQueues <- initEventsQueues rtViewStateDir connectedNodesNames dpRequestors currentDPLock rtViewPageOpened <- newTVarIO False @@ -70,6 +71,7 @@ doRunCardanoTracer config protocolsBrake dpRequestors = do , teDPRequestors = dpRequestors , teProtocolsBrake = protocolsBrake , teRTViewPageOpened = rtViewPageOpened + , teRTViewStateDir = rtViewStateDir } -- Specify what should be done before 'cardano-tracer' stops. diff --git a/cardano-tracer/test/Cardano/Tracer/Test/Acceptor.hs b/cardano-tracer/test/Cardano/Tracer/Test/Acceptor.hs index 50d5d64c8ca..3cc010ff058 100644 --- a/cardano-tracer/test/Cardano/Tracer/Test/Acceptor.hs +++ b/cardano-tracer/test/Cardano/Tracer/Test/Acceptor.hs @@ -41,7 +41,7 @@ launchAcceptorsSimple mode localSock dpName = do savedTO <- initSavedTraceObjects currentLogLock <- newLock currentDPLock <- newLock - eventsQueues <- initEventsQueues connectedNodesNames dpRequestors currentDPLock + eventsQueues <- initEventsQueues Nothing connectedNodesNames dpRequestors currentDPLock chainHistory <- initBlockchainHistory resourcesHistory <- initResourcesHistory @@ -65,6 +65,7 @@ launchAcceptorsSimple mode localSock dpName = do , teDPRequestors = dpRequestors , teProtocolsBrake = protocolsBrake , teRTViewPageOpened = rtViewPageOpened + , teRTViewStateDir = Nothing } void . sequenceConcurrently $ diff --git a/cardano-tracer/test/Cardano/Tracer/Test/DataPoint/Tests.hs b/cardano-tracer/test/Cardano/Tracer/Test/DataPoint/Tests.hs index a3931fd3b48..eec913372f3 100644 --- a/cardano-tracer/test/Cardano/Tracer/Test/DataPoint/Tests.hs +++ b/cardano-tracer/test/Cardano/Tracer/Test/DataPoint/Tests.hs @@ -35,7 +35,7 @@ propDataPoint rootDir localSock = do stopProtocols <- initProtocolsBrake dpRequestors <- initDataPointRequestors savedDPValues :: TVar DataPointValues <- newTVarIO [] - withAsync (doRunCardanoTracer config stopProtocols dpRequestors) . const $ do + withAsync (doRunCardanoTracer config Nothing stopProtocols dpRequestors) . const $ do sleep 1.0 withAsync (launchForwardersSimple Initiator localSock 1000 10000) . const $ do sleep 1.5 diff --git a/cardano-tracer/test/Cardano/Tracer/Test/Logs/Tests.hs b/cardano-tracer/test/Cardano/Tracer/Test/Logs/Tests.hs index 26b8f5c1874..8bb187b7420 100644 --- a/cardano-tracer/test/Cardano/Tracer/Test/Logs/Tests.hs +++ b/cardano-tracer/test/Cardano/Tracer/Test/Logs/Tests.hs @@ -36,7 +36,7 @@ propLogs :: LogFormat -> FilePath -> FilePath -> IO Property propLogs format rootDir localSock = do stopProtocols <- initProtocolsBrake dpRequestors <- initDataPointRequestors - withAsync (doRunCardanoTracer (config rootDir localSock) stopProtocols dpRequestors) . const $ do + withAsync (doRunCardanoTracer (config rootDir localSock) Nothing stopProtocols dpRequestors) . const $ do sleep 1.0 withAsync (launchForwardersSimple Initiator localSock 1000 10000) . const $ do sleep 8.0 -- Wait till some rotation is done. @@ -82,7 +82,7 @@ propMultiInit :: LogFormat -> FilePath -> FilePath -> FilePath -> IO Property propMultiInit format rootDir localSock1 localSock2 = do stopProtocols <- initProtocolsBrake dpRequestors <- initDataPointRequestors - withAsync (doRunCardanoTracer (config rootDir localSock1 localSock2) stopProtocols dpRequestors) . const $ do + withAsync (doRunCardanoTracer (config rootDir localSock1 localSock2) Nothing stopProtocols dpRequestors) . const $ do sleep 1.0 withAsync (launchForwardersSimple Responder localSock1 1000 10000) . const $ do sleep 1.0 @@ -109,7 +109,7 @@ propMultiResp :: LogFormat -> FilePath -> FilePath -> IO Property propMultiResp format rootDir localSock = do stopProtocols <- initProtocolsBrake dpRequestors <- initDataPointRequestors - withAsync (doRunCardanoTracer (config rootDir localSock) stopProtocols dpRequestors) . const $ do + withAsync (doRunCardanoTracer (config rootDir localSock) Nothing stopProtocols dpRequestors) . const $ do sleep 1.0 withAsync (launchForwardersSimple Initiator localSock 1000 10000) . const $ do sleep 1.0 diff --git a/cardano-tracer/test/Cardano/Tracer/Test/Restart/Tests.hs b/cardano-tracer/test/Cardano/Tracer/Test/Restart/Tests.hs index 0f175773f31..f64b378514b 100644 --- a/cardano-tracer/test/Cardano/Tracer/Test/Restart/Tests.hs +++ b/cardano-tracer/test/Cardano/Tracer/Test/Restart/Tests.hs @@ -34,7 +34,7 @@ propNetworkForwarder rootDir localSock = do dpRequestors <- initDataPointRequestors propNetwork' rootDir ( launchForwardersSimple Initiator localSock 1000 10000 - , doRunCardanoTracer config brake dpRequestors + , doRunCardanoTracer config Nothing brake dpRequestors ) propNetwork'