diff options
Diffstat (limited to 'server/src/Thermoprint')
| -rw-r--r-- | server/src/Thermoprint/Server/Printer.hs | 65 |
1 files changed, 58 insertions, 7 deletions
diff --git a/server/src/Thermoprint/Server/Printer.hs b/server/src/Thermoprint/Server/Printer.hs index e66afff..0db98a0 100644 --- a/server/src/Thermoprint/Server/Printer.hs +++ b/server/src/Thermoprint/Server/Printer.hs | |||
| @@ -1,29 +1,80 @@ | |||
| 1 | {-# LANGUAGE RankNTypes #-} | 1 | {-# LANGUAGE RankNTypes #-} |
| 2 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
| 3 | {-# LANGUAGE FlexibleContexts #-} | ||
| 4 | {-# LANGUAGE RecordWildCards #-} | ||
| 5 | {-# LANGUAGE OverloadedStrings #-} | ||
| 6 | {-# LANGUAGE TemplateHaskell #-} | ||
| 7 | {-# LANGUAGE StandaloneDeriving #-} | ||
| 8 | {-# LANGUAGE DeriveGeneric, DeriveAnyClass #-} | ||
| 2 | 9 | ||
| 3 | module Thermoprint.Server.Printer | 10 | module Thermoprint.Server.Printer |
| 4 | ( Printer | 11 | ( Printer(..) |
| 12 | , Queue(..) | ||
| 13 | , runPrinter | ||
| 5 | ) where | 14 | ) where |
| 6 | 15 | ||
| 7 | import Thermoprint.API (PrintingError(..), Printout) | 16 | import Thermoprint.API (PrintingError(..), Printout) |
| 17 | import qualified Thermoprint.API as API (JobStatus(..)) | ||
| 8 | 18 | ||
| 9 | import Thermoprint.Server.Database | 19 | import Thermoprint.Server.Database |
| 10 | 20 | ||
| 11 | import Database.Persist | 21 | import Database.Persist |
| 12 | import Database.Persist.Sql | 22 | import Database.Persist.Sql |
| 13 | 23 | ||
| 14 | import Data.Sequence (Seq, ViewL(..)) | 24 | import Data.Sequence (Seq, ViewL(..), viewl, (<|)) |
| 15 | import qualified Data.Sequence as Seq | 25 | import qualified Data.Sequence as Seq |
| 16 | import Data.Map (Map) | 26 | import Data.Map (Map) |
| 17 | import qualified Data.Map as Map | 27 | import qualified Data.Map as Map |
| 18 | 28 | ||
| 19 | import Control.Monad.IO.Class (MonadIO) | 29 | import qualified Data.Text as T (pack) |
| 30 | |||
| 31 | import Data.Typeable (Typeable) | ||
| 32 | import GHC.Generics (Generic) | ||
| 33 | import Control.DeepSeq | ||
| 34 | |||
| 35 | import Control.Monad.Trans.Resource | ||
| 36 | import Control.Monad.IO.Class | ||
| 37 | import Control.Monad.Logger | ||
| 38 | import Control.Monad.Reader | ||
| 39 | |||
| 40 | import Control.Monad (forever) | ||
| 20 | 41 | ||
| 21 | import Control.Concurrent.STM | 42 | import Control.Concurrent.STM |
| 22 | 43 | ||
| 23 | data Printer = Printer | 44 | data Printer = Printer |
| 24 | { print :: forall m. (MonadIO m) => Printout -> m (Maybe PrintingError) | 45 | { print :: forall m. (MonadIO m) => Printout -> m (Maybe PrintingError) |
| 25 | , queue :: TVar (Seq JobId) | 46 | , queue :: TVar Queue |
| 26 | } | 47 | } |
| 27 | 48 | ||
| 28 | runPrinter :: Printer -> IO () | 49 | -- | Zipper for 'Seq JobId' |
| 29 | runPrinter = undefined | 50 | data Queue = Queue |
| 51 | { pending :: Seq JobId -- ^ Pending jobs, closest first | ||
| 52 | , current :: Maybe JobId | ||
| 53 | , history :: Seq (JobId, Maybe PrintingError) -- ^ Completed jobs, closest first | ||
| 54 | } | ||
| 55 | deriving (Typeable, Generic, NFData) | ||
| 56 | |||
| 57 | atomically' :: MonadIO m => STM a -> m a | ||
| 58 | atomically' = liftIO . atomically | ||
| 59 | |||
| 60 | runPrinter :: ( MonadReader ConnectionPool m | ||
| 61 | , MonadIO m | ||
| 62 | , MonadLogger m | ||
| 63 | , MonadBaseControl IO m | ||
| 64 | ) => Printer -> m () | ||
| 65 | -- ^ Loop 'forever' pushing entries from the 'Queue' associated to a 'Printer' into its 'print'-method | ||
| 66 | runPrinter Printer{..} = forever $ do | ||
| 67 | jobId <- atomically' $ do | ||
| 68 | (Queue queuePending Nothing history) <- readTVar queue | ||
| 69 | case viewl queuePending of | ||
| 70 | EmptyL -> retry | ||
| 71 | (jobId :< remaining) -> do | ||
| 72 | writeTVar queue $!! Queue remaining (Just jobId) history | ||
| 73 | return jobId | ||
| 74 | job <- runSqlPool (get jobId) =<< ask | ||
| 75 | case job of | ||
| 76 | Nothing -> $(logWarn) "Nonexistent job id in printer queue" | ||
| 77 | Just job -> do | ||
| 78 | printReturn <- print (jobContent job) | ||
| 79 | maybe (return ()) ($(logWarn) . T.pack . (("Error while printing " ++ show jobId ++ ": ") ++) . show) $ printReturn | ||
| 80 | atomically' $ modifyTVar' queue (\Queue{..} -> force . Queue pending Nothing $ (jobId, printReturn) <| history) | ||
