zwirn-0.2.3.1: app/zwirnzi/CI/ConfigDoux.hs
{-# OPTIONS_GHC -Wno-orphans #-}
module CI.ConfigDoux where
import Conferer (fetch, mkConfig')
import Conferer.Config ((/.))
import Conferer.FromConfig (DefaultConfig (..))
import qualified Conferer.FromConfig as Conf
import qualified Conferer.Source.CLIArgs as Cli
import qualified Conferer.Source.Env as Env
import qualified Conferer.Source.Yaml as Yaml
import Control.Monad (unless)
import qualified Data.ByteString.Lazy.UTF8 as BL
import Data.Maybe (fromMaybe)
import Data.Ratio ((%))
import qualified Data.Text as T
import Data.Yaml (ToJSON (..), encodeFile, object, (.=))
import System.Directory.OsPath
import System.File.OsPath as F
import System.OsPath
import Zwirn.Doux.Types (defaultDouxClockConfig)
import qualified Zwirn.Doux.Types as Stream
import Zwirn.Language (StreamType (Doux))
import Zwirn.Language.Compiler (CIError (..), Environment (..), compilerInterpreterBoot, runCI)
import qualified Zwirn.Language.Compiler as Compiler
import Prelude hiding (log)
data StreamConfig = StreamConfig
{ streamConfigSamples :: Maybe FilePath,
streamConfigInput :: Maybe String,
streamConfigOutput :: Maybe String,
streamConfigHost :: Maybe String,
streamConfigBufferSize :: Int,
streamConfigChannels :: Int,
streamConfigBlockSize :: Int,
streamConfigMaxVoices :: Int
}
deriving (Show)
data CiConfig = CiConfig
{ ciConfigBootPath :: FilePath,
ciConfigCli :: Bool,
ciConfigOverwriteBuiltin :: Bool,
ciConfigDynamicTypes :: Bool,
ciConfigPrecision :: Int
}
deriving (Show)
data FullConfig = FullConfig
{ fullConfigCi :: CiConfig,
fullConfigStream :: StreamConfig
}
deriving (Show)
instance DefaultConfig CiConfig where
configDef = CiConfig "" False False False 200
instance DefaultConfig StreamConfig where
configDef = StreamConfig Nothing Nothing Nothing Nothing 256 2 32 32
instance DefaultConfig FullConfig where
configDef = FullConfig configDef configDef
instance Conf.FromConfig StreamConfig where
fromConfig key configSource = do
path <- Conf.fetchFromConfig (key /. "samples") configSource
input <- Conf.fetchFromConfig (key /. "input") configSource
output <- Conf.fetchFromConfig (key /. "output") configSource
host <- Conf.fetchFromConfig (key /. "host") configSource
bs <- Conf.fetchFromConfig (key /. "buffersize") configSource
cs <- Conf.fetchFromConfig (key /. "channels") configSource
bl <- Conf.fetchFromConfig (key /. "blocksize") configSource
mx <- Conf.fetchFromConfig (key /. "maxvoices") configSource
return $ StreamConfig path input output host (fromMaybe 256 bs) (fromMaybe 2 cs) (fromMaybe 32 bl) (fromMaybe 32 mx)
instance Conf.FromConfig CiConfig where
fromConfig key configSource = do
path <- Conf.fetchFromConfig (key /. "bootpath") configSource
cli <- Conf.fetchFromConfig (key /. "cli") configSource
bp <- Conf.fetchFromConfig (key /. "overwritebuiltin") configSource
dt <- Conf.fetchFromConfig (key /. "dynamictypes") configSource
prec <- Conf.fetchFromConfig (key /. "precision") configSource
return $ CiConfig (fromMaybe "" path) (fromMaybe False cli) (fromMaybe False bp) (fromMaybe False dt) (fromMaybe 200 prec)
instance Conf.FromConfig FullConfig where
fromConfig key configSource = do
ci <- Conf.fetchFromConfig (key /. "ci") configSource
str <- Conf.fetchFromConfig (key /. "stream") configSource
return $ FullConfig ci (fromMaybe configDef str)
instance ToJSON CiConfig where
toJSON (CiConfig p cli o d prec) =
object
[ "bootpath" .= p,
"cli" .= cli,
"overwritebuiltin" .= o,
"dynamictypes" .= d,
"precision" .= prec
]
instance ToJSON StreamConfig where
toJSON (StreamConfig sam inp out host buf chan block maxv) =
object
[ "samples" .= sam,
"host" .= host,
"input" .= inp,
"output" .= out,
"buffersize" .= buf,
"channels" .= chan,
"blocksize" .= block,
"maxvoices" .= maxv
]
instance ToJSON FullConfig where
toJSON (FullConfig ci str) =
object
[ "ci" .= toJSON ci,
"stream" .= toJSON str
]
getConfigPath :: IO OsPath
getConfigPath = do
appname <- encodeUtf "zwirnzi"
configname <- encodeUtf "config-doux.yaml"
configDirPath <- getXdgDirectory XdgConfig appname
let path = configDirPath </> configname
createDirectoryIfMissing True configDirPath
return path
getConfig :: IO FullConfig
getConfig = do
path <- getConfigPath
exists <- doesFileExist path
unless exists encodeDefault
decoded <- decodeUtf path
conf <-
mkConfig'
[]
[ Cli.fromConfig,
Env.fromConfig "zwirnzi",
Yaml.fromFilePath decoded
]
fetch conf
toStream :: Rational -> StreamConfig -> Stream.StreamConfig
toStream prec (StreamConfig a b c d e f g h) = Stream.StreamConfig prec a b c d e f g h defaultDouxClockConfig
toCiConfig :: CiConfig -> Compiler.CiConfig
toCiConfig (CiConfig _ _ x y z) = Compiler.CiConfig x y (1 % fromIntegral z) Doux
configPath :: IO String
configPath = do
path <- getConfigPath
exists <- doesFileExist path
decoded <- decodeUtf path
if exists then return decoded else return "Config file not found!"
resetConfig :: IO String
resetConfig = encodeDefault >> return "Restored default config."
encodeDefault :: IO ()
encodeDefault = encodeConfig configDef
encodeConfig :: FullConfig -> IO ()
encodeConfig conf = do
path <- getConfigPath
strp <- decodeFS path
encodeFile strp $ toJSON conf
getFile :: String -> IO String
getFile p = do
path <- encodeUtf p
f <- F.readFile path
return $ BL.toString f
checkBoot :: (String -> IO ()) -> FilePath -> Environment -> IO (Maybe Environment)
checkBoot log "" _ = log "Starting without Bootfile." >> return Nothing
checkBoot log path env = do
ospath <- encodeUtf path
isfile <- doesFileExist ospath
ps <-
if isfile
then return $ decodeUtf ospath
else do
isfolder <- doesDirectoryExist ospath
if isfolder
then do
pss <- listDirectory ospath
fs <- mapM decodeUtf pss
return $ map (\f -> path ++ "/" ++ f) fs
else return []
res <- runCI env (compilerInterpreterBoot $ map T.pack ps)
case res of
Left (CIError err _) -> log ("Error in Bootfile: " ++ show err) >> return Nothing
Right newEnv ->
if ps /= []
then log ("Successfully loaded Bootfiles from " ++ path) >> return (Just newEnv)
else log ("No Bootfiles found at " ++ path) >> return Nothing
cliMode :: FullConfig -> Bool
cliMode = ciConfigCli . fullConfigCi