{- |
Module: Temporal.Interceptor
Description: Define interceptors for Temporal workflows and activities.

Temporal interceptors allow you to customize and extend the behavior of
workflows and activities by intercepting and modifying their execution at
various points. Interceptors can be used to add cross-cutting concerns,
such as logging, security, or monitoring, to your Temporal applications.

This module provides types and functions for defining and composing
interceptors for different parts of Temporal workflows and activities.

Types for different types of interceptors:

* 'WorkflowInboundInterceptor': An interceptor for workflows, invoked for
  commands sent to workflow execution.
* 'WorkflowOutboundInterceptor': An interceptor for workflows, invoked for
  commands sent from a workflow.
* 'ActivityInboundInterceptor': An interceptor for activities, invoked for
  commands sent to an activity.
* 'ActivityOutboundInterceptor': An interceptor for activities, invoked for
  actions executed by an activity.
* 'ClientInterceptors': Interceptors for Temporal clients.

Functions for composing interceptors:

* 'interceptorConvertChildWorkflowHandle': A function for converting child
  workflow handles within interceptors.

Example usage of interceptors:

* Define a custom interceptor for activities using 'ActivityInboundInterceptor'.

   > myActivityInterceptor :: ActivityInboundInterceptor
   > myActivityInterceptor = ActivityInboundInterceptor
   >   { executeActivity = \input next -> do
   >       -- Perform custom logic before calling the activity function
   >       result <- next input
   >       -- Perform custom logic after the activity function completes
   >       return result
   >   }

* Compose multiple interceptors using 'Semigroup' instances.

   > combinedInterceptor :: Interceptor
   > combinedInterceptor = bugsnagInterceptor <> encryptionInterceptor <> otelInterceptor

* Provide the interceptors to the Temporal Workflow client and worker.
-}
module Temporal.Interceptor (
  Interceptors (..),
  ExecuteWorkflowInput (..),
  WorkflowInboundInterceptor (..),
  HandleQueryInput (..),
  WorkflowOutboundInterceptor (..),
  ActivityInput (..),
  ActivityInboundInterceptor (..),
  ExecuteActivityInput (..),
  ActivityOutboundInterceptor (..),
  WorkflowExitVariant (..),
  ClientInterceptors (..),
  QueryWorkflowInput (..),
  SignalWithStartWorkflowInput (..),
  ScheduleClientInterceptors (..),
  interceptorConvertChildWorkflowHandle,
) where

import Temporal.Client.Types
import Temporal.Payload
import Temporal.Workflow.Internal.Monad
import Temporal.Workflow.Types


data ActivityInboundInterceptor env = ActivityInboundInterceptor
  { forall env.
ActivityInboundInterceptor env
-> env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
executeActivity :: env -> ExecuteActivityInput -> (env -> ExecuteActivityInput -> IO (Either String Payload)) -> IO (Either String Payload)
  }


instance Semigroup (ActivityInboundInterceptor env) where
  ActivityInboundInterceptor env
l <> :: ActivityInboundInterceptor env
-> ActivityInboundInterceptor env -> ActivityInboundInterceptor env
<> ActivityInboundInterceptor env
r =
    ActivityInboundInterceptor
      { executeActivity :: env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
executeActivity = \env
env ExecuteActivityInput
input env -> ExecuteActivityInput -> IO (Either String Payload)
next -> ActivityInboundInterceptor env
-> env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
forall env.
ActivityInboundInterceptor env
-> env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
executeActivity ActivityInboundInterceptor env
l env
env ExecuteActivityInput
input ((env -> ExecuteActivityInput -> IO (Either String Payload))
 -> IO (Either String Payload))
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
forall a b. (a -> b) -> a -> b
$ \env
env' ExecuteActivityInput
input' -> ActivityInboundInterceptor env
-> env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
forall env.
ActivityInboundInterceptor env
-> env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
executeActivity ActivityInboundInterceptor env
r env
env' ExecuteActivityInput
input' env -> ExecuteActivityInput -> IO (Either String Payload)
next
      }


instance Monoid (ActivityInboundInterceptor env) where
  mempty :: ActivityInboundInterceptor env
mempty =
    ActivityInboundInterceptor
      { executeActivity :: env
-> ExecuteActivityInput
-> (env -> ExecuteActivityInput -> IO (Either String Payload))
-> IO (Either String Payload)
executeActivity = \env
env ExecuteActivityInput
input env -> ExecuteActivityInput -> IO (Either String Payload)
next -> env -> ExecuteActivityInput -> IO (Either String Payload)
next env
env ExecuteActivityInput
input
      }


data ActivityOutboundInterceptor env = ActivityOutboundInterceptor {}


instance Semigroup (ActivityOutboundInterceptor env) where
  ActivityOutboundInterceptor env
ActivityOutboundInterceptor <> :: ActivityOutboundInterceptor env
-> ActivityOutboundInterceptor env
-> ActivityOutboundInterceptor env
<> ActivityOutboundInterceptor env
ActivityOutboundInterceptor = ActivityOutboundInterceptor env
forall env. ActivityOutboundInterceptor env
ActivityOutboundInterceptor


instance Monoid (ActivityOutboundInterceptor env) where
  mempty :: ActivityOutboundInterceptor env
mempty = ActivityOutboundInterceptor env
forall env. ActivityOutboundInterceptor env
ActivityOutboundInterceptor


