packages feed

pms-domain-service-0.0.1.0: src/PMS/Domain/Service/DS/State/Run.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}

module PMS.Domain.Service.DS.State.Run where


import System.IO
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Logger
import qualified Data.Text as T
import Control.Lens
import Control.Monad.Reader
import qualified Control.Concurrent.STM as STM
import System.FilePath
import System.Exit

import qualified PMS.Domain.Model.DM.Type as DM
import qualified PMS.Domain.Model.DM.Constant as DM

import PMS.Domain.Service.DM.Type
import PMS.Domain.Service.DM.TH
import PMS.Domain.Service.DM.Constant
import qualified PMS.Domain.Service.DS.Utility as U



instanceTH_IAppState ''RunStateData

-- |
--
instance IStateActivity RunStateData EntryEventData where
  action _ _ = do
    $logDebugS DM._LOGTAG "Run entry called."
    return Nothing

-- |
--
instance IStateActivity RunStateData ExitEventData where
  action _ _ = do
    $logDebugS DM._LOGTAG "Run exit called."
    return Nothing

-- |
--
instance IStateActivity RunStateData TransitEventData
  -- @see default implementation in Type module.

-- |
--
instance IStateActivity RunStateData InitEventData
  -- @see default implementation in Type module.

-- |
--
instance IStateActivity RunStateData LaunchEventData where
  action _ _ = do
    $logDebugS DM._LOGTAG "Run launch called."
    return Nothing

-- |
--
instance IStateActivity RunStateData DisconnectEventData where
  action _ _ = do
    $logDebugS DM._LOGTAG "Run discoonect called."
    return $ Just RunToStop

-- |
--
instance IStateActivity RunStateData TerminateEventData
  -- @see default implementation in Type module.

-- |
--
instance IStateActivity RunStateData InitializedEventData
  -- @see default implementation in Type module.

-- |
--
instance IStateActivity RunStateData ToolsListEventData where
  action s (ToolsListEvent r@(ToolsListEventData dat)) = do
    $logDebugS DM._LOGTAG "Run ToolsListEvent called."
    $logDebugS DM._LOGTAG (T.pack (show s))
    $logDebugS DM._LOGTAG (T.pack (show r))

    scriptsDir <- view DM.scriptsDirDomainData <$> lift ask

    let toolFile = scriptsDir </> _TOOLS_LIST_FILE
    cont <- U.readFile toolFile
    let result = DM.McpToolsListResponseResult $ DM.RawJsonByteString cont
        jsonRpc = dat^.DM.jsonrpcMcpToolsListRequestData
        resDat = DM.McpToolsListResponseData jsonRpc result
        res = DM.McpToolsListResponse resDat

    $logDebugS DM._LOGTAG $ T.pack $ show res

    queue <- view DM.responseQueueDomainData <$> lift ask
    liftIO $ STM.atomically $ STM.writeTQueue queue res

    return noStateTransition

-- |
--
instance IStateActivity RunStateData ToolsCallEventData where
  action _ (ToolsCallEvent (ToolsCallEventData evDat)) = do
    $logDebugS DM._LOGTAG "Run ToolsCallEvent called."

    cmd <- genCommand evDat $ evDat^.DM.paramsMcpToolsCallRequestData^.DM.nameMcpToolsCallRequestDataParams

    cmdQ <- view DM.commandQueueDomainData <$> lift ask
    liftIO $ STM.atomically $ STM.writeTQueue cmdQ cmd

    return noStateTransition
    
    where
      genCommand :: DM.McpToolsCallRequestData -> String -> AppContext DM.Command
      genCommand dat "pty-connect" = genPtyConnectCommand dat
      genCommand dat "pty-bash"    = genPtyConnectCommand dat
      genCommand dat "pty-ssh"     = genPtyConnectCommand dat
      genCommand dat "pty-cabal"   = genPtyConnectCommand dat
      genCommand dat "pty-stack"   = genPtyConnectCommand dat
      genCommand dat "pty-ghci"    = genPtyConnectCommand dat
      genCommand dat "pty-message" = do
        resQ <- view DM.responseQueueDomainData <$> lift ask
        let cmdDat = DM.PtyMessageCommandData {
                      DM._namePtyMessageCommandData = dat^.DM.paramsMcpToolsCallRequestData^.DM.nameMcpToolsCallRequestDataParams
                    , DM._argumentsPtyMessageCommandData = dat^.DM.paramsMcpToolsCallRequestData^.DM.argumentsMcpToolsCallRequestDataParams
                    , DM._callbackPtyMessageCommandData = callback resQ
                    }

        return $ DM.PtyMessageCommand cmdDat
      genCommand dat _ = do
        resQ <- view DM.responseQueueDomainData <$> lift ask
        let cmdDat = DM.SystemCommandData {
                      DM._nameSystemCommandData = dat^.DM.paramsMcpToolsCallRequestData^.DM.nameMcpToolsCallRequestDataParams
                    , DM._argumentsSystemCommandData = dat^.DM.paramsMcpToolsCallRequestData^.DM.argumentsMcpToolsCallRequestDataParams
                    , DM._callbackSystemCommandData = callback resQ
                    }

        return $ DM.SystemCommand cmdDat

      genPtyConnectCommand :: DM.McpToolsCallRequestData -> AppContext DM.Command
      genPtyConnectCommand dat = do
        resQ <- view DM.responseQueueDomainData <$> lift ask
        let cmdDat = DM.PtyConnectCommandData {
                      DM._namePtyConnectCommandData = dat^.DM.paramsMcpToolsCallRequestData^.DM.nameMcpToolsCallRequestDataParams
                    , DM._argumentsPtyConnectCommandData = dat^.DM.paramsMcpToolsCallRequestData^.DM.argumentsMcpToolsCallRequestDataParams
                    , DM._callbackPtyConnectCommandData = callback resQ
                    }

        return $ DM.PtyConnectCommand cmdDat

      -- |
      --
      callback :: STM.TQueue DM.McpResponse -> DM.SystemCommandCallback ()
      callback resQ code outStr errStr = do
        hPutStrLn stderr $ "[INFO] PMS.Domain.Service.DS.State.Run.callback called."

        let jsonRpc = evDat^.DM.jsonrpcMcpToolsCallRequestData
            content = [ DM.McpToolsCallResponseResultContent "text" outStr
                      , DM.McpToolsCallResponseResultContent "text" errStr
                      ]
            result = DM.McpToolsCallResponseResult {
                       DM._contentMcpToolsCallResponseResult = content
                     , DM._isErrorMcpToolsCallResponseResult = (ExitSuccess /= code)
                     }
            resDat = DM.McpToolsCallResponseData jsonRpc result
            res = DM.McpToolsCallResponse resDat

        STM.atomically $ STM.writeTQueue resQ res

        hPutStrLn stderr $ "[INFO] PMS.Domain.Service.DS.State.Run.callback end."