118 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
| {-|
 | |
| 
 | |
| hledger-web - a hledger add-on providing a web interface.
 | |
| Copyright (c) 2007-2020 Simon Michael <simon@joyful.com>
 | |
| Released under GPL version 3 or later.
 | |
| 
 | |
| -}
 | |
| 
 | |
| {-# LANGUAGE MultiWayIf #-}
 | |
| {-# LANGUAGE NamedFieldPuns #-}
 | |
| {-# LANGUAGE OverloadedStrings #-}
 | |
| 
 | |
| module Hledger.Web.Main where
 | |
| 
 | |
| import Control.Exception (bracket)
 | |
| import Control.Monad (when)
 | |
| import Data.String (fromString)
 | |
| import qualified Data.Text as T
 | |
| import Network.Socket
 | |
| import Network.Wai (Application)
 | |
| import Network.Wai.Handler.Warp (runSettings, runSettingsSocket, defaultSettings, setHost, setPort)
 | |
| import Network.Wai.Handler.Launch (runHostPortFullUrl)
 | |
| import Prelude hiding (putStrLn)
 | |
| import System.Directory (removeFile)
 | |
| import System.Environment ( getArgs, withArgs )
 | |
| import System.Exit (exitSuccess, exitFailure)
 | |
| import System.IO (hFlush, stdout)
 | |
| import System.PosixCompat.Files (getFileStatus, isSocket)
 | |
| import Text.Printf (printf)
 | |
| import Yesod.Default.Config
 | |
| import Yesod.Default.Main (defaultDevelApp)
 | |
| 
 | |
| import Hledger
 | |
| import Hledger.Cli hiding (progname,prognameandversion)
 | |
| import Hledger.Utils.UTF8IOCompat (putStrLn)
 | |
| import Hledger.Web.Application (makeApplication)
 | |
| import Hledger.Web.Settings (Extra(..), parseExtra)
 | |
| import Hledger.Web.Test (hledgerWebTest)
 | |
| import Hledger.Web.WebOptions
 | |
| 
 | |
| -- Run in fast reloading mode for yesod devel.
 | |
| hledgerWebDev :: IO (Int, Application)
 | |
| hledgerWebDev =
 | |
|   withJournalDo (cliopts_ defwebopts) (defaultDevelApp loader . makeApplication defwebopts)
 | |
|   where
 | |
|     loader =
 | |
|       Yesod.Default.Config.loadConfig
 | |
|         (configSettings Development) {csParseExtra = parseExtra}
 | |
| 
 | |
| -- Run normally.
 | |
| hledgerWebMain :: IO ()
 | |
| hledgerWebMain = do
 | |
|   wopts@WebOpts{cliopts_=copts@CliOpts{debug_, rawopts_}} <- getHledgerWebOpts
 | |
|   when (debug_ > 0) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show wopts)
 | |
|   if
 | |
|     | "help"            `inRawOpts` rawopts_ -> putStr (showModeUsage webmode) >> exitSuccess
 | |
|     | "info"            `inRawOpts` rawopts_ -> runInfoForTopic "hledger-web" Nothing
 | |
|     | "man"             `inRawOpts` rawopts_ -> runManForTopic  "hledger-web" Nothing
 | |
|     | "version"         `inRawOpts` rawopts_ -> putStrLn prognameandversion >> exitSuccess
 | |
|     --  "binary-filename" `inRawOpts` rawopts_ -> putStrLn (binaryfilename progname)
 | |
|     | "test"            `inRawOpts` rawopts_ -> do
 | |
|       -- remove --test and --, leaving other args for hspec
 | |
|       filter (not . (`elem` ["--test","--"])) <$> getArgs >>= flip withArgs hledgerWebTest
 | |
|     | otherwise                              -> withJournalDo copts (web wopts)
 | |
| 
 | |
| -- | The hledger web command.
 | |
| web :: WebOpts -> Journal -> IO ()
 | |
| web opts j = do
 | |
|   let initq = _rsQuery . reportspec_ $ cliopts_ opts
 | |
|       j' = filterJournalTransactions initq j
 | |
|       h = host_ opts
 | |
|       p = port_ opts
 | |
|       u = base_url_ opts
 | |
|       staticRoot = T.pack <$> file_url_ opts
 | |
|       appconfig = AppConfig{appEnv = Development
 | |
|                            ,appHost = fromString h
 | |
|                            ,appPort = p
 | |
|                            ,appRoot = T.pack u
 | |
|                            ,appExtra = Extra "" Nothing staticRoot
 | |
|                            }
 | |
|   app <- makeApplication opts j' appconfig
 | |
|   -- XXX would like to allow a host name not just an IP address here
 | |
|   _ <- printf "Serving web %s on %s:%d with base url %s\n"
 | |
|          (if serve_api_ opts then "API" else "UI and API" :: String) h p u
 | |
|   if serve_ opts || serve_api_ opts
 | |
|     then do
 | |
|       putStrLn "Press ctrl-c to quit"
 | |
|       hFlush stdout
 | |
|       let warpsettings = setHost (fromString h) (setPort p defaultSettings)
 | |
|       case socket_ opts of
 | |
|         Just s -> do
 | |
|           if isUnixDomainSocketAvailable then
 | |
|             bracket
 | |
|               (do
 | |
|                   sock <- socket AF_UNIX Stream 0
 | |
|                   setSocketOption sock ReuseAddr 1
 | |
|                   bind sock $ SockAddrUnix s
 | |
|                   listen sock maxListenQueue
 | |
|                   return sock
 | |
|               )
 | |
|               (\_ -> do
 | |
|                   sockstat <-  getFileStatus s
 | |
|                   when (isSocket sockstat) $ removeFile s
 | |
|               )
 | |
|               (\sock -> Network.Wai.Handler.Warp.runSettingsSocket warpsettings sock app)
 | |
|             else do
 | |
|               putStrLn "Unix domain sockets are not available on your operating system"
 | |
|               putStrLn "Please try again without --socket"
 | |
|               exitFailure
 | |
|         Nothing -> Network.Wai.Handler.Warp.runSettings warpsettings app
 | |
|     else do
 | |
|       putStrLn "This server will exit after 2m with no browser windows open (or press ctrl-c)"
 | |
|       putStrLn "Opening web browser..."
 | |
|       hFlush stdout
 | |
|       -- exits after 2m of inactivity (hardcoded)
 | |
|       Network.Wai.Handler.Launch.runHostPortFullUrl h p u app
 | |
| 
 |