{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeOperators #-} module Thermoprint.Server ( thermoprintServer , module Data.Default.Class , module Servant.Server.Internal.Enter ) where import Data.Default.Class import qualified Config.Dyre as Dyre import System.IO (hPutStrLn, stderr) import System.Exit (exitFailure) import Control.Monad ((<=<), mapM_, liftM2) import Prelude hiding ((.), id) import Control.Category import Control.Monad.Logger import Control.Monad.Reader import Control.Monad.Trans.Resource import Control.Monad.Trans.Either import Control.Monad.IO.Class import Data.Functor.Compose import Thermoprint.API hiding (JobId(..), DraftId(..)) import qualified Thermoprint.API as API (JobId(..), DraftId(..)) import Data.Set (Set) import qualified Data.Set as Set import Data.Sequence (Seq) import qualified Data.Sequence as Seq import Data.Sequence (Map) import qualified Data.Sequence as Map import qualified Network.Wai.Handler.Warp as Warp import Network.Wai (Application) import Servant import Servant.Server import Servant.Server.Internal.Enter import Database.Persist import Database.Persist.Sql import Database.Persist.TH data Config = Config { dyreError :: Maybe String , warpSettings :: Warp.Settings } instance Default Config where def = Config { dyreError = Nothing , warpSettings = Warp.defaultSettings } data HandlerInput = HandlerInput { sqlPool :: ConnectionPool } share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Job printer PrinterId content Printout Draft title DraftTitle Maybe content Printout |] thermoprintServer :: ( MonadLogger m , MonadIO m , MonadBaseControl IO m , MonadReader ConnectionPool m ) => (m :~> IO) -> Config -> IO () thermoprintServer io = Dyre.wrapMain $ Dyre.defaultParams { Dyre.projectName = "thermoprint-server" , Dyre.realMain = realMain <=< handleDyreErrors , Dyre.showError = (\cfg msg -> cfg { dyreError = Just msg }) } where handleDyreErrors cfg@(Config{..}) | Just msg <- dyreError = do hPutStrLn stderr msg exitFailure undefined | otherwise = return cfg realMain (Config{..}) = enter io $ do sqlPool <- ask runSqlPool (runMigrationSilent migrateAll) sqlPool >>= mapM_ $(logWarn) let handlerInput = HandlerInput { sqlPool = sqlPool } io' :: ReaderT HandlerInput IO :~> IO io' = runReaderTNat handlerInput liftIO . Warp.runSettings warpSettings . serve thermoprintAPI $ enter (hoistNat io') thermoprintServer' type Handler = EitherT ServantErr (ReaderT HandlerInput IO) (<||>) :: Monad m => m a -> m b -> m (a :<|> b) (<||>) = liftM2 (:<|>) infixr 9 <||> thermoprintServer' :: ServerT ThermoprintAPI Handler thermoprintServer' = listPrinters :<|> listJobs <||> queueJob :<|> getJob <||> jobStatus <||> deleteJob :<|> (listDrafts :<|> addDraft) :<|> updateDraft <||> getDraft <||> deleteDraft <||> printDraft listPrinters :: Handler (Set PrinterId) listPrinters = return Set.empty queueJob :: Maybe PrinterId -> Printout -> Handler API.JobId queueJob = return undefined printerStatus :: PrinterId -> Handler PrinterStatus printerStatus = return undefined listJobs :: Maybe PrinterId -> Maybe API.JobId -> Maybe API.JobId -> Handler (Seq (API.JobId, JobStatus)) listJobs = return undefined getJob :: API.JobId -> Handler Printout getJob = return undefined jobStatus :: API.JobId -> Handler JobStatus jobStatus = return undefined deleteJob :: API.JobId -> Handler () deleteJob = return undefined listDrafts :: Handler (Map API.DraftId (Maybe DraftTitle)) listDrafts = return undefined addDraft :: Maybe DraftTitle -> Printout -> Handler API.DraftId addDraft = return undefined updateDraft :: API.DraftId -> Maybe DraftTitle -> Printout -> Handler () updateDraft = return undefined getDraft :: API.DraftId -> Handler (Maybe DraftTitle, Printout) getDraft = return undefined deleteDraft :: API.DraftId -> Handler () deleteDraft = return undefined printDraft :: API.DraftId -> Maybe PrinterId -> Handler API.JobId printDraft = return undefined