packages feed

pms-domain-service-0.0.4.0: src/PMS/Domain/Service/DS/Core.hs

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

module PMS.Domain.Service.DS.Core where

import Control.Monad.Logger
import Data.Conduit
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Lens
import Control.Monad.Reader
import qualified Control.Concurrent.STM as STM
import Control.Monad.Trans.State.Lazy
import qualified Data.Text as T
import Control.Monad.Except

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.DS.State.Start()
import PMS.Domain.Service.DS.State.Run()
import PMS.Domain.Service.DS.State.Stop()

-- |
--
funcTH_transit


-- |
--
app :: AppContext ()
app = do
  $logDebugS DM._LOGTAG "app called."
  runConduit pipeline
  where
    pipeline :: ConduitM () Void AppContext ()
    pipeline = src .| work .| sink

---------------------------------------------------------------------------------
-- |
--
src :: ConduitT () DM.McpRequest AppContext ()
src = lift go >>= yield >> src
  where
    go :: AppContext DM.McpRequest
    go = do
      queue <- view DM.requestQueueDomainData <$> lift ask
      req <- liftIO $ STM.atomically $ STM.readTQueue queue
      $logDebugS DM._LOGTAG $ T.pack $ "src: req: " ++ show req
      return req

---------------------------------------------------------------------------------
-- |
--
work :: ConduitT DM.McpRequest EventW AppContext ()
work = await >>= \case
  Just reqBS -> flip catchError errHdl $
    lift (go reqBS) >>= yield >> work
  Nothing -> do
    $logWarnS DM._LOGTAG "work: await returns nothing. skip."
    work
  where
    errHdl :: String -> ConduitT DM.McpRequest EventW AppContext ()
    errHdl msg = do
      $logWarnS DM._LOGTAG $ T.pack $ "work: exception occurred. skip. " ++ msg
      work


    go :: DM.McpRequest -> AppContext EventW
    go req = req2ev req

-- |
--
req2ev :: DM.McpRequest -> AppContext EventW
req2ev (DM.McpInitializeRequest dat) = pure . EventW . InitializeEvent . InitializeEventData $ dat
req2ev (DM.McpToolsListRequest dat) = pure . EventW . ToolsListEvent . ToolsListEventData $ dat
req2ev (DM.McpToolsCallRequest dat) = pure . EventW . ToolsCallEvent . ToolsCallEventData $ dat
req2ev (DM.McpPromptsListRequest dat) = pure . EventW . PromptsListEvent . PromptsListEventData $ dat
req2ev (DM.McpPromptsGetRequest dat) = pure . EventW . PromptsGetEvent . PromptsGetEventData $ dat
req2ev (DM.McpResourcesTemplatesListRequest dat) = pure . EventW . ResourcesTemplatesListEvent . ResourcesTemplatesListEventData $ dat
req2ev (DM.McpResourcesListRequest dat) = pure . EventW . ResourcesListEvent . ResourcesListEventData $ dat
req2ev (DM.McpResourcesReadRequest dat) = pure . EventW . ResourcesReadEvent . ResourcesReadEventData $ dat
req2ev (DM.McpInitializedNotification dat) = pure . EventW . InitializedEvent . InitializedEventData $ dat
req2ev (DM.McpCancelledNotification dat) = pure . EventW . CancelledEvent . CancelledEventData $ dat
req2ev (DM.McpCompletionCompleteRequest dat) = pure . EventW . CompletionCompleteEvent . CompletionCompleteEventData $ dat

---------------------------------------------------------------------------------
-- |
--
sink :: ConduitT EventW Void AppContext ()
sink = await >>= \case
  Just ev -> flip catchError errHdl $ do
    lift (go ev) >> sink
  Nothing -> do
    $logWarnS DM._LOGTAG "sink: await returns nothing. skip."
    sink

  where
    errHdl :: String -> ConduitT EventW Void AppContext ()
    errHdl msg = do
      $logWarnS DM._LOGTAG $ T.pack $ "sink: exception occurred. skip. " ++ msg
      sink
      
    go :: EventW -> AppContext ()
    go ev = get >>= flip actionSW ev >>= \case
      Nothing -> return ()
      Just st -> transit st