11{-# OPTIONS_GHC -fno-warn-orphans #-}
22module Application
3- ( makeApplication
4- , getApplicationDev
3+ ( getApplicationDev
4+ , appMain
5+ , develMain
56 , makeFoundation
7+ -- * for DevelMain
8+ , getApplicationRepl
9+ , shutdownApp
10+ -- * for GHCI
11+ , handler
12+ , db
613 ) where
714
15+ import Control.Monad.Logger (liftLoc , runLoggingT )
16+ import Database.Persist.Postgresql (createPostgresqlPool , pgConnStr ,
17+ pgPoolSize , runSqlPool )
818import Import
9- import Settings
10- import Yesod.Auth
11- import Yesod.Default.Config
12- import Yesod.Default.Main
19+ import Language.Haskell.TH.Syntax (qLocation )
20+ import Network.Wai.Handler.Warp (Settings , defaultSettings ,
21+ defaultShouldDisplayException ,
22+ runSettings , setHost ,
23+ setOnException , setPort , getPort )
24+ import Network.Wai.Middleware.RequestLogger (Destination (Logger ),
25+ IPAddrSource (.. ),
26+ OutputFormat (.. ), destination ,
27+ mkRequestLogger , outputFormat )
28+ import System.Log.FastLogger (defaultBufSize , newStdoutLoggerSet ,
29+ toLogStr )
1330import Yesod.Default.Handlers
14- import Network.Wai.Middleware.RequestLogger
15- ( mkRequestLogger , outputFormat , OutputFormat (.. ), IPAddrSource (.. ), destination
16- )
17- import qualified Network.Wai.Middleware.RequestLogger as RequestLogger
18- import qualified Database.Persist
19- import Database.Persist.Sql (runMigration )
20- import Network.HTTP.Conduit (newManager , conduitManagerSettings )
21- import Control.Monad.Logger (runLoggingT )
22- import System.Log.FastLogger (newStdoutLoggerSet , defaultBufSize )
23- import Network.Wai.Logger (clockDateCacher )
24- import Data.Default (def )
25- import Yesod.Core.Types (loggerSet , Logger (Logger ))
2631
2732-- Import all relevant handler modules here.
2833import Handler.Admin
@@ -38,56 +43,135 @@ import Handler.Sitemap
3843-- comments there for more details.
3944mkYesodDispatch " App" resourcesApp
4045
41- -- This function allocates resources (such as a database connection pool),
42- -- performs initialization and creates a WAI application . This is also the
43- -- place to put your migrate statements to have automatic database
46+ -- | This function allocates resources (such as a database connection pool),
47+ -- performs initialization and return a foundation datatype value . This is also
48+ -- the place to put your migrate statements to have automatic database
4449-- migrations handled by Yesod.
45- makeApplication :: AppConfig DefaultEnv Extra -> IO Application
46- makeApplication conf = do
47- foundation <- makeFoundation conf
50+ makeFoundation :: AppSettings -> IO App
51+ makeFoundation appSettings = do
52+ -- Some basic initializations: HTTP connection manager, logger, and static
53+ -- subsite.
54+ appHttpManager <- newManager
55+ appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
56+ appStatic <-
57+ (if appMutableStatic appSettings then staticDevel else static)
58+ (appStaticDir appSettings)
4859
49- -- Initialize the logging middleware
60+ -- We need a log function to create a connection pool. We need a connection
61+ -- pool to create our foundation. And we need our foundation to get a
62+ -- logging function. To get out of this loop, we initially create a
63+ -- temporary foundation without a real connection pool, get a log function
64+ -- from there, and then create the real foundation.
65+ let mkFoundation appConnPool = App {.. }
66+ tempFoundation = mkFoundation $ error " connPool forced in tempFoundation"
67+ logFunc = messageLoggerSource tempFoundation appLogger
68+
69+ -- Create the database connection pool
70+ pool <- flip runLoggingT logFunc $ createPostgresqlPool
71+ (pgConnStr $ appDatabaseConf appSettings)
72+ (pgPoolSize $ appDatabaseConf appSettings)
73+
74+ -- Perform database migration using our application's logging settings.
75+ runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc
76+
77+ -- Return the foundation
78+ return $ mkFoundation pool
79+
80+ -- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
81+ -- applyng some additional middlewares.
82+ makeApplication :: App -> IO Application
83+ makeApplication foundation = do
5084 logWare <- mkRequestLogger def
5185 { outputFormat =
52- if development
86+ if appDetailedRequestLogging $ appSettings foundation
5387 then Detailed True
54- else Apache FromSocket
55- , destination = RequestLogger. Logger $ loggerSet $ appLogger foundation
88+ else Apache
89+ (if appIpFromHeader $ appSettings foundation
90+ then FromFallback
91+ else FromSocket )
92+ , destination = Logger $ loggerSet $ appLogger foundation
5693 }
5794
5895 -- Create the WAI application and apply middlewares
59- app <- toWaiAppPlain foundation
60- return $ logWare app
61-
62- -- | Loads up any necessary settings, creates your foundation datatype, and
63- -- performs some initialization.
64- makeFoundation :: AppConfig DefaultEnv Extra -> IO App
65- makeFoundation conf = do
66- manager <- newManager conduitManagerSettings
67- s <- staticSite
68- dbconf <- withYamlEnvironment " config/postgresql.yml" (appEnv conf)
69- Database.Persist. loadConfig >>=
70- Database.Persist. applyEnv
71- p <- Database.Persist. createPoolConfig (dbconf :: Settings. PersistConf )
72-
73- loggerSet' <- newStdoutLoggerSet defaultBufSize
74- (getter, _) <- clockDateCacher
75-
76- let logger = Yesod.Core.Types. Logger loggerSet' getter
77- foundation = App conf s p manager dbconf logger
96+ appPlain <- toWaiAppPlain foundation
97+ return $ logWare $ defaultMiddlewaresNoLogging appPlain
7898
79- -- Perform database migration using our application's logging settings.
80- runLoggingT
81- (Database.Persist. runPool dbconf (runMigration migrateAll) p)
82- (messageLoggerSource foundation logger)
83-
84- return foundation
85-
86- -- for yesod devel
87- getApplicationDev :: IO (Int , Application )
88- getApplicationDev =
89- defaultDevelApp loader makeApplication
90- where
91- loader = Yesod.Default.Config. loadConfig (configSettings Development )
92- { csParseExtra = parseExtra
93- }
99+ -- | Warp settings for the given foundation value.
100+ warpSettings :: App -> Settings
101+ warpSettings foundation =
102+ setPort (appPort $ appSettings foundation)
103+ $ setHost (appHost $ appSettings foundation)
104+ $ setOnException (\ _req e ->
105+ when (defaultShouldDisplayException e) $ messageLoggerSource
106+ foundation
107+ (appLogger foundation)
108+ $ (qLocation >>= liftLoc)
109+ " yesod"
110+ LevelError
111+ (toLogStr $ " Exception from Warp: " ++ show e))
112+ defaultSettings
113+
114+
115+
116+ -- | For yesod devel, return the Warp settings and WAI Application.
117+ getApplicationDev :: IO (Settings , Application )
118+ getApplicationDev = do
119+ settings <- getAppSettings
120+ foundation <- makeFoundation settings
121+ wsettings <- getDevSettings $ warpSettings foundation
122+ app <- makeApplication foundation
123+ return (wsettings, app)
124+
125+
126+ getAppSettings :: IO AppSettings
127+ getAppSettings = loadAppSettings [configSettingsYml] [] useEnv
128+
129+ -- | main function for use by yesod devel
130+ develMain :: IO ()
131+ develMain = develMainHelper getApplicationDev
132+
133+ -- | The @main@ function for an executable running this site.
134+ appMain :: IO ()
135+ appMain = do
136+ -- Get the settings from all relevant sources
137+ settings <- loadAppSettingsArgs
138+ -- fall back to compile-time values, set to [] to require values at runtime
139+ [configSettingsYmlValue]
140+
141+ -- allow environment variables to override
142+ useEnv
143+
144+ -- Generate the foundation from the settings
145+ foundation <- makeFoundation settings
146+
147+ -- Generate a WAI Application from the foundation
148+ app <- makeApplication foundation
149+
150+ -- Run the application with Warp
151+ runSettings (warpSettings foundation) app
152+ --------------------------------------------------------------
153+ -- Functions for DevelMain.hs (a way to run the app from GHCi)
154+ --------------------------------------------------------------
155+ getApplicationRepl :: IO (Int , App , Application )
156+ getApplicationRepl = do
157+ settings <- getAppSettings
158+ foundation <- makeFoundation settings
159+ wsettings <- getDevSettings $ warpSettings foundation
160+ app1 <- makeApplication foundation
161+ return (getPort wsettings, foundation, app1)
162+
163+ shutdownApp :: App -> IO ()
164+ shutdownApp _ = return ()
165+
166+
167+ ---------------------------------------------
168+ -- Functions for use in development with GHCi
169+ ---------------------------------------------
170+
171+ -- | Run a handler
172+ handler :: Handler a -> IO a
173+ handler h = getAppSettings >>= makeFoundation >>= flip unsafeHandler h
174+
175+ -- | Run DB queries
176+ db :: ReaderT SqlBackend (HandlerT App IO ) a -> IO a
177+ db = handler . runDB
0 commit comments