1 {-# OPTIONS_GHC -fno-warn-orphans #-}
15 import Control.Monad.Logger (liftLoc, runLoggingT)
16 import Database.Persist.Sqlite (createSqlitePool, runSqlPool,
17 sqlDatabase, sqlPoolSize)
19 import Language.Haskell.TH.Syntax (qLocation)
20 import Network.Wai.Handler.Warp (Settings, defaultSettings,
21 defaultShouldDisplayException,
23 setOnException, setPort, getPort)
24 import Network.Wai.Middleware.RequestLogger (Destination (Logger),
26 OutputFormat (..), destination,
27 mkRequestLogger, outputFormat)
28 import System.Log.FastLogger (defaultBufSize, newStdoutLoggerSet,
31 -- Import all relevant handler modules here.
32 -- Don't forget to add new modules to your cabal file!
36 -- This line actually creates our YesodDispatch instance. It is the second half
37 -- of the call to mkYesodData which occurs in Foundation.hs. Please see the
38 -- comments there for more details.
39 mkYesodDispatch "App" resourcesApp
41 -- | This function allocates resources (such as a database connection pool),
42 -- performs initialization and return a foundation datatype value. This is also
43 -- the place to put your migrate statements to have automatic database
44 -- migrations handled by Yesod.
45 makeFoundation :: AppSettings -> IO App
46 makeFoundation appSettings = do
47 -- Some basic initializations: HTTP connection manager, logger, and static
49 appHttpManager <- newManager
50 appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
52 (if appMutableStatic appSettings then staticDevel else static)
53 (appStaticDir appSettings)
55 -- We need a log function to create a connection pool. We need a connection
56 -- pool to create our foundation. And we need our foundation to get a
57 -- logging function. To get out of this loop, we initially create a
58 -- temporary foundation without a real connection pool, get a log function
59 -- from there, and then create the real foundation.
60 let mkFoundation appConnPool = App {..}
61 tempFoundation = mkFoundation $ error "connPool forced in tempFoundation"
62 logFunc = messageLoggerSource tempFoundation appLogger
64 -- Create the database connection pool
65 pool <- flip runLoggingT logFunc $ createSqlitePool
66 (sqlDatabase $ appDatabaseConf appSettings)
67 (sqlPoolSize $ appDatabaseConf appSettings)
69 -- Perform database migration using our application's logging settings.
70 runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc
72 -- Return the foundation
73 return $ mkFoundation pool
75 -- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
76 -- applyng some additional middlewares.
77 makeApplication :: App -> IO Application
78 makeApplication foundation = do
79 logWare <- mkRequestLogger def
81 if appDetailedRequestLogging $ appSettings foundation
84 (if appIpFromHeader $ appSettings foundation
87 , destination = Logger $ loggerSet $ appLogger foundation
90 -- Create the WAI application and apply middlewares
91 appPlain <- toWaiAppPlain foundation
92 return $ logWare $ defaultMiddlewaresNoLogging appPlain
94 -- | Warp settings for the given foundation value.
95 warpSettings :: App -> Settings
96 warpSettings foundation =
97 setPort (appPort $ appSettings foundation)
98 $ setHost (appHost $ appSettings foundation)
99 $ setOnException (\_req e ->
100 when (defaultShouldDisplayException e) $ messageLoggerSource
102 (appLogger foundation)
103 $(qLocation >>= liftLoc)
106 (toLogStr $ "Exception from Warp: " ++ show e))
109 -- | For yesod devel, return the Warp settings and WAI Application.
110 getApplicationDev :: IO (Settings, Application)
111 getApplicationDev = do
112 settings <- getAppSettings
113 foundation <- makeFoundation settings
114 wsettings <- getDevSettings $ warpSettings foundation
115 app <- makeApplication foundation
116 return (wsettings, app)
118 getAppSettings :: IO AppSettings
119 getAppSettings = loadAppSettings [configSettingsYml] [] useEnv
121 -- | main function for use by yesod devel
123 develMain = develMainHelper getApplicationDev
125 -- | The @main@ function for an executable running this site.
128 -- Get the settings from all relevant sources
129 settings <- loadAppSettingsArgs
130 -- fall back to compile-time values, set to [] to require values at runtime
131 [configSettingsYmlValue]
133 -- allow environment variables to override
136 -- Generate the foundation from the settings
137 foundation <- makeFoundation settings
139 -- Generate a WAI Application from the foundation
140 app <- makeApplication foundation
142 -- Run the application with Warp
143 runSettings (warpSettings foundation) app
146 --------------------------------------------------------------
147 -- Functions for DevelMain.hs (a way to run the app from GHCi)
148 --------------------------------------------------------------
149 getApplicationRepl :: IO (Int, App, Application)
150 getApplicationRepl = do
151 settings <- getAppSettings
152 foundation <- makeFoundation settings
153 wsettings <- getDevSettings $ warpSettings foundation
154 app1 <- makeApplication foundation
155 return (getPort wsettings, foundation, app1)
157 shutdownApp :: App -> IO ()
158 shutdownApp _ = return ()
161 ---------------------------------------------
162 -- Functions for use in development with GHCi
163 ---------------------------------------------
166 handler :: Handler a -> IO a
167 handler h = getAppSettings >>= makeFoundation >>= flip unsafeHandler h
170 db :: ReaderT SqlBackend (HandlerT App IO) a -> IO a