{-# LANGUAGE OverloadedStrings #-}

module ElectrsClient.Data.Env
  ( ElectrsEnv (..),
    BitcoindEnv (..),
    Env (..),
    RawConfig (..),
    readRawConfig,
    parseFromJSON,
  )
where

import Data.Aeson (withObject, (.:))
import qualified Data.Aeson as A (decode)
import Data.ByteString.Lazy.Char8 as C8L (pack)
import ElectrsClient.Import.External
import qualified Env as E
  ( Error (..),
    Mod,
    Var,
    header,
    help,
    keep,
    nonempty,
    parse,
    var,
  )
import Network.Bitcoin as Btc

data ElectrsEnv = ElectrsEnv
  { ElectrsEnv -> Text
electrsEnvPort :: Text,
    ElectrsEnv -> Text
electrsEnvHost :: Text
  }
  deriving stock ((forall x. ElectrsEnv -> Rep ElectrsEnv x)
-> (forall x. Rep ElectrsEnv x -> ElectrsEnv) -> Generic ElectrsEnv
forall x. Rep ElectrsEnv x -> ElectrsEnv
forall x. ElectrsEnv -> Rep ElectrsEnv x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ElectrsEnv x -> ElectrsEnv
$cfrom :: forall x. ElectrsEnv -> Rep ElectrsEnv x
Generic)

instance FromJSON ElectrsEnv where
  parseJSON :: Value -> Parser ElectrsEnv
parseJSON =
    String
-> (Object -> Parser ElectrsEnv) -> Value -> Parser ElectrsEnv
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject
      String
"ElectrsEnv"
      ( \Object
x ->
          Text -> Text -> ElectrsEnv
ElectrsEnv
            (Text -> Text -> ElectrsEnv)
-> Parser Text -> Parser (Text -> ElectrsEnv)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
x Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"port"
            Parser (Text -> ElectrsEnv) -> Parser Text -> Parser ElectrsEnv
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
x Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"host"
      )

data BitcoindEnv = BitcoindEnv
  { BitcoindEnv -> Text
bitcoindEnvHost :: Text,
    BitcoindEnv -> Text
bitcoindEnvUsername :: Text,
    BitcoindEnv -> Text
bitcoindEnvPassword :: Text
  }
  deriving stock ((forall x. BitcoindEnv -> Rep BitcoindEnv x)
-> (forall x. Rep BitcoindEnv x -> BitcoindEnv)
-> Generic BitcoindEnv
forall x. Rep BitcoindEnv x -> BitcoindEnv
forall x. BitcoindEnv -> Rep BitcoindEnv x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep BitcoindEnv x -> BitcoindEnv
$cfrom :: forall x. BitcoindEnv -> Rep BitcoindEnv x
Generic)

instance FromJSON BitcoindEnv where
  parseJSON :: Value -> Parser BitcoindEnv
parseJSON =
    String
-> (Object -> Parser BitcoindEnv) -> Value -> Parser BitcoindEnv
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject
      String
"BitcoindEnv"
      ( \Object
x ->
          Text -> Text -> Text -> BitcoindEnv
BitcoindEnv
            (Text -> Text -> Text -> BitcoindEnv)
-> Parser Text -> Parser (Text -> Text -> BitcoindEnv)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
x Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"host"
            Parser (Text -> Text -> BitcoindEnv)
-> Parser Text -> Parser (Text -> BitcoindEnv)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
x Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"username"
            Parser (Text -> BitcoindEnv) -> Parser Text -> Parser BitcoindEnv
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
x Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"password"
      )

data Env = Env
  { Env -> ElectrsEnv
envElectrs :: ElectrsEnv,
    Env -> Client
envBtc :: Btc.Client
  }

data RawConfig = RawConfig
  { RawConfig -> ElectrsEnv
rawConfigElectrsEnv :: ElectrsEnv,
    RawConfig -> BitcoindEnv
rawConfigBtcEnv :: BitcoindEnv
  }

parseFromJSON :: (FromJSON a) => String -> Either E.Error a
parseFromJSON :: forall a. FromJSON a => String -> Either Error a
parseFromJSON =
  Either Error a
-> (a -> Either Error a) -> Maybe a -> Either Error a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
    (Error -> Either Error a
forall a b. a -> Either a b
Left (Error -> Either Error a) -> Error -> Either Error a
forall a b. (a -> b) -> a -> b
$ String -> Error
E.UnreadError String
"parseFromJSON failed")
    a -> Either Error a
forall a b. b -> Either a b
Right
    (Maybe a -> Either Error a)
-> (String -> Maybe a) -> String -> Either Error a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe a
forall a. FromJSON a => ByteString -> Maybe a
A.decode
    (ByteString -> Maybe a)
-> (String -> ByteString) -> String -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
C8L.pack

readRawConfig :: IO RawConfig
readRawConfig :: IO RawConfig
readRawConfig =
  (Info Error -> Info Error)
-> Parser Error RawConfig -> IO RawConfig
forall e a. (Info Error -> Info e) -> Parser e a -> IO a
E.parse (String -> Info Error -> Info Error
forall e. String -> Info e -> Info e
E.header String
"ElectrsClient") (Parser Error RawConfig -> IO RawConfig)
-> Parser Error RawConfig -> IO RawConfig
forall a b. (a -> b) -> a -> b
$
    ElectrsEnv -> BitcoindEnv -> RawConfig
RawConfig
      (ElectrsEnv -> BitcoindEnv -> RawConfig)
-> Parser Error ElectrsEnv
-> Parser Error (BitcoindEnv -> RawConfig)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Reader Error ElectrsEnv
-> String -> Mod Var ElectrsEnv -> Parser Error ElectrsEnv
forall e a.
AsUnset e =>
Reader e a -> String -> Mod Var a -> Parser e a
E.var (Reader Error ElectrsEnv
forall a. FromJSON a => String -> Either Error a
parseFromJSON Reader Error ElectrsEnv
-> (String -> Either Error String) -> Reader Error ElectrsEnv
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< String -> Either Error String
forall e s. (AsEmpty e, IsString s) => Reader e s
E.nonempty) String
"LSP_ELECTRS_ENV" Mod Var ElectrsEnv
forall a. Mod Var a
opts
      Parser Error (BitcoindEnv -> RawConfig)
-> Parser Error BitcoindEnv -> Parser Error RawConfig
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Reader Error BitcoindEnv
-> String -> Mod Var BitcoindEnv -> Parser Error BitcoindEnv
forall e a.
AsUnset e =>
Reader e a -> String -> Mod Var a -> Parser e a
E.var (Reader Error BitcoindEnv
forall a. FromJSON a => String -> Either Error a
parseFromJSON Reader Error BitcoindEnv
-> (String -> Either Error String) -> Reader Error BitcoindEnv
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< String -> Either Error String
forall e s. (AsEmpty e, IsString s) => Reader e s
E.nonempty) String
"LSP_BITCOIND_ENV" Mod Var BitcoindEnv
forall a. Mod Var a
opts

opts :: E.Mod E.Var a
opts :: forall a. Mod Var a
opts =
  Mod Var a
forall (t :: * -> *) a. HasKeep t => Mod t a
E.keep Mod Var a -> Mod Var a -> Mod Var a
forall a. Semigroup a => a -> a -> a
<> String -> Mod Var a
forall (t :: * -> *) a. HasHelp t => String -> Mod t a
E.help String
""