summaryrefslogtreecommitdiff
path: root/app/Foobar/Services/Coalescing.hs
blob: c44c5ebf83fa7a4316fe496231999bbfb52f8966 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{-# LANGUAGE OverloadedRecordDot, DuplicateRecordFields #-}

-- |
-- Module     : Foobar.Services.Coalescing
-- Description: Coalesce multiple events using a timeout.

module Foobar.Services.Coalescing
  ( EventScheduler
  , mkEventScheduler
  , scheduleEvent
  ) where

import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Word (Word32)

import qualified GI.GLib as GLib

-- | Management structure for coalescing events.
data EventScheduler
  = EventScheduler { delay    :: !Int
                   , sourceId :: !(IORef (Maybe Word32)) }

-- | Create a new event scheduler for coalescing events.
mkEventScheduler
  :: Int               -- ^ Delay for scheduling events in milliseconds.
  -> IO EventScheduler -- ^ The event scheduler structure.
mkEventScheduler delay' = EventScheduler delay' <$> newIORef Nothing

-- | Schedule an event.
--
-- If there is already an event scheduled, the two are coalesced.
scheduleEvent
  :: EventScheduler -- ^ The event scheduler.
  -> IO ()          -- ^ The event to be scheduled.
  -> IO ()
scheduleEvent s event = do
  existingId <- readIORef s.sourceId
  let sourceFunc :: GLib.SourceFunc
      sourceFunc = do
        event
        writeIORef s.sourceId Nothing
        pure GLib.SOURCE_REMOVE
  case existingId of
    Just _  -> pure ()
    Nothing -> do newId <- GLib.timeoutAdd GLib.PRIORITY_DEFAULT (fromIntegral s.delay) sourceFunc
                  writeIORef s.sourceId (Just newId)