schedule-planner-1.0.1.1: src/SchedulePlanner/Server.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module : $Header$
Description : functions necessary for deploying the application as a webservice
Copyright : (c) Justus Adam, 2015
License : LGPL-3
Maintainer : development@justusadam.com
Stability : experimental
Portability : POSIX
Uses wai and warp to create a deployable web service instance of this software.
-}
module SchedulePlanner.Server (server, app, ServerOptions(..)) where
import Data.ByteString.Lazy (ByteString)
import Network.HTTP.Types (Header, imATeaPot418, methodOptions,
methodPost, ok200)
import Network.Wai (Application, lazyRequestBody,
remoteHost, requestMethod,
responseLBS)
import Network.Wai.Handler.Warp (run)
#ifndef NOSCRAPER
import SchedulePlanner.Scraper
#endif
import System.IO (IOMode (AppendMode), hPutStrLn,
withFile)
defaultHeaders :: [Header]
defaultHeaders =
[ ("Access-Control-Allow-Origin" , "http://justus.science")
, ("Access-Control-Allow-Methods", "POST")
, ("Access-Control-Allow-Headers", "Content-Type")
]
{-|
Options used for the "serve" subcommand.
-}
data ServerOptions = ServerOptions
{ port :: Int -- ^ default 'defaultServerPort'
, logFile :: Maybe FilePath
}
writeToLog :: FilePath -> String -> IO ()
writeToLog logfile = withFile logfile AppendMode . flip hPutStrLn
{-|
The 'Application' used for the server instance.
-}
app :: ServerOptions -> (ByteString -> ByteString) -> Application
app opts app' request respond
| rMethod == methodPost =
logPureReq ("New POST request from " ++ (show $ remoteHost request)) >>
lazyRequestBody request >>=
respond . responseLBS ok200 headers . app'
| rMethod == methodOptions = respond $ responseLBS ok200 headers "Bring it!"
| otherwise =
logPureReq ("Unhandleable request: " ++ show request) >>
respond (responseLBS imATeaPot418 [] "What are you doing to an innocent teapot?")
where
logAction logfile = withFile logfile AppendMode . flip hPutStrLn
logPureReq message =
maybe
(return ())
(flip logAction message)
(logFile opts)
logIOReq messageGetter =
maybe
(return ())
((>>=) messageGetter . logAction)
(logFile opts)
rMethod = requestMethod request
headers = defaultHeaders
{-|
Run the server.
-}
server :: ServerOptions -> (ByteString -> ByteString) -> IO ()
server opts@(ServerOptions { port = port, logFile = logfile }) =
(>>) (maybe (return ()) logInit logfile) . run port . app opts
where
logInit = flip writeToLog $ "Server starting on port " ++ show port