packages feed

zwirn-0.2.2.1: app/zwirnzi/CI/Config.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module CI.Config where

{-
    CommandLine.hs - configuration
    Copyright (C) 2023, Martin Gius

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
-}

import Conferer as Conf
import Conferer.Source.CLIArgs as Cli
import Conferer.Source.Env as Env
import Conferer.Source.Yaml as Yaml
import Control.Monad (unless)
import qualified Data.ByteString.Lazy.UTF8 as BL
import qualified Data.Text as T
import GHC.Generics (Generic)
import qualified Sound.Tidal.Clock as Clock (ClockConfig (..), defaultConfig)
import System.Directory.OsPath
import System.File.OsPath as F
import System.OsPath
import qualified Zwirn.Language.Compiler as Compiler
import qualified Zwirn.Stream.Target as Stream
import qualified Zwirn.Stream.Types as Stream

data ClockConfig = ClockConfig
  { clockConfigQuantum :: Double,
    clockConfigBeatsPerCycle :: Double,
    clockConfigFrameTimespan :: Double,
    clockConfigEnableLink :: Bool,
    clockConfigSkipTicks :: Int,
    clockConfigProcessAhead :: Double
  }
  deriving (Show, Generic)

data TargetConfig = TargetConfig
  { targetConfigName :: T.Text,
    targetConfigOSCPath :: T.Text,
    targetConfigBusOSCPath :: T.Text,
    targetConfigAddress :: String,
    targetConfigPort :: Int,
    targetConfigBusPort :: Maybe Int
  }
  deriving (Show, Generic)

data StreamConfig = StreamConfig
  { streamConfigTargets :: [TargetConfig],
    streamConfigDefaultTarget :: T.Text,
    streamConfigLocalPort :: Int,
    streamConfigPrecision :: Rational,
    streamConfigClock :: ClockConfig
  }
  deriving (Show, Generic)

data CiConfig = CiConfig
  { ciConfigBootPath :: FilePath,
    ciConfigListener :: Bool,
    ciConfigCli :: Bool,
    ciConfigOverwriteBuiltin :: Bool,
    ciConfigDynamicTypes :: Bool
  }
  deriving (Generic)

data FullConfig = FullConfig
  { fullConfigCi :: CiConfig,
    fullConfigClock :: ClockConfig,
    fullConfigStream :: StreamConfig
  }
  deriving (Generic)

instance DefaultConfig TargetConfig where
  configDef = TargetConfig "superdirt" "/dirt/play" "/c_set" "127.0.0.1" 57120 (Just 57110)

instance DefaultConfig CiConfig where
  configDef = CiConfig "" False False False False

instance DefaultConfig StreamConfig where
  configDef = StreamConfig [configDef] "superdirt" 2323 0.005 configDef

instance DefaultConfig ClockConfig where
  configDef = fromClock Clock.defaultConfig

instance DefaultConfig FullConfig where
  configDef = FullConfig configDef configDef configDef

instance FromConfig TargetConfig

instance FromConfig CiConfig

instance FromConfig StreamConfig

instance FromConfig ClockConfig

instance FromConfig FullConfig

getConfig :: IO Conf.Config
getConfig = do
  home <- getHomeDirectory
  configDirPath <- (home <>) <$> encodeUtf "/.config/zwirnzi/"
  path <- (home <>) <$> encodeUtf "/.config/zwirnzi/config.yaml"
  createDirectoryIfMissing True configDirPath
  exists <- doesFileExist path
  unless exists (F.writeFile path defaultConfigFile)
  decoded <- decodeUtf path
  mkConfig'
    []
    [ Cli.fromConfig,
      Env.fromConfig "zwirnzi",
      Yaml.fromFilePath decoded
    ]

fromClock :: Clock.ClockConfig -> ClockConfig
fromClock (Clock.ClockConfig a b c d e f) = ClockConfig (realToFrac a) (realToFrac b) c d (fromIntegral e) f

toClock :: ClockConfig -> Clock.ClockConfig
toClock (ClockConfig a b c d e f) = Clock.ClockConfig (realToFrac a) (realToFrac b) c d (fromIntegral e) f

toTarget :: TargetConfig -> Stream.TargetConfig
toTarget (TargetConfig a b c d e f) = Stream.TargetConfig a b c d e f

toStream :: StreamConfig -> Stream.StreamConfig
toStream (StreamConfig a b c d e) = Stream.StreamConfig (map toTarget a) b c d (toClock e)

toCiConfig :: CiConfig -> Compiler.CiConfig
toCiConfig (CiConfig _ _ _ x y) = Compiler.CiConfig x y

configPath :: IO String
configPath = do
  home <- getHomeDirectory
  path <- (home <>) <$> encodeUtf "/.config/zwirnzi/config.yaml"
  exists <- doesFileExist path
  decoded <- decodeUtf path
  if exists then return decoded else return "Config file not found!"

resetConfig :: IO String
resetConfig = do
  home <- getHomeDirectory
  configDirPath <- (home <>) <$> encodeUtf "/.config/zwirnzi/"
  path <- (home <>) <$> encodeUtf "/.config/zwirnzi/config.yaml"
  createDirectoryIfMissing True configDirPath
  F.writeFile path defaultConfigFile
  return "Restored default config."

defaultConfigFile :: BL.ByteString
defaultConfigFile =
  BL.fromString "ci:"
    <|> "  listener: true"
    <|> "  bootpath:  \"\""
    <|> "  overwritebuiltin: false"
    <|> "  dynamictypes: false"
    <|> "stream:"
    <|> "  targets:"
    <|> "    - name: \"superdirt\""
    <|> "      oscpath: \"/dirt/play\""
    <|> "      busoscpath: \"/c_set\""
    <|> "      address: \"127.0.0.1\""
    <|> "      port: 57120"
    <|> "      busport: 57110"
    <|> "  defaulttarget: \"superdirt\""
    <|> "  localport: 52323"
    <|> "  precision: 0.005"
    <|> "  clock:"
    <|> "    quantum: 4"
    <|> "    beatspercycle: 4"
    <|> "    frametimespan: 0.05"
    <|> "    enablelink: false"
    <|> "    skipticks: 10"
    <|> "    processahead: 0.3"
  where
    (<|>) x y = x <> "\n" <> y

getFile :: String -> IO String
getFile p = do
  path <- encodeUtf p
  f <- F.readFile path
  return $ BL.toString f