aboutsummaryrefslogtreecommitdiff
path: root/server/src/Thermoprint/Server/QMConfig.hs
blob: 8f08fafaa964cd707d96d9b26ec32e3d10731eb4 (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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{-# LANGUAGE GADTs              #-}
{-# LANGUAGE FlexibleContexts   #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE TypeOperators      #-}
{-# LANGUAGE RecordWildCards    #-}
{-# LANGUAGE ViewPatterns       #-}

module Thermoprint.Server.QMConfig
       ( QMConfig(..)
       , nullQM
       , idQM
       , standardSleep
       , limitHistorySize
       , limitHistoryAge
       ) where

import Control.Monad.Trans.Resource
import Control.Monad.Trans.Control
import Control.Monad.Trans.Identity
import Control.Monad.Logger
import Control.Monad.Reader
import Control.Monad.IO.Class
import Control.Monad.Morph
import Control.Monad.State
import Control.Category
import Servant.Server.Internal.Enter (enter, (:~>)(..))

import Data.Default.Class

import           Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Time
import Data.Foldable

import Control.Concurrent.STM

import Thermoprint.Server.Queue hiding (idQM, intersection, nullQM, union, runQM)
import qualified Thermoprint.Server.Queue as Q

import Prelude hiding (length, maximum, id, (.))

data QMConfig m where
  QMConfig :: ( MonadTrans t
              , MFunctor t
              , Monad (t STM)
              , MonadIO (t IO)
              ) => QueueManager t -> (t IO) :~> m -> QMConfig m
  QMConfig' :: ( MonadIO m
               ) => ( forall t. ( MonadTrans t
                                , MFunctor t
                                , Monad (t STM)
                                , MonadIO (t IO)
                                , Monad (QueueManagerM t)
                                ) => QueueManager t
                    ) -> QMConfig m

instance MonadIO m => Default (QMConfig m) where
  def = idQM

intersection :: (Functor f, Foldable f, MonadIO m) => f (QMConfig m) -> QMConfig m
intersection = foldr' (qmCombine Q.intersection) idQM

idQM :: MonadIO m => QMConfig m
idQM = QMConfig' Q.idQM

union :: (Foldable f, MonadIO m) => f (QMConfig m) -> QMConfig m
union = foldr' (qmCombine Q.union) idQM
  
nullQM :: MonadIO m => QMConfig m
nullQM = QMConfig' Q.nullQM

qmCombine :: ([QueueManager t] -> QueueManager t) -> QMConfig m -> QMConfig m -> QMConfig m
qmCombine qmCombine' (QMConfig a natA) (QMConfig b natB) = undefined
  where
    natA :: t IO :~> m
    natB :: t' IO :~> m
    ---
    hoistNat natB :: t (t' IO) :~> t m
    -- 
    ? :: t m :~> m
    natAB :: ComposeT t t' IO :~> m

runQM :: ( HasQueue q ) => TChan JobId -> QMConfig m -> q -> t IO ()
runQM gcChan (QMConfig qm nat) q = unNat nat $ runQM gcChan qm q
runQM gcChan (QMConfig' qm) q = hoist liftIO $ runQM gcChan qm q

standardSleep :: Monad (QueueManagerM t) => QueueManager t
-- ^ Instruct 'runQM' to sleep some standard amount of time
--
-- /TODO/: Investigate implementing a smarter algorithm (PID-controller)
standardSleep = return $ 20

limitHistorySize :: MonadIO m => Int -> QMConfig m
-- ^ Limit a 'Queue's 'history's size to some number of 'QueueEntry's
limitHistorySize max = QMConfig' $ modify' limitSize >> standardSleep
  where
    limitSize :: Queue -> Queue
    limitSize q@Queue{..} = q { history = Seq.take max history }

limitHistoryAge :: MonadIO m => NominalDiffTime -- ^ Maximum age relative to the youngest 'QueueEntry'
                -> QMConfig m
-- ^ Limit a 'Queue's 'history's contents to 'QueueEntry's below a certain age
limitHistoryAge  maxAge = QMConfig' $ modify' limitAge >> standardSleep
  where
    limitAge :: Queue -> Queue
    limitAge q@Queue{..} = q { history = Seq.filter (filterAge . created . fst) history}
      where
        youngest :: UTCTime
        youngest = maximum $ created . fst <$> history
        filterAge :: UTCTime -> Bool
        filterAge time = not $ (youngest `diffUTCTime` time) > maxAge