{-# LANGUAGE BlockArguments , ViewPatterns , OverloadedStrings , RecordWildCards , LambdaCase #-} module Lightning.Plugin where import Network.JSONRPC import qualified Data.Conduit.Combinators as CC import Control.Monad.Logger import Control.Monad.IO.Class import Control.Monad.IO.Unlift import qualified Network.Socket as N import Network.Socket import Data.Aeson import qualified Data.Text as T import System.IO import Control.Monad import Lightning.Hooks import Lightning.Client import Lightning.Manifest jsonrpc :: (MonadLoggerIO (l m), MonadUnliftIO (l m)) => JSONRPCT (l m) g -> (l m) g jsonrpc = runJSONRPCT V2 False (CC.stdout) CC.stdin jsonh :: (MonadLoggerIO (l m), MonadUnliftIO (l m)) => Handle -> JSONRPCT (l m) g -> (l m) g jsonh h = runJSONRPCT V2 False (CC.sinkHandle h) (CC.sourceHandle h) type Cli = Method -> Params -> Filter -> IO Value plugInit :: (MonadUnliftIO m, MonadFail m) => Manifest -> m (Init, Cli) plugInit manifest = runNoLoggingT $ jsonrpc do liftIO $ hSetBuffering stdout NoBuffering Just (Request V2 "getmanifest" _ i) <- receiveRequest sendResponse $ Response V2 manifest i Just (Request V2 "init" (fromJSON -> Success init'@(Init _ _)) i2) <- receiveRequest sendResponse $ Response V2 (object []) i2 h <- liftIO $ getRpc init' pure (init', cli h) -- plugRun :: _ -- ?? -- (MonadUnliftIO m, MonadFail m) => -- (Request -> ReaderT Session (NoLoggingT m) a) -- -> m a1 -- -- JSONRPCT (l m) g -> IO () -- XXX -- plugRun app = runNoLoggingT.forever.jsonrpc $ do -- Just req <- receiveRequest -- app req plugRun :: MonadUnliftIO m => JSONRPCT (NoLoggingT m) a1 -> m a2 plugRun app = runNoLoggingT.forever.jsonrpc $ app type Params = Maybe Value type Filter = Maybe Value cli :: Handle -> Method -> Params -> Filter -> IO Value cli h m Nothing f = cli h m (Just $ object []) f -- using JSONRPC cli h m (Just p) Nothing = runNoLoggingT $ jsonh h do Just (Right v) <- sendRequest $ Cj m p pure v -- using manual conduits because of filter spec -- XXX: is it possible to do this within JSONRPCT? cli h m (Just p) f@(Just _) = do Just (Res v _) <- liftIO $ lightningCli h $ Command m f p pure v data Cj = Cj Method Value instance ToRequest Cj where requestMethod (Cj m _) = m requestIsNotif = const False instance ToJSON Cj where toJSON (Cj _ v) = toJSON v getRpc :: Init -> IO Handle getRpc (Init _ InitConfig{..}) = do soc <- socket AF_UNIX Stream 0 N.connect soc $ SockAddrUnix $ T.unpack file socketToHandle soc ReadWriteMode where file = lightning5dir <> "/" <> rpc5file