clplug-1.0.0.0: src/Plugin/Client.hs
{-# LANGUAGE
LambdaCase
, OverloadedStrings
, DeriveGeneric
, DeriveAnyClass
, GeneralizedNewtypeDeriving
, FlexibleContexts
, DuplicateRecordFields
, TypeSynonymInstances
, FlexibleInstances
#-}
module Plugin.Client (
lightningCli,
lightningCliDebug,
Command(..),
PartialCommand,
Res(..),
Cli
)
where
import Plugin.Connect
import Plugin.Internal.Conduit
import Data.ByteString.Lazy as L
import System.IO.Unsafe
import Data.IORef
import Control.Monad.Reader
import Data.Conduit hiding (connect)
import Data.Conduit.Combinators hiding (stdout, stderr, stdin)
import Data.Aeson
import Data.Text
import Data.Maybe
import Control.Concurrent.STM.TVar
import Control.Monad.STM
-- | Use with a text object for method only, a tuple for method and params, or a partialCommand (no ID) to specify a filter of the response.
class Cli a where
lightningCli :: (MonadReader Plug m, MonadIO m) =>
a -> m (Maybe Res)
instance Cli Text where
lightningCli m = lightningCli_ (Command m Nothing Nothing)
instance Cli (Text, Value) where
lightningCli (m, p) = lightningCli_ (Command m (Just p) Nothing)
instance Cli PartialCommand where
lightningCli = lightningCli_
-- | Withhold the ID for use with lightningCli
type PartialCommand = Int -> Command
instance Show PartialCommand where
show x = show . x $ -1
data Command = Command {
method :: Text
, params :: Maybe Value
, reqFilter :: Maybe Value
, ____id :: Int
} deriving (Show)
instance ToJSON Command where
toJSON (Command m p Nothing i) =
object [ "jsonrpc" .= ("2.0" :: Text)
, "id" .= i
, "method" .= m
, "params" .= fromMaybe (object []) p
]
toJSON (Command m p (Just f) i) =
object [ "jsonrpc" .= ("2.0" :: Text)
, "id" .= i
, "filter" .= f
, "method" .= m
, "params" .= fromMaybe (object []) p
]
lightningCli_ :: (MonadReader Plug m, MonadIO m) =>
PartialCommand -> m (Maybe Res)
lightningCli_ v = do
Plug h _ _ tv <- ask
i <- liftIO . atomically $ stateTVar tv (\s -> (s, s + 1))
liftIO $ L.hPutStr h . encode $ v i
liftIO $ runConduit $ sourceHandle h .| inConduit .| await >>= \case
(Just (Correct x)) -> pure $ Just x
_ -> pure Nothing
-- | provide a log function (that doesn't hit stdin/out) for debugging
lightningCliDebug :: (MonadReader Plug m, MonadIO m, Cli c, Show c) =>
(String -> IO ()) -> c -> m (Maybe Res)
lightningCliDebug logger v = do
log' v
res <- lightningCli v
log' res
pure res
where
log' :: (Show a, MonadIO m) => a -> m ()
log' = liftIO . logger . show