module JmlSvc.Web ( Config(..) , flags , run ) where import Protolude import qualified Network.Wai as Wai import qualified Network.Wai.Handler.Warp as Warp import qualified Network.Wai.Middleware.RequestLogger as RL import qualified Options.Applicative as Options -- | Generic Warp configuration. data Config = Config { port :: Warp.Port -- ^ Port to listen on , accessLogs :: AccessLogs -- ^ Level of access logs to display , debugExceptions :: Bool -- ^ Whether to show detailed exception information on 500s } deriving (Eq, Show) -- | Command-line flags for generating 'Config'. flags :: Options.Parser Config flags = Config <$> Options.option Options.auto (fold [Options.long "port", Options.metavar "PORT", Options.help "Port to listen on"]) <*> Options.option (Options.eitherReader parseAccessLogs) (fold [Options.long "access-logs", Options.help "How to log HTTP access", Options.value Disabled]) <*> Options.switch (fold [Options.long "debug-exceptions", Options.help "Show exceptions on 500."]) where parseAccessLogs "none" = pure Disabled parseAccessLogs "basic" = pure Enabled parseAccessLogs "dev" = pure DevMode parseAccessLogs _ = throwError "One of 'none', 'basic', or 'dev'" -- | What level of access logs to show. data AccessLogs = Disabled -- ^ Don't show access logs. | Enabled -- ^ Show Apache-style access logs. | DevMode -- ^ Show detailed, colorful access logs. Not suitable in production. deriving (Eq, Show) -- | Run a web server for 'app'. Blocks until the server is shut down. run :: MonadIO io => Config -> Wai.Application -> io () run config@Config {..} app = liftIO $ Warp.runSettings settings (logging app) where settings = warpSettings config logging = case accessLogs of Disabled -> identity Enabled -> RL.logStdout DevMode -> RL.logStdoutDev -- | Generate warp settings from config -- -- Serve from a port and print out where we're serving from. warpSettings :: Config -> Warp.Settings warpSettings Config {..} = Warp.setOnExceptionResponse exceptionHandler . Warp.setBeforeMainLoop printPort . Warp.setPort port $ Warp.defaultSettings where printPort = putText $ "Listening on: " <> show port exceptionHandler | debugExceptions = Warp.exceptionResponseForDebug | otherwise = Warp.defaultOnExceptionResponse