module Hasura.Eventing.Common
  ( LockedEventsCtx (..),
    saveLockedEvents,
    removeEventFromLockedEvents,
  )
where

import Control.Concurrent.STM.TVar
import Control.Monad.STM
import Data.Set qualified as Set
import Hasura.Prelude
import Hasura.RQL.Types.Action (LockedActionEventId)
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Eventing (EventId)
import Hasura.RQL.Types.ScheduledTrigger (CronEventId, OneOffScheduledEventId)

data LockedEventsCtx = LockedEventsCtx
  { LockedEventsCtx -> TVar (Set CronEventId)
leCronEvents :: TVar (Set.Set CronEventId),
    LockedEventsCtx -> TVar (Set CronEventId)
leOneOffEvents :: TVar (Set.Set OneOffScheduledEventId),
    LockedEventsCtx -> TVar (HashMap SourceName (Set CronEventId))
leEvents :: TVar (HashMap SourceName (Set.Set EventId)),
    LockedEventsCtx -> TVar (Set CronEventId)
leActionEvents :: TVar (Set.Set LockedActionEventId)
  }

-- | After the events are fetched from the DB, we store the locked events
--   in a hash set(order doesn't matter and look ups are faster) in the
--   event engine context
saveLockedEvents :: (MonadIO m) => [EventId] -> TVar (Set.Set EventId) -> m ()
saveLockedEvents :: [CronEventId] -> TVar (Set CronEventId) -> m ()
saveLockedEvents [CronEventId]
eventIds TVar (Set CronEventId)
lockedEvents =
  IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$
    STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      Set CronEventId
lockedEventsVals <- TVar (Set CronEventId) -> STM (Set CronEventId)
forall a. TVar a -> STM a
readTVar TVar (Set CronEventId)
lockedEvents
      TVar (Set CronEventId) -> Set CronEventId -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar (Set CronEventId)
lockedEvents
        (Set CronEventId -> STM ()) -> Set CronEventId -> STM ()
forall a b. (a -> b) -> a -> b
$! Set CronEventId -> Set CronEventId -> Set CronEventId
forall a. Ord a => Set a -> Set a -> Set a
Set.union Set CronEventId
lockedEventsVals
        (Set CronEventId -> Set CronEventId)
-> Set CronEventId -> Set CronEventId
forall a b. (a -> b) -> a -> b
$ [CronEventId] -> Set CronEventId
forall a. Ord a => [a] -> Set a
Set.fromList [CronEventId]
eventIds

-- | Remove an event from the 'LockedEventsCtx' after it has been processed
removeEventFromLockedEvents ::
  MonadIO m => EventId -> TVar (Set.Set EventId) -> m ()
removeEventFromLockedEvents :: CronEventId -> TVar (Set CronEventId) -> m ()
removeEventFromLockedEvents CronEventId
eventId TVar (Set CronEventId)
lockedEvents =
  IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$
    STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      Set CronEventId
lockedEventsVals <- TVar (Set CronEventId) -> STM (Set CronEventId)
forall a. TVar a -> STM a
readTVar TVar (Set CronEventId)
lockedEvents
      TVar (Set CronEventId) -> Set CronEventId -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar (Set CronEventId)
lockedEvents (Set CronEventId -> STM ()) -> Set CronEventId -> STM ()
forall a b. (a -> b) -> a -> b
$! CronEventId -> Set CronEventId -> Set CronEventId
forall a. Ord a => a -> Set a -> Set a
Set.delete CronEventId
eventId Set CronEventId
lockedEventsVals