Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTView: CPU usage (GC + App) as pct, https by default, errors export #3934

Merged
merged 6 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ source-repository-package

source-repository-package
type: git
location: https://github.com/HeinrichApfelmus/threepenny-gui
tag: e3bb8283fc7d2e8aa374eea29426002e8dcd67a8
--sha256: 0nf836b552asgpwn2gxwl7yd7ssdhb1wkvdqz6s4dpzqnlpyivx9
location: https://github.com/denisshevchenko/threepenny-gui
tag: 4ec92ded05ccf59ba4a874be4b404ac1b6d666b6
--sha256: 00fvvaf4ir4hskq4a6gggbh2wmdvy8j8kn6s4m1p1vlh8m8mq514

-- Drops an instance breaking our code. Should be released to Hackage eventually.
source-repository-package
Expand All @@ -336,6 +336,9 @@ constraints:
-- that dependency
, network >= 3.1.1.0

package snap-server
flags: +openssl

package comonad
flags: -test-doctests

Expand Down
2 changes: 2 additions & 0 deletions cardano-tracer/cardano-tracer.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ library
Cardano.Tracer.Handlers.Metrics.Utils

Cardano.Tracer.Handlers.RTView.Run
Cardano.Tracer.Handlers.RTView.SSL.Certs
Cardano.Tracer.Handlers.RTView.State.Displayed
Cardano.Tracer.Handlers.RTView.State.EraSettings
Cardano.Tracer.Handlers.RTView.State.Errors
Expand Down Expand Up @@ -100,6 +101,7 @@ library
other-modules: Paths_cardano_tracer

build-depends: aeson
, aeson-pretty
, async
, async-extras
, blaze-html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import System.Remote.Monitoring (forkServerWith, serverThreadId)
import System.Time.Extra (sleep)

import Cardano.Tracer.Configuration (Endpoint (..))
import Cardano.Tracer.Handlers.RTView.SSL.Certs (placeDefaultSSLFiles)
import Cardano.Tracer.Types (AcceptedMetrics, ConnectedNodes, NodeId (..))

-- | 'ekg' package allows to run only one EKG server, to display only one web page
Expand All @@ -43,13 +44,17 @@ runMonitoringServer
runMonitoringServer (Endpoint listHost listPort, monitorEP) connectedNodes acceptedMetrics = do
-- Pause to prevent collision between "Listening"-notifications from servers.
sleep 0.2
UI.startGUI config $ \window -> do
(certFile, keyFile) <- placeDefaultSSLFiles
UI.startGUI (config certFile keyFile) $ \window -> do
void $ return window # set UI.title "EKG Monitoring Nodes"
void $ mkPageBody window connectedNodes monitorEP acceptedMetrics
where
config = UI.defaultConfig
{ UI.jsPort = Just . fromIntegral $ listPort
, UI.jsAddr = Just . encodeUtf8 . T.pack $ listHost
config cert key = UI.defaultConfig
{ UI.jsSSLBind = Just . encodeUtf8 . T.pack $ listHost
, UI.jsSSLPort = Just . fromIntegral $ listPort
, UI.jsSSLCert = Just cert
, UI.jsSSLKey = Just key
, UI.jsLog = const $ return ()
}

-- | We have to keep an id of the node as well as thread id of currently launched EKG server.
Expand Down
20 changes: 14 additions & 6 deletions cardano-tracer/src/Cardano/Tracer/Handlers/RTView/Run.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}

