mirror of
https://github.com/simonmichael/hledger.git
synced 2024-12-26 20:02:27 +03:00
web: -fweb now builds with simpleserver; the alternate -fwebhappstack builds with happstack
hack-handler-simpleserver is presumably quite a bit easier to install than happstack, and so far fits hledger's needs just as well, so it is now the default when installing with -fweb. To build with happstack, use -fwebhappstack instead. hledger --version shows which webserver was built. Also webserver thread management has been simplified so should be more consistent across platforms.
This commit is contained in:
parent
f937f59276
commit
d4965b87ff
@ -18,7 +18,7 @@ module Commands.All (
|
||||
#ifdef VTY
|
||||
module Commands.UI,
|
||||
#endif
|
||||
#ifdef WEB
|
||||
#if defined(WEB) || defined(WEBHAPPSTACK)
|
||||
module Commands.Web,
|
||||
#endif
|
||||
#ifdef CHART
|
||||
@ -37,7 +37,7 @@ import Commands.Stats
|
||||
#ifdef VTY
|
||||
import Commands.UI
|
||||
#endif
|
||||
#ifdef WEB
|
||||
#if defined(WEB) || defined(WEBHAPPSTACK)
|
||||
import Commands.Web
|
||||
#endif
|
||||
#ifdef CHART
|
||||
|
144
Commands/Web.hs
144
Commands/Web.hs
@ -13,36 +13,31 @@ import Control.Applicative.Error (Failing(Success,Failure))
|
||||
import Control.Concurrent
|
||||
import Control.Monad.Reader (ask)
|
||||
import Data.IORef (newIORef, atomicModifyIORef)
|
||||
import HSP hiding (Request,catch)
|
||||
import HSP.HTML (renderAsHTML)
|
||||
--import qualified HSX.XMLGenerator (XML)
|
||||
import Hack.Contrib.Constants (_TextHtmlUTF8)
|
||||
import Hack.Contrib.Response (set_content_type)
|
||||
import Hack.Handler.Happstack (runWithConfig,ServerConf(ServerConf))
|
||||
import Happstack.State.Control (waitForTermination)
|
||||
import Network.HTTP (urlEncode, urlDecode)
|
||||
import Network.Loli (loli, io, get, post, html, text, public)
|
||||
--import Network.Loli.Middleware.IOConfig (ioconfig)
|
||||
import Network.Loli.Type (AppUnit)
|
||||
import Network.Loli.Utils (update)
|
||||
import Options hiding (value)
|
||||
#ifdef MAKE
|
||||
import Paths_hledger_make (getDataFileName)
|
||||
#else
|
||||
import Paths_hledger (getDataFileName)
|
||||
#endif
|
||||
import System.Directory (getModificationTime)
|
||||
import System.IO.Storage (withStore, putValue, getValue)
|
||||
import System.Process (readProcess)
|
||||
import System.Time (ClockTime, getClockTime, diffClockTimes, TimeDiff(TimeDiff))
|
||||
import Text.ParserCombinators.Parsec (parse)
|
||||
-- import Text.XHtml hiding (dir, text, param, label)
|
||||
-- import Text.XHtml.Strict ((<<),(+++),(!))
|
||||
import qualified HSP (Request(..))
|
||||
|
||||
import Hack.Contrib.Constants (_TextHtmlUTF8)
|
||||
import Hack.Contrib.Response (set_content_type)
|
||||
import qualified Hack (Env, http)
|
||||
import qualified Hack.Contrib.Request (inputs, params, path)
|
||||
import qualified Hack.Contrib.Response (redirect)
|
||||
-- import qualified Text.XHtml.Strict as H
|
||||
#ifdef WEBHAPPSTACK
|
||||
import System.Process (readProcess)
|
||||
import Hack.Handler.Happstack (runWithConfig,ServerConf(ServerConf))
|
||||
#else
|
||||
import Hack.Handler.SimpleServer (run)
|
||||
#endif
|
||||
|
||||
import Network.Loli (loli, io, get, post, html, text, public)
|
||||
import Network.Loli.Type (AppUnit)
|
||||
import Network.Loli.Utils (update)
|
||||
|
||||
import HSP hiding (Request,catch)
|
||||
import qualified HSP (Request(..))
|
||||
import HSP.HTML (renderAsHTML)
|
||||
|
||||
import Commands.Add (ledgerAddTransaction)
|
||||
import Commands.Balance
|
||||
@ -50,33 +45,69 @@ import Commands.Histogram
|
||||
import Commands.Print
|
||||
import Commands.Register
|
||||
import Ledger
|
||||
import Utils (openBrowserOn)
|
||||
import Ledger.IO (readLedger)
|
||||
#
|
||||
import Options hiding (value)
|
||||
#ifdef MAKE
|
||||
import Paths_hledger_make (getDataFileName)
|
||||
#else
|
||||
import Paths_hledger (getDataFileName)
|
||||
#endif
|
||||
import Utils (openBrowserOn)
|
||||
|
||||
-- import Debug.Trace
|
||||
-- strace :: Show a => a -> a
|
||||
-- strace a = trace (show a) a
|
||||
|
||||
tcpport = 5000 :: Int
|
||||
homeurl = printf "http://localhost:%d/" tcpport
|
||||
browserdelay = 100000 -- microseconds
|
||||
|
||||
web :: [Opt] -> [String] -> Ledger -> IO ()
|
||||
web opts args l = do
|
||||
if Debug `elem` opts
|
||||
then do
|
||||
-- just run the server in the foreground
|
||||
putStrLn $ printf "starting web server on port %d in debug mode" tcpport
|
||||
server opts args l
|
||||
else do
|
||||
-- start the server (in background, so we can..) then start the web browser
|
||||
printf "starting web interface on port %d\n" tcpport
|
||||
tid <- forkIO $ server opts args l
|
||||
putStrLn "starting web browser"
|
||||
openBrowserOn homeurl
|
||||
waitForTermination
|
||||
putStrLn "shutting down web server..."
|
||||
killThread tid
|
||||
putStrLn "shutdown complete"
|
||||
unless (Debug `elem` opts) $ forkIO browser >> return ()
|
||||
server opts args l
|
||||
|
||||
browser :: IO ()
|
||||
browser = putStrLn "starting web browser" >> threadDelay browserdelay >> openBrowserOn homeurl >> return ()
|
||||
|
||||
server :: [Opt] -> [String] -> Ledger -> IO ()
|
||||
server opts args l =
|
||||
-- server initialisation
|
||||
withStore "hledger" $ do -- IO ()
|
||||
printf "starting web server on port %d\n" tcpport
|
||||
t <- getCurrentLocalTime
|
||||
webfiles <- getDataFileName "web"
|
||||
putValue "hledger" "ledger" l
|
||||
#ifdef WEBHAPPSTACK
|
||||
hostname <- readProcess "hostname" [] "" `catch` \_ -> return "hostname"
|
||||
runWithConfig (ServerConf tcpport hostname) $ -- (Env -> IO Response) -> IO ()
|
||||
#else
|
||||
run tcpport $ -- (Env -> IO Response) -> IO ()
|
||||
#endif
|
||||
\env -> do -- IO Response
|
||||
-- general request handler
|
||||
let a = intercalate "+" $ reqparam env "a"
|
||||
p = intercalate "+" $ reqparam env "p"
|
||||
opts' = opts ++ [Period p]
|
||||
args' = args ++ (map urlDecode $ words a)
|
||||
l' <- fromJust `fmap` getValue "hledger" "ledger"
|
||||
l'' <- reloadIfChanged opts' args' l'
|
||||
-- declare path-specific request handlers
|
||||
let command :: [String] -> ([Opt] -> FilterSpec -> Ledger -> String) -> AppUnit
|
||||
command msgs f = string msgs $ f opts' (optsToFilterSpec opts' args' t) l''
|
||||
(loli $ -- State Loli () -> (Env -> IO Response)
|
||||
do
|
||||
get "/balance" $ command [] showBalanceReport -- String -> ReaderT Env (StateT Response IO) () -> State Loli ()
|
||||
get "/register" $ command [] showRegisterReport
|
||||
get "/histogram" $ command [] showHistogram
|
||||
get "/transactions" $ ledgerpage [] l'' (showTransactions (optsToFilterSpec opts' args' t))
|
||||
post "/transactions" $ handleAddform l''
|
||||
get "/env" $ getenv >>= (text . show)
|
||||
get "/params" $ getenv >>= (text . show . Hack.Contrib.Request.params)
|
||||
get "/inputs" $ getenv >>= (text . show . Hack.Contrib.Request.inputs)
|
||||
public (Just webfiles) ["/style.css"]
|
||||
get "/" $ redirect ("transactions") Nothing
|
||||
) env
|
||||
|
||||
getenv = ask
|
||||
response = update
|
||||
@ -115,41 +146,6 @@ reloadIfChanged opts _ l = do
|
||||
-- refilter :: [Opt] -> [String] -> Ledger -> LocalTime -> IO Ledger
|
||||
-- refilter opts args l t = return $ filterAndCacheLedgerWithOpts opts args t (jtext $ journal l) (journal l)
|
||||
|
||||
server :: [Opt] -> [String] -> Ledger -> IO ()
|
||||
server opts args l =
|
||||
-- server initialisation
|
||||
withStore "hledger" $ do -- IO ()
|
||||
t <- getCurrentLocalTime
|
||||
webfiles <- getDataFileName "web"
|
||||
putValue "hledger" "ledger" l
|
||||
-- XXX hack-happstack abstraction leak
|
||||
hostname <- readProcess "hostname" [] "" `catch` \_ -> return "hostname"
|
||||
runWithConfig (ServerConf tcpport hostname) $ -- (Env -> IO Response) -> IO ()
|
||||
\env -> do -- IO Response
|
||||
-- general request handler
|
||||
let a = intercalate "+" $ reqparam env "a"
|
||||
p = intercalate "+" $ reqparam env "p"
|
||||
opts' = opts ++ [Period p]
|
||||
args' = args ++ (map urlDecode $ words a)
|
||||
l' <- fromJust `fmap` getValue "hledger" "ledger"
|
||||
l'' <- reloadIfChanged opts' args' l'
|
||||
-- declare path-specific request handlers
|
||||
let command :: [String] -> ([Opt] -> FilterSpec -> Ledger -> String) -> AppUnit
|
||||
command msgs f = string msgs $ f opts' (optsToFilterSpec opts' args' t) l''
|
||||
(loli $ -- State Loli () -> (Env -> IO Response)
|
||||
do
|
||||
get "/balance" $ command [] showBalanceReport -- String -> ReaderT Env (StateT Response IO) () -> State Loli ()
|
||||
get "/register" $ command [] showRegisterReport
|
||||
get "/histogram" $ command [] showHistogram
|
||||
get "/transactions" $ ledgerpage [] l'' (showTransactions (optsToFilterSpec opts' args' t))
|
||||
post "/transactions" $ handleAddform l''
|
||||
get "/env" $ getenv >>= (text . show)
|
||||
get "/params" $ getenv >>= (text . show . Hack.Contrib.Request.params)
|
||||
get "/inputs" $ getenv >>= (text . show . Hack.Contrib.Request.inputs)
|
||||
public (Just webfiles) ["/style.css"]
|
||||
get "/" $ redirect ("transactions") Nothing
|
||||
) env
|
||||
|
||||
ledgerpage :: [String] -> Ledger -> (Ledger -> String) -> AppUnit
|
||||
ledgerpage msgs l f = do
|
||||
env <- getenv
|
||||
|
@ -37,7 +37,7 @@ main = do
|
||||
#ifdef VTY
|
||||
| cmd `isPrefixOf` "ui" = withLedgerDo opts args cmd ui
|
||||
#endif
|
||||
#ifdef WEB
|
||||
#if defined(WEB) || defined(WEBHAPPSTACK)
|
||||
| cmd `isPrefixOf` "web" = withLedgerDo opts args cmd web
|
||||
#endif
|
||||
#ifdef CHART
|
||||
|
3
Makefile
3
Makefile
@ -1,7 +1,8 @@
|
||||
# hledger project makefile
|
||||
|
||||
# optional features described in MANUAL, comment out if you don't have the libs
|
||||
OPTFLAGS=-DWEB -DVTY
|
||||
OPTFLAGS=-DCHART -DVTY -DWEB
|
||||
#OPTFLAGS=-DCHART -DVTY -DWEBHAPPSTACK
|
||||
|
||||
# command to run during "make ci"
|
||||
CICMD=test
|
||||
|
14
Version.hs
14
Version.hs
@ -61,13 +61,15 @@ versionmsg = progname ++ "-" ++ versionstr ++ configmsg :: String
|
||||
| otherwise = " with " ++ intercalate ", " configflags
|
||||
|
||||
configflags = tail [""
|
||||
#ifdef VTY
|
||||
,"vty"
|
||||
#endif
|
||||
#ifdef WEB
|
||||
,"web"
|
||||
#endif
|
||||
#ifdef CHART
|
||||
,"chart"
|
||||
#endif
|
||||
#ifdef VTY
|
||||
,"vty"
|
||||
#endif
|
||||
#if defined(WEB)
|
||||
,"web (using simpleserver)"
|
||||
#else if defined(WEBHAPPSTACK)
|
||||
,"web (using happstack)"
|
||||
#endif
|
||||
]
|
||||
|
@ -35,7 +35,11 @@ flag vty
|
||||
default: False
|
||||
|
||||
flag web
|
||||
description: enable the web ui
|
||||
description: enable the web ui (using simpleserver)
|
||||
default: False
|
||||
|
||||
flag webhappstack
|
||||
description: enable the web ui (using happstack)
|
||||
default: False
|
||||
|
||||
flag chart
|
||||
@ -105,6 +109,21 @@ executable hledger
|
||||
if flag(web)
|
||||
cpp-options: -DWEB
|
||||
other-modules:Commands.Web
|
||||
build-depends:
|
||||
hsp
|
||||
,hsx
|
||||
,xhtml >= 3000.2
|
||||
,loli
|
||||
,io-storage
|
||||
,hack-contrib
|
||||
,hack
|
||||
,hack-handler-simpleserver
|
||||
,HTTP >= 4000.0
|
||||
,applicative-extras
|
||||
|
||||
if flag(webhappstack)
|
||||
cpp-options: -DWEBHAPPSTACK
|
||||
other-modules:Commands.Web
|
||||
build-depends:
|
||||
hsp
|
||||
,hsx
|
||||
|
Loading…
Reference in New Issue
Block a user