98 lines
3.6 KiB
Haskell
98 lines
3.6 KiB
Haskell
{-# LANGUAGE CPP #-}
|
|
|
|
module PostgREST.Main where
|
|
|
|
|
|
import PostgREST.App
|
|
import PostgREST.Config (AppConfig (..),
|
|
minimumPgVersion,
|
|
prettyVersion,
|
|
readOptions)
|
|
import PostgREST.DbStructure
|
|
import PostgREST.Error (pgErrResponse)
|
|
import PostgREST.Middleware
|
|
import PostgREST.Types (DbStructure)
|
|
|
|
import Control.Monad
|
|
import Data.Monoid ((<>))
|
|
import Data.String.Conversions (cs)
|
|
import Data.Time.Clock.POSIX (getPOSIXTime)
|
|
import qualified Hasql.Query as H
|
|
import qualified Hasql.Session as H
|
|
import qualified Hasql.Transaction as HT
|
|
import qualified Hasql.Decoders as HD
|
|
import qualified Hasql.Encoders as HE
|
|
import qualified Hasql.Pool as P
|
|
import Network.Wai
|
|
import Network.Wai.Handler.Warp
|
|
import Network.Wai.Middleware.RequestLogger (logStdout)
|
|
import System.IO (BufferMode (..),
|
|
hSetBuffering, stderr,
|
|
stdin, stdout)
|
|
import Web.JWT (secret)
|
|
#ifndef mingw32_HOST_OS
|
|
import System.Posix.Signals
|
|
import Control.Concurrent (myThreadId)
|
|
import Control.Exception.Base (throwTo, AsyncException(..))
|
|
#endif
|
|
|
|
isServerVersionSupported :: H.Session Bool
|
|
isServerVersionSupported = do
|
|
ver <- H.query () pgVersion
|
|
return $ read (cs ver) >= minimumPgVersion
|
|
where
|
|
pgVersion =
|
|
H.statement "SHOW server_version_num"
|
|
HE.unit (HD.singleRow $ HD.value HD.text) True
|
|
|
|
main :: IO ()
|
|
main = do
|
|
hSetBuffering stdout LineBuffering
|
|
hSetBuffering stdin LineBuffering
|
|
hSetBuffering stderr NoBuffering
|
|
|
|
conf <- readOptions
|
|
let port = configPort conf
|
|
pgSettings = cs (configDatabase conf)
|
|
appSettings = setPort port
|
|
. setServerName (cs $ "postgrest/" <> prettyVersion)
|
|
$ defaultSettings
|
|
|
|
unless (secret "secret" /= configJwtSecret conf) $
|
|
putStrLn "WARNING, running in insecure mode, JWT secret is the default value"
|
|
Prelude.putStrLn $ "Listening on port " ++
|
|
(show $ configPort conf :: String)
|
|
|
|
pool <- P.acquire (configPool conf, 10, pgSettings)
|
|
|
|
#ifndef mingw32_HOST_OS
|
|
tid <- myThreadId
|
|
void $ installHandler keyboardSignal (Catch $ do
|
|
P.release pool
|
|
throwTo tid UserInterrupt
|
|
) Nothing
|
|
#endif
|
|
|
|
result <- P.use pool $ do
|
|
supported <- isServerVersionSupported
|
|
unless supported $ error (
|
|
"Cannot run in this PostgreSQL version, PostgREST needs at least "
|
|
<> show minimumPgVersion)
|
|
getDbStructure (cs $ configSchema conf)
|
|
|
|
let dbStructure = either (error.show) id result
|
|
runSettings appSettings $ postgrest conf dbStructure pool
|
|
|
|
postgrest :: AppConfig -> DbStructure -> P.Pool -> Application
|
|
postgrest conf dbStructure pool =
|
|
let middle = (if configQuiet conf then id else logStdout) . defaultMiddle in
|
|
|
|
middle $ \ req respond -> do
|
|
time <- getPOSIXTime
|
|
body <- strictRequestBody req
|
|
|
|
let handleReq = runWithClaims conf time (app dbStructure conf body) req
|
|
resp <- either pgErrResponse id <$> P.use pool
|
|
(HT.run handleReq HT.ReadCommitted HT.Write)
|
|
respond resp
|