module Cardano.Tracer.Handlers.RTView.Run
( runRTView
Expand All @@ -14,8 +15,9 @@ import qualified Graphics.UI.Threepenny as UI
import System.Time.Extra (sleep)

import Cardano.Tracer.Configuration
import Cardano.Tracer.Handlers.RTView.State.EraSettings
import Cardano.Tracer.Handlers.RTView.SSL.Certs
import Cardano.Tracer.Handlers.RTView.State.Displayed
import Cardano.Tracer.Handlers.RTView.State.EraSettings
import Cardano.Tracer.Handlers.RTView.State.Errors
import Cardano.Tracer.Handlers.RTView.State.Historical
import Cardano.Tracer.Handlers.RTView.State.Last
Expand Down Expand Up @@ -48,6 +50,8 @@ runRTView TracerConfig{logging, network, hasRTView}
whenJust hasRTView $ \(Endpoint host port) -> do
-- Pause to prevent collision between "Listening"-notifications from servers.
sleep 0.3
-- Get paths to default SSL files for config.
(certFile, keyFile) <- placeDefaultSSLFiles
-- Initialize displayed stuff outside of main page renderer,
-- to be able to update corresponding elements after page reloading.
displayedElements <- initDisplayedElements
Expand All @@ -64,7 +68,7 @@ runRTView TracerConfig{logging, network, hasRTView}
errors <- initErrors

void . sequenceConcurrently $
[ UI.startGUI (config host port) $
[ UI.startGUI (config host port certFile keyFile) $
mkMainPage
connectedNodes
displayedElements
Expand Down Expand Up @@ -96,8 +100,12 @@ runRTView TracerConfig{logging, network, hasRTView}
savedTO
]
where
config h p = UI.defaultConfig
{ UI.jsPort = Just . fromIntegral $ p
, UI.jsAddr = Just . encodeUtf8 . T.pack $ h
, UI.jsLog = const $ return () -- To hide 'threepenny-gui' internal messages.
-- RTView's web page is available via 'https://' url only.
config h p cert key = UI.defaultConfig
{ UI.jsSSLBind = Just . encodeUtf8 . T.pack $ h
, UI.jsSSLPort = Just . fromIntegral $ p
, UI.jsSSLCert = Just cert
, UI.jsSSLKey = Just key
, UI.jsLog = const $ return () -- To hide 'threepenny-gui' internal messages.
, UI.jsWindowReloadOnDisconnect = False
}
123 changes: 123 additions & 0 deletions cardano-tracer/src/Cardano/Tracer/Handlers/RTView/SSL/Certs.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}

module Cardano.Tracer.Handlers.RTView.SSL.Certs
( placeDefaultSSLFiles
) where

import Control.Monad.Extra (unlessM)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.String.QQ
import qualified System.Directory as D

import Cardano.Tracer.Handlers.RTView.System

placeDefaultSSLFiles :: IO (FilePath, FilePath)
placeDefaultSSLFiles = do
(pathToCertFile, pathToKeyFile) <- getPathsToSSLCerts
writeIfNeeded pathToCertFile defaultCert
writeIfNeeded pathToKeyFile defaultKey
-- Set permissions like 'openssl' does.
D.setPermissions pathToCertFile (D.setOwnerWritable True $ D.emptyPermissions { D.readable = True }) -- 0644
D.setPermissions pathToKeyFile (D.setOwnerWritable True . D.setOwnerReadable True $ D.emptyPermissions) -- 0600
return (pathToCertFile, pathToKeyFile)
where
writeIfNeeded p f = unlessM (D.doesFileExist p) $ BS.writeFile p f

-- By default we use self-signed 'cert.pem' certificate and 'key.pem' key created
-- by 'openssl' program. Example of the command:
--
-- $ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes

defaultCert :: ByteString
defaultCert = [s|
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUNIm8PPV3chKFhFj/A/nd4cdHWJIwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjA1MjQwODA5MTRaFw0yMzA1
MjQwODA5MTRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQC59W9J7xYp+6RaTla/wIZja5A7mpl+3KSHTvSOds34
jGigw7aAM8VzUGG7Gkx3oFq5LmB1i4GwTsaUHtPLgvbkkwzz83B0ZIr9Ox5uhVa+
m7pYpAgKhMjLRc11KF2cIfM8NOqDwmwM/+c1SsDegSVFViJrEwFUfQTeYjG7mbLB
wia4pzEj6Ou3URRFCoCxBon/4/321vieDVsK+eLEUHFROyLXDkIQGcDhbsbQLt0r
GZ2chlpSJvzJorn0/tWM8VNZCfKu6sab58HT+TgJDTZ9lwIbeMNWPB3zHTGurxkB
w8Po48tlz41kiArKiWF9vgB9ObY3AY8l2CWKASPhGwYW1Ndkeqn+78oB29HY92oJ
LozBA5kkDQgbo51lQlobGRVsS6cotu3iqIUHigjbXH1+/Nch2eRPxg/5OcdBpPix
qQJOP7GM+krNt3iDA9DkFGKWTf11p0eZRODWE+ACJU5tQY9QaCQ4d2HKGZm4gWdz
Vedvck2GhdnZi9RzL0UVRUzkTpEf6nIChn8lZP0+48c69E6DHV9xXB4mNTkuHYEO
iQ8EVQDXIxjRVUjDaccxs6snAewWOygySweXjc0XFEdogMfzldpeS669HWcmMbbt
dkEUy6zC11dKVaHn1Ou9sjz1mnzHXAjrDEcsPy7SFabqLxRnrhRRs948RFvjQzYp
QwIDAQABo1MwUTAdBgNVHQ4EFgQUsAwUYTw3B5PyadhB/nYduV8HDgEwHwYDVR0j
BBgwFoAUsAwUYTw3B5PyadhB/nYduV8HDgEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAgakOs52QWC/jGDbLxMD55Xj3WtG0jwZM+1RzFeIemEMK
3pspcyNUVM+CoAMrCilH5es+giFvbo3KDS/wYLMkAYJNdSSoj3OQq7PBrkt2lkCi
NBF3Ul4Mip1jMVwgzyFNqNCQaz/y/Hdm+4GQ1vJlLEKhOL3h8b5icK0+jgY81PiC
th5wlE26JyVD+smYg25VMqcTYyFNSZ/I4bPE2isxWw3EXOrBtP8MwqsPw1swWyD2
9pQx2evU+XDNvQ3cN/q9lZckbH5qytxNCGds5PO249bE1WRZLznLj/VDKFSTyYul
CR7Qcg6GguwxMmIYCfkHaF+ivOEtJGs5JKaCXxjBsOvxW6exxDe1aTmU4C+GpTeU
1HPowrfp5HzRP9BbDV37//w1dFcLp3cxKpOjFpVfpv9YUH6FvQid57OeC7kIq90N
Zi4jxHH7DV5DozLARlp61CKSuV6LbBNqDywtwoZPK9TNCqvdXa504hFw4KpdRWPi
A8Lr1iudUNDxwq+bbSrxPUKL1i/6h/yU5nz469iMUzgKtJkhpbT6kaz9zBgClxeG
GZHU7nKd8Ay85+b59RM7hrkc9miSgyY/uLaUHN1klYllbtBJvpR1MPQbcNSny09x
gx0QcX6nEDv/K8XuOvzndTRCuOB9R6ly0i+hfrTXi2FnlOnZ93U6FfrRXagsTrk=
-----END CERTIFICATE-----
|]

defaultKey :: ByteString
defaultKey = [s|
-----BEGIN PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQC59W9J7xYp+6Ra
Tla/wIZja5A7mpl+3KSHTvSOds34jGigw7aAM8VzUGG7Gkx3oFq5LmB1i4GwTsaU
HtPLgvbkkwzz83B0ZIr9Ox5uhVa+m7pYpAgKhMjLRc11KF2cIfM8NOqDwmwM/+c1
SsDegSVFViJrEwFUfQTeYjG7mbLBwia4pzEj6Ou3URRFCoCxBon/4/321vieDVsK
+eLEUHFROyLXDkIQGcDhbsbQLt0rGZ2chlpSJvzJorn0/tWM8VNZCfKu6sab58HT
+TgJDTZ9lwIbeMNWPB3zHTGurxkBw8Po48tlz41kiArKiWF9vgB9ObY3AY8l2CWK
ASPhGwYW1Ndkeqn+78oB29HY92oJLozBA5kkDQgbo51lQlobGRVsS6cotu3iqIUH
igjbXH1+/Nch2eRPxg/5OcdBpPixqQJOP7GM+krNt3iDA9DkFGKWTf11p0eZRODW
E+ACJU5tQY9QaCQ4d2HKGZm4gWdzVedvck2GhdnZi9RzL0UVRUzkTpEf6nIChn8l
ZP0+48c69E6DHV9xXB4mNTkuHYEOiQ8EVQDXIxjRVUjDaccxs6snAewWOygySweX
jc0XFEdogMfzldpeS669HWcmMbbtdkEUy6zC11dKVaHn1Ou9sjz1mnzHXAjrDEcs
Py7SFabqLxRnrhRRs948RFvjQzYpQwIDAQABAoICAQCwsQtYhctagtdsUylMM6O9
zdOTPteAWigexR/MSgh1lPxJXQ0IjaicZBEoldl4hS4O7IkMx0yn+IHo9c2qfrsW
/r59AZ+liG8kJEtLGnkMza1nUhyt2fNsadvJ6Vvg4cVbPLBkF5VRWMoYsfnGsZF3
a1tyv/EwlUXOBCFbLrRSNKdUJtCjXUqzuV94Jn2XNy5irQB/zU0X6HrMWBlnDURO
udDl5I9S+xVxXi+cWhseO82tj1881fy1nl/w8T56GEdov/IOz9d9Bd3/Crt6pkpT
VOvUrI92XdLbUK8HWyp4qcl5fRCjoW2oyzbtsVGoB6QxWGfRpjKc897fXSv5VRMX
dybTsJod9lTZnQ/oABlfNpg58b/CiUFZO1Zf/+M5o/9CTRrjC0pmP2+9aw059wDi
7FPNaqz1fBSUNdb/SF4w0LzofItE68n1JJTRW4jscOBIo5NzsfMnPDjW0VGfpFbY
vdhIpuWVuyObdsIkaBFSXMej8oUjOnn4Wx4UIijf9z753Asy7R37BcNuSplUJY9w
Jhv0OSq8lBPHgiUKPwcLJhcpMjGkakTa3fyrqgzi/s+KDBmPLcQzVvbtJyHITg3t
KWrfzweC5xXDG/dUMIuYdwBliKnpqEapMOUJkIEUtjRtSTBglyehj8wE7CgiouBL
Y46zcXRbTxFG2VX2KJip6QKCAQEA9O6+yZyFwB9mgJ6kNfm2tzYrFVmd7C1amcfu
ykFds49GofhVHQMkaLX5F7ttcSdY7BQH1XH9jRAyeIvTKqB5EilNCIzYiR/ekIQT
BUfTUpZOgKaPQcKSOfjJuSJa+YhLSEKl79t63oDmHx1iBCuP2YTVSLvhr150eOZP
3vs385bN4B8L1W6KwFRNVqP1PgdXHWljw2CvgJU5HtXzTxZ8b4vR5dcPi77o8rgG
gRWsXpyeNDIPOtfzvcq2Ryh1iWIIwIGmloHV/CHWbYD3GeZSipgl/klV97pO0NpW
skZ3eBqsULjy8MhIqTPZlyHRMmEI11EWKOxdFqhdqKAhXUyRZwKCAQEAwlyCjXbF
lqUtJr6tgGqp/acvWO+APLQM7g+lL6imR3begtt1syDXsG5yceFnJK+7sNszpM4l
LXWIUHPX0oh/G0py1+QcI6d0VxVNM25p3XmLEFQvgYyrUbLZ11dafdls8+GInl44
8leP5s/P8x6qWIY74OwG0o4c+Uib7Ep/Qv1js/BUTcZ/Aao3gKI/bYUpGbH7zG9a
It5aAqgH5hQQoztYxtL1sF2sRQRXqr3XbFbyfgf+FT7UVm2TNfLFtl2MOBIicsZi
a7VchP6KluBZuZAkEr18KnZHbmf9tdwwY1BaU3KpbnZZw2ln0+QUJNpZpkrINcKL
d8KmLnVCRZ9zxQKCAQEAqT6TfLJ4RUItTPDR3S4Y0E5QxObw1bKdKSfa280BF0MI
doEnJu316Zjcb0amoAqlSjOpGhczMZcgmOVdW9YY8rCxNxhDw7TO0KNClWKFJksQ
IZt13+W3rvE3SoLvw/8mrd7H1I6fP0JoQNXH1cPYGWDNE/4nO0uURbo3NIf4qIvq
5FPvlGJW5AEck6Klol/mFT+unOGhQ8NY/fKutlZ+U4GU3zGU32Ziht0cOXQlcBbe
xohUt79jACEjhNXzKaQhEgxEdTlwCFHFXlM/65iYLoZlsmkwSwZk0bIdOACzKr2b
lgfGbxSmCKz4TJMkf6BHQKkaG9r/k9lxJkTH6TUwPwKCAQAm1F6Mro7ZAtTbabq1
7hlaAJ2X8fk3p2zx3pRMyi+2FUxs7jU8fTI6IEai87osfSNNOO2/XiPVSibak9op
SHXEWQJKmVr50ImQoEPVI5jo01ByCa+X/Sd44fddayk7/UUkEAnAQei0mcO5BAly
c8zqdJ7f16ehRx0IvHXSJiv4kTDrEPd2tlJHXd9Kxp9PXQwSAxngBNsIHk3zO+ig
EaAlTET3K8xD2OMCwtRU2yp/jXtSrHwZeHzpa2i+nWrcfSH3TcAuF+4vwILkWwoL
DHVAekiKqep1fT3WE9Z/D6dnH/V7uGubEu/p91Pz5BwWJL1GWKhY/S3p1ixnGawM
xsdVAoIBAQDK4JvIaKB77zrlVataKOcS0TJcXek22le+9rEUNB+6cFmG9gB5s0Kw
1MlbXdHE/P3D5tZMYt+Q9XdW1tb/g3BJoy0DINGmRnlCTwMtIC8fX6vWpNFBLDJ2
XjrTq4YI7ivIbxXFb+kkSMVolBnlRHfBUBUoshx5UoN5J56jGngq0Ne10HIAuLzm
S+g6oAs1m2EE4ZJEEjh4UoVh3hjF+0I2+fVRnmC/qTLr8o3F9JhlWYk2OZii9Plo
6OXwDhD8RieMUu7rDRD59ONr1n0j0U/WQqMfkK87glDni7HolzDx3pLWDOSWgYaI
+Jz2VtvTX0rLiK/CnJ59JvIpniHtAIgf
-----END PRIVATE KEY-----
|]

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE StandaloneDeriving #-}

module Cardano.Tracer.Handlers.RTView.State.Errors
( ErrorIx
Expand All @@ -16,15 +18,20 @@ module Cardano.Tracer.Handlers.RTView.State.Errors
, severityDesc
, initErrors
, deleteAllErrors
, errorsToJSON
) where

import Control.Concurrent.STM (atomically)
import Control.Concurrent.STM.TVar
import Control.Concurrent.STM.TVar (TVar, modifyTVar', newTVarIO, readTVarIO)
import Data.Aeson (ToJSON)
import Data.Aeson.Encode.Pretty (encodePretty)
import qualified Data.ByteString.Lazy as BSL
import Data.List (find, sortBy)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.Text (Text, isInfixOf)
import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8)

import Cardano.Tracer.Handlers.RTView.State.TraceObjects
import Cardano.Tracer.Types (NodeId)
Expand All @@ -35,6 +42,9 @@ type ErrorIx = Int
type ErrorInfo = (ErrorIx, TraceObjectInfo)
type Errors = TVar (Map NodeId [ErrorInfo])

-- | We need it to export errors list to JSON-file.
deriving instance ToJSON SeverityS

initErrors :: IO Errors
initErrors = newTVarIO M.empty

Expand Down Expand Up @@ -130,3 +140,14 @@ getErrorsHandled errors nodeId handler = do
case M.lookup nodeId errors' of
Nothing -> return []
Just errorsFromNode -> return $ handler errorsFromNode

errorsToJSON
:: Errors
-> NodeId
-> IO (Maybe Text)
errorsToJSON errors nodeId =
getErrors errors nodeId >>= \case
[] -> return Nothing
errorsFromNode -> do
let errorsList = [eI | (_ix, eI) <- errorsFromNode]
return . Just . decodeUtf8 . BSL.toStrict $ encodePretty errorsList
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import qualified Data.Map.Strict as M
import Data.Set (Set)
import qualified Data.Set as S
import Data.Text (Text)
import Data.Text.Read
import Data.Text.Read (decimal, double)
import Data.Time.Clock (UTCTime)
import Data.Word (Word64)

Expand Down
16 changes: 12 additions & 4 deletions cardano-tracer/src/Cardano/Tracer/Handlers/RTView/State/Last.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ import Cardano.Tracer.Types (NodeId)
-- rendering on the corresponding chart.

data LastResourcesForNode = LastResourcesForNode
{ cpuLastTicks :: !Int
, cpuLastNS :: !Word64
{ cpuLastTicks :: !Int
, cpuLastNS :: !Word64
, cpuGCLastTicks :: !Int
, cpuGCLastNS :: !Word64
, cpuAppLastTicks :: !Int
, cpuAppLastNS :: !Word64
}

type LastResources = TVar (Map NodeId LastResourcesForNode)
Expand All @@ -40,8 +44,12 @@ addNullResources lastResources nodeId = atomically $
where
nulls =
LastResourcesForNode
{ cpuLastTicks = 0
, cpuLastNS = 0
{ cpuLastTicks = 0
, cpuLastNS = 0
, cpuGCLastTicks = 0
, cpuGCLastNS = 0
, cpuAppLastTicks = 0
, cpuAppLastNS = 0
}

updateLastResources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Data.Maybe (mapMaybe)
import Data.Text (Text, intercalate)
import Data.Time.Clock (UTCTime)

import Cardano.Logging (TraceObject (..), SeverityS)
import Cardano.Logging (SeverityS, TraceObject (..))

import Cardano.Tracer.Types (NodeId)

Expand Down
25 changes: 20 additions & 5 deletions cardano-tracer/src/Cardano/Tracer/Handlers/RTView/System.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
module Cardano.Tracer.Handlers.RTView.System
( getPathToChartsConfig
, getPathToThemeConfig
, getPathsToSSLCerts
, getProcessId
) where

import Data.Word (Word32)
import Graphics.UI.Threepenny.Core
import System.Directory
import Graphics.UI.Threepenny.Core (UI, liftIO)
import qualified System.Directory as D
import System.FilePath ((</>))

#if defined(mingw32_HOST_OS)
Expand All @@ -33,7 +34,21 @@ getPathToThemeConfig = getPathToConfig "theme"

getPathToConfig :: FilePath -> IO FilePath
getPathToConfig configName = do
configDir <- getXdgDirectory XdgConfig ""
configDir <- getPathToConfigDir
return $ configDir </> configName

getPathsToSSLCerts :: IO (FilePath, FilePath)
getPathsToSSLCerts = do
configDir <- getPathToConfigDir
let pathToSSLSubDir = configDir </> "ssl"
D.createDirectoryIfMissing True pathToSSLSubDir
return ( pathToSSLSubDir </> "cert.pem"
, pathToSSLSubDir </> "key.pem"
)

getPathToConfigDir :: IO FilePath
getPathToConfigDir = do
configDir <- D.getXdgDirectory D.XdgConfig ""
let pathToRTViewConfigDir = configDir </> "cardano-rt-view"
createDirectoryIfMissing True pathToRTViewConfigDir
return $ pathToRTViewConfigDir </> configName
D.createDirectoryIfMissing True pathToRTViewConfigDir
return pathToRTViewConfigDir
Loading