packages feed

mohws-0.2: src/Network/MoHWS/Part/DynHS.hs

-- Copyright 2006 Bjorn Bringert
module Network.MoHWS.Part.DynHS where

import Network.MoHWS.Part.DynHS.GHCUtil
          (Session, initGHC, setLogAction, withCleanUp, getFileValue, )

import qualified Network.MoHWS.Module.Description as ModuleDesc
import qualified Network.MoHWS.Module             as Module
import qualified Network.MoHWS.HTTP.Header as Header
import qualified Network.MoHWS.HTTP.Response as Response
import qualified Network.MoHWS.Server.Request as ServerRequest
import qualified Network.MoHWS.Server.Context as ServerContext
import qualified Network.MoHWS.Stream as Stream
import Network.MoHWS.Server.Request (serverFilename, )
import Network.MoHWS.Logger.Error (debug, logError, )

import Network.MoHWS.Configuration as Config

import Control.Exception as Exception
import Control.Monad.Trans.Maybe (MaybeT(MaybeT), )
import Control.Monad (liftM, mzero, )
import Data.List (isSuffixOf, )
import Data.Tuple.HT (mapFst, )


-- FIXME: keep this in config
packageDirectory :: FilePath
packageDirectory = "/usr/lib/ghc-6.8.2"  -- last working version was 6.6


desc :: (Stream.C body) => ModuleDesc.T body ext
desc =
   ModuleDesc.empty {
      ModuleDesc.name = "dynhs",
      ModuleDesc.load = loadDynHS
   }

loadDynHS :: (Stream.C body) =>
   ServerContext.T ext -> IO (Module.T body)
loadDynHS st =
    do s <- initGHC packageDirectory
       dynhsLoadConfig s st
       return $
          Module.empty {
             Module.handleRequest = dynhsHandleRequest s st
          }

dynhsLoadConfig :: Session -> ServerContext.T ext -> IO ()
dynhsLoadConfig s st = setLogAction s (logError st)

dynhsHandleRequest :: (Stream.C body) =>
   Session -> ServerContext.T ext -> ServerRequest.T body -> MaybeT IO (Response.T body)
dynhsHandleRequest s st sreq =
    if ".hs" `isSuffixOf` serverFilename sreq
      then dynhsHandleRequest2 s st sreq
      else mzero

dynhsHandleRequest2 :: (Stream.C body) =>
   Session -> ServerContext.T ext -> ServerRequest.T body -> MaybeT IO (Response.T body)
dynhsHandleRequest2 s st sreq =
   MaybeT $ withCleanUp s $
-- FIXME: lots of fake stuff here
    do debug st $ "DynHS: Loading " ++ show (serverFilename sreq)
       e_cgiMain <- logGHCErrors s st (getCgiMain s (serverFilename sreq))
       case e_cgiMain of
         Left resp -> return $ Just resp
         Right cgiMain ->
            do debug st $ "DynHS: Loaded successfully: " ++ show (serverFilename sreq)
               liftM Just $ runCgiMain st sreq cgiMain

type CGIMain = [(String,String)] -> [(String,String)] -> IO ([(String,String)], String)

getCgiMain :: Session -> FilePath -> IO CGIMain
getCgiMain s file = getFileValue s file "cgiMain"

runCgiMain :: (Stream.C body) =>
   ServerContext.T ext -> ServerRequest.T body -> CGIMain -> IO (Response.T body)
runCgiMain st _sreq cgiMain =
    -- FIXME: lots of fake stuff here
    do let env = []
           inputs = []
       (hs,content) <- cgiMain env inputs
       let headers =
              Header.group $
              map (uncurry Header.make . mapFst Header.makeName) hs
       let code = 200
           descr = "OK"
       return $
          Response.Cons code descr headers [] True $
          Response.bodyWithSizeFromString $
          Stream.fromString (Config.chunkSize (ServerContext.config st)) content

-- GHC utilities

logGHCErrors :: (Stream.C body) =>
   Session -> ServerContext.T ext -> IO a -> IO (Either (Response.T body) a)
logGHCErrors _s st f =
    liftM Right f
    `Exception.catch`
    (\e -> do logError st (show e)
              -- FIXME: include error message in response
              return $ Left $ Response.makeInternalServerError (ServerContext.config st))