diff options
-rw-r--r-- | server/src/Thermoprint/Server/Printer.hs | 65 | ||||
-rw-r--r-- | server/thermoprint-server.cabal | 1 | ||||
-rw-r--r-- | server/thermoprint-server.nix | 10 |
3 files changed, 64 insertions, 12 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) | ||
diff --git a/server/thermoprint-server.cabal b/server/thermoprint-server.cabal index 8862255..926118d 100644 --- a/server/thermoprint-server.cabal +++ b/server/thermoprint-server.cabal | |||
@@ -40,6 +40,7 @@ library | |||
40 | , either >=4.4.1 && <5 | 40 | , either >=4.4.1 && <5 |
41 | , text >=1.2.1 && <2 | 41 | , text >=1.2.1 && <2 |
42 | , stm >=2.4.4 && <3 | 42 | , stm >=2.4.4 && <3 |
43 | , deepseq >=1.4.1 && <2 | ||
43 | hs-source-dirs: src | 44 | hs-source-dirs: src |
44 | default-language: Haskell2010 | 45 | default-language: Haskell2010 |
45 | 46 | ||
diff --git a/server/thermoprint-server.nix b/server/thermoprint-server.nix index 57e94a3..69bff1d 100644 --- a/server/thermoprint-server.nix +++ b/server/thermoprint-server.nix | |||
@@ -1,5 +1,5 @@ | |||
1 | { mkDerivation, base, containers, data-default-class, dyre, either | 1 | { mkDerivation, base, containers, data-default-class, deepseq, dyre |
2 | , monad-logger, mtl, persistent, persistent-sqlite | 2 | , either, monad-logger, mtl, persistent, persistent-sqlite |
3 | , persistent-template, resourcet, servant-server, stdenv, stm, text | 3 | , persistent-template, resourcet, servant-server, stdenv, stm, text |
4 | , thermoprint-spec, transformers, wai, warp | 4 | , thermoprint-spec, transformers, wai, warp |
5 | }: | 5 | }: |
@@ -10,9 +10,9 @@ mkDerivation { | |||
10 | isLibrary = true; | 10 | isLibrary = true; |
11 | isExecutable = true; | 11 | isExecutable = true; |
12 | libraryHaskellDepends = [ | 12 | libraryHaskellDepends = [ |
13 | base containers data-default-class dyre either monad-logger mtl | 13 | base containers data-default-class deepseq dyre either monad-logger |
14 | persistent persistent-template resourcet servant-server stm text | 14 | mtl persistent persistent-template resourcet servant-server stm |
15 | thermoprint-spec transformers wai warp | 15 | text thermoprint-spec transformers wai warp |
16 | ]; | 16 | ]; |
17 | executableHaskellDepends = [ | 17 | executableHaskellDepends = [ |
18 | base monad-logger mtl persistent-sqlite resourcet | 18 | base monad-logger mtl persistent-sqlite resourcet |