{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-} -- | Settings are centralized, as much as possible, into this file. This -- includes database connection settings, static file locations, etc. -- In addition, you can configure a number of different aspects of Yesod -- by overriding methods in the Yesod typeclass. That instance is -- declared in the Foundation.hs file. module Settings where import Startlude import qualified Control.Effect.Labelled as Fused import qualified Control.Exception as Exception import Data.Aeson import Data.FileEmbed ( embedFile ) import Data.Yaml ( decodeEither' ) import Database.Persist.Sqlite ( SqliteConf(..) ) import Network.Wai.Handler.Warp ( HostPreference ) import Yesod.Default.Config2 ( applyEnvValue , configSettingsYml ) import Lib.Types.Emver import Lib.Types.Emver.Orphans ( ) -- | Runtime settings to configure this application. These settings can be -- loaded from various sources: defaults, environment variables, config files, -- theoretically even a database. data AppSettings = AppSettings { appDatabaseConf :: SqliteConf -- ^ Configuration settings for accessing the database. , appHost :: HostPreference -- ^ Host/interface the server should bind to. , appPort :: Word16 -- ^ Port to listen on , appIpFromHeader :: Bool -- ^ Get the IP address from the header when logging. Useful when sitting -- behind a reverse proxy. , appDetailedRequestLogging :: Bool -- ^ Use detailed request logging system , appShouldLogAll :: Bool -- ^ Should all log messages be displayed? , appMgrVersionSpec :: VersionRange , appFilesystemBase :: Text , appTorSocksPort :: Word16 -- ^ Port on localhost where the tor client is listening, defaults to 9050 , appTorRestartCooldown :: NominalDiffTime } deriving Show instance FromJSON AppSettings where parseJSON = withObject "AppSettings" $ \o -> do appDatabaseConf <- o .: "database" >>= withObject "database conf" (\db -> do dbName <- db .: "database" poolSize <- db .: "poolsize" pure $ SqliteConf dbName poolSize ) appHost <- fromString <$> o .: "host" appPort <- o .: "port" appIpFromHeader <- o .: "ip-from-header" appDetailedRequestLogging <- o .:? "detailed-logging" .!= False appShouldLogAll <- o .:? "should-log-all" .!= False appMgrVersionSpec <- o .: "app-mgr-version-spec" appFilesystemBase <- o .: "filesystem-base" appTorSocksPort <- o .:? "tor-socks-port" .!= 9050 appTorRestartCooldown <- o .:? "tor-restart-cooldown" .!= (secondsToNominalDiffTime 600) return AppSettings { .. } -- | Raw bytes at compile time of @config/settings.yml@ configSettingsYmlBS :: ByteString configSettingsYmlBS = $(embedFile configSettingsYml) -- | @config/settings.yml@, parsed to a @Value@. configSettingsYmlValue :: Value configSettingsYmlValue = either Exception.throw id $ decodeEither' configSettingsYmlBS -- | A version of @AppSettings@ parsed at compile time from @config/settings.yml@. compileTimeAppSettings :: AppSettings compileTimeAppSettings = case fromJSON $ applyEnvValue False mempty configSettingsYmlValue of Error e -> panic $ toS e Success settings -> settings injectSettings :: Monad m => AppSettings -> Fused.Labelled "appSettings" (ReaderT AppSettings) m a -> m a injectSettings s = flip runReaderT s . Fused.runLabelled @"appSettings"