This is done to be more consistent with future field naming conventions, and to make automatic generation of lenses simpler. See discussion in \#1545. rsOpts -> _rsReportOpts rsToday -> _rsDay rsQuery -> _rsQuery rsQueryOpts -> _rsQueryOpts
		
			
				
	
	
		
			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
 | 
						|
 |