data Interceptors env = Interceptors
  { forall env. Interceptors env -> WorkflowInboundInterceptor
workflowInboundInterceptors :: WorkflowInboundInterceptor
  , forall env. Interceptors env -> WorkflowOutboundInterceptor
workflowOutboundInterceptors :: WorkflowOutboundInterceptor
  , forall env. Interceptors env -> ActivityInboundInterceptor env
activityInboundInterceptors :: ActivityInboundInterceptor env
  , forall env. Interceptors env -> ActivityOutboundInterceptor env
activityOutboundInterceptors :: ActivityOutboundInterceptor env
  , forall env. Interceptors env -> ClientInterceptors
clientInterceptors :: ClientInterceptors
  , forall env. Interceptors env -> ScheduleClientInterceptors
scheduleClientInterceptors :: ScheduleClientInterceptors
  }


instance Semigroup (Interceptors env) where
  Interceptors WorkflowInboundInterceptor
a WorkflowOutboundInterceptor
b ActivityInboundInterceptor env
c ActivityOutboundInterceptor env
d ClientInterceptors
e ScheduleClientInterceptors
f <> :: Interceptors env -> Interceptors env -> Interceptors env
<> Interceptors WorkflowInboundInterceptor
a' WorkflowOutboundInterceptor
b' ActivityInboundInterceptor env
c' ActivityOutboundInterceptor env
d' ClientInterceptors
e' ScheduleClientInterceptors
f' = WorkflowInboundInterceptor
-> WorkflowOutboundInterceptor
-> ActivityInboundInterceptor env
-> ActivityOutboundInterceptor env
-> ClientInterceptors
-> ScheduleClientInterceptors
-> Interceptors env
forall env.
WorkflowInboundInterceptor
-> WorkflowOutboundInterceptor
-> ActivityInboundInterceptor env
-> ActivityOutboundInterceptor env
-> ClientInterceptors
-> ScheduleClientInterceptors
-> Interceptors env
Interceptors (WorkflowInboundInterceptor
a WorkflowInboundInterceptor
-> WorkflowInboundInterceptor -> WorkflowInboundInterceptor
forall a. Semigroup a => a -> a -> a
<> WorkflowInboundInterceptor
a') (WorkflowOutboundInterceptor
b WorkflowOutboundInterceptor
-> WorkflowOutboundInterceptor -> WorkflowOutboundInterceptor
forall a. Semigroup a => a -> a -> a
<> WorkflowOutboundInterceptor
b') (ActivityInboundInterceptor env
c ActivityInboundInterceptor env
-> ActivityInboundInterceptor env -> ActivityInboundInterceptor env
forall a. Semigroup a => a -> a -> a
<> ActivityInboundInterceptor env
c') (ActivityOutboundInterceptor env
d ActivityOutboundInterceptor env
-> ActivityOutboundInterceptor env
-> ActivityOutboundInterceptor env
forall a. Semigroup a => a -> a -> a
<> ActivityOutboundInterceptor env
d') (ClientInterceptors
e ClientInterceptors -> ClientInterceptors -> ClientInterceptors
forall a. Semigroup a => a -> a -> a
<> ClientInterceptors
e') (ScheduleClientInterceptors
f ScheduleClientInterceptors
-> ScheduleClientInterceptors -> ScheduleClientInterceptors
forall a. Semigroup a => a -> a -> a
<> ScheduleClientInterceptors
f')


instance Monoid (Interceptors env) where
  mempty :: Interceptors env
mempty = WorkflowInboundInterceptor
-> WorkflowOutboundInterceptor
-> ActivityInboundInterceptor env
-> ActivityOutboundInterceptor env
-> ClientInterceptors
-> ScheduleClientInterceptors
-> Interceptors env
forall env.
WorkflowInboundInterceptor
-> WorkflowOutboundInterceptor
-> ActivityInboundInterceptor env
-> ActivityOutboundInterceptor env
-> ClientInterceptors
-> ScheduleClientInterceptors
-> Interceptors env
Interceptors WorkflowInboundInterceptor
forall a. Monoid a => a
mempty WorkflowOutboundInterceptor
forall a. Monoid a => a
mempty ActivityInboundInterceptor env
forall a. Monoid a => a
mempty ActivityOutboundInterceptor env
forall a. Monoid a => a
mempty ClientInterceptors
forall a. Monoid a => a
mempty ScheduleClientInterceptors
forall a. Monoid a => a
mempty


data ScheduleClientInterceptors = ScheduleClientInterceptors
  { ScheduleClientInterceptors
-> StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
scheduleWorkflowAction :: StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
  -- ^ Unlike the other interceptors, this one is invoked on the construction of the workflow start options
  }


instance Semigroup ScheduleClientInterceptors where
  ScheduleClientInterceptors StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
a <> :: ScheduleClientInterceptors
-> ScheduleClientInterceptors -> ScheduleClientInterceptors
<> ScheduleClientInterceptors StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
b =
    ScheduleClientInterceptors
      { scheduleWorkflowAction :: StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
scheduleWorkflowAction = \StartWorkflowOptions
opts [Payload]
input -> do
          opts' <- StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
a StartWorkflowOptions
opts [Payload]
input
          b opts' input
      }


instance Monoid ScheduleClientInterceptors where
  mempty :: ScheduleClientInterceptors
mempty =
    ScheduleClientInterceptors
      { scheduleWorkflowAction :: StartWorkflowOptions -> [Payload] -> IO StartWorkflowOptions
scheduleWorkflowAction = \StartWorkflowOptions
opts [Payload]
_ -> StartWorkflowOptions -> IO StartWorkflowOptions
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return StartWorkflowOptions
opts
      }