aboutsummaryrefslogtreecommitdiff
path: root/server/src/Thermoprint/Server/Printer.hs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/Thermoprint/Server/Printer.hs')
-rw-r--r--server/src/Thermoprint/Server/Printer.hs67
1 files changed, 41 insertions, 26 deletions
diff --git a/server/src/Thermoprint/Server/Printer.hs b/server/src/Thermoprint/Server/Printer.hs
index 67180c4..7f41430 100644
--- a/server/src/Thermoprint/Server/Printer.hs
+++ b/server/src/Thermoprint/Server/Printer.hs
@@ -12,38 +12,41 @@ module Thermoprint.Server.Printer
12 ( PrinterMethod(..), Printer(..) 12 ( PrinterMethod(..), Printer(..)
13 , printer 13 , printer
14 , Queue(..) 14 , Queue(..)
15 , QueueEntry(..)
15 , runPrinter 16 , runPrinter
16 , addToQueue 17 , addToQueue
17 ) where 18 ) where
18 19
19import Thermoprint.API (PrintingError(..), Printout) 20import Thermoprint.API (PrintingError(..), Printout)
20import qualified Thermoprint.API as API (JobStatus(..)) 21import qualified Thermoprint.API as API (JobStatus(..))
21 22
22import Thermoprint.Server.Database 23import Thermoprint.Server.Database
23 24
24import Database.Persist 25import Database.Persist
25import Database.Persist.Sql 26import Database.Persist.Sql
26 27
27import Data.Sequence (Seq, ViewL(..), viewl, (<|)) 28import Data.Sequence (Seq, ViewL(..), viewl, (<|), (|>))
28import qualified Data.Sequence as Seq 29import qualified Data.Sequence as Seq
29import Data.Map (Map) 30import Data.Map (Map)
30import qualified Data.Map as Map 31import qualified Data.Map as Map
31 32
32import qualified Data.Text as T (pack) 33import qualified Data.Text as T (pack)
33 34
34import Data.Typeable (Typeable) 35import Data.Typeable (Typeable)
35import GHC.Generics (Generic) 36import GHC.Generics (Generic)
36import Control.DeepSeq 37import Control.DeepSeq
37import Data.Default.Class 38import Data.Default.Class
38 39
39import Control.Monad.Trans.Resource 40import Control.Monad.Trans.Resource
40import Control.Monad.IO.Class 41import Control.Monad.IO.Class
41import Control.Monad.Logger 42import Control.Monad.Logger
42import Control.Monad.Reader 43import Control.Monad.Reader
43 44
44import Control.Monad (forever) 45import Control.Monad (forever)
45 46
46import Control.Concurrent.STM 47import Control.Concurrent.STM
48
49import Data.Time.Clock
47 50
48newtype PrinterMethod = PM { unPM :: forall m. (MonadResource m, MonadLogger m) => Printout -> m (Maybe PrintingError) } 51newtype PrinterMethod = PM { unPM :: forall m. (MonadResource m, MonadLogger m) => Printout -> m (Maybe PrintingError) }
49 52
@@ -52,11 +55,11 @@ data Printer = Printer
52 , queue :: TVar Queue 55 , queue :: TVar Queue
53 } 56 }
54 57
55-- | Zipper for 'Seq JobId' 58-- | Zipper for 'Seq QueueEntry'
56data Queue = Queue 59data Queue = Queue
57 { pending :: Seq JobId -- ^ Pending jobs, closest first 60 { pending :: Seq QueueEntry -- ^ Pending jobs, closest last
58 , current :: Maybe JobId 61 , current :: Maybe QueueEntry
59 , history :: Seq (JobId, Maybe PrintingError) -- ^ Completed jobs, closest first 62 , history :: Seq (QueueEntry, Maybe PrintingError) -- ^ Completed jobs, closest first
60 } 63 }
61 deriving (Typeable, Generic, NFData) 64 deriving (Typeable, Generic, NFData)
62 65
@@ -67,6 +70,12 @@ instance Default Queue where
67 , history = Seq.empty 70 , history = Seq.empty
68 } 71 }
69 72
73data QueueEntry = QueueEntry
74 { jobId :: JobId
75 , created :: UTCTime
76 }
77 deriving (Typeable, Generic, NFData)
78
70printer :: MonadResource m => m PrinterMethod -> m Printer 79printer :: MonadResource m => m PrinterMethod -> m Printer
71printer p = Printer <$> p <*> liftIO (newTVarIO def) 80printer p = Printer <$> p <*> liftIO (newTVarIO def)
72 81
@@ -80,13 +89,13 @@ runPrinter :: ( MonadReader ConnectionPool m
80 ) => Printer -> m () 89 ) => Printer -> m ()
81-- ^ Loop 'forever' pushing entries from the 'Queue' associated to a 'Printer' into its 'print'-method 90-- ^ Loop 'forever' pushing entries from the 'Queue' associated to a 'Printer' into its 'print'-method
82runPrinter Printer{..} = forever $ do 91runPrinter Printer{..} = forever $ do
83 jobId <- atomically' $ do 92 entry@(QueueEntry{..}) <- atomically' $ do
84 (Queue queuePending Nothing history) <- readTVar queue 93 (Queue queuePending Nothing history) <- readTVar queue
85 case viewl queuePending of 94 case viewl queuePending of
86 EmptyL -> retry 95 EmptyL -> retry
87 (jobId :< remaining) -> do 96 (current :< remaining) -> do
88 writeTVar queue $!! Queue remaining (Just jobId) history 97 writeTVar queue $!! Queue remaining (Just current) history
89 return jobId 98 return current
90 job <- runSqlPool (get jobId) =<< ask 99 job <- runSqlPool (get jobId) =<< ask
91 case job of 100 case job of
92 Nothing -> do 101 Nothing -> do
@@ -96,7 +105,7 @@ runPrinter Printer{..} = forever $ do
96 $(logInfo) . T.pack $ "Printing " ++ show (unSqlBackendKey . unJobKey $ jobId) 105 $(logInfo) . T.pack $ "Printing " ++ show (unSqlBackendKey . unJobKey $ jobId)
97 printReturn <- (unPM print) (jobContent job) -- We could, at this point, do some exception handling. It was decided that this would be undesirable, because we really don't have any idea what exceptions to catch 106 printReturn <- (unPM print) (jobContent job) -- We could, at this point, do some exception handling. It was decided that this would be undesirable, because we really don't have any idea what exceptions to catch
98 maybe (return ()) ($(logWarn) . T.pack . (("Error while printing " ++ show (unSqlBackendKey . unJobKey $ jobId) ++ ": ") ++) . show) $ printReturn 107 maybe (return ()) ($(logWarn) . T.pack . (("Error while printing " ++ show (unSqlBackendKey . unJobKey $ jobId) ++ ": ") ++) . show) $ printReturn
99 atomically' $ modifyTVar' queue (\Queue{..} -> force . Queue pending Nothing $ (jobId, printReturn) <| history) 108 atomically' $ modifyTVar' queue (\Queue{..} -> force . Queue pending Nothing $ (entry, printReturn) <| history)
100 109
101addToQueue :: ( MonadReader ConnectionPool m 110addToQueue :: ( MonadReader ConnectionPool m
102 , MonadLogger m 111 , MonadLogger m
@@ -105,6 +114,12 @@ addToQueue :: ( MonadReader ConnectionPool m
105 ) => Printout -> Printer -> m JobId 114 ) => Printout -> Printer -> m JobId
106addToQueue printout Printer{..} = do 115addToQueue printout Printer{..} = do
107 jobId <- runSqlPool (insert $ Job printout) =<< ask 116 jobId <- runSqlPool (insert $ Job printout) =<< ask
117 time <- liftIO getCurrentTime
118 let
119 entry = QueueEntry
120 { jobId = jobId
121 , created = time
122 }
108 $(logInfo) . T.pack $ "Queueing " ++ show (unSqlBackendKey . unJobKey $ jobId) 123 $(logInfo) . T.pack $ "Queueing " ++ show (unSqlBackendKey . unJobKey $ jobId)
109 atomically' $ modifyTVar' queue (\Queue{..} -> force $ Queue (jobId <| pending) current history) 124 atomically' $ modifyTVar' queue (\Queue{..} -> force $ Queue (pending |> entry) current history)
110 return jobId 125 return jobId