import Control.Monad
import Data.Maybe
import Network
+import Network.HTTP.Lucu
+import Rakka.Environment
+import Rakka.Resource.Index
+import Rakka.Resource.Object
+import Rakka.Resource.Page
import System.Console.GetOpt
+import System.Directory
import System.Environment
import System.Exit
+import System.Posix.Files
import System.Posix.Types
import System.Posix.User
defaultPort :: PortNumber
defaultPort = fromIntegral 8080
+defaultLocalStateDir :: FilePath
+defaultLocalStateDir = LOCALSTATEDIR -- replaced by CPP
+
defaultUserName :: String
defaultUserName = "daemon"
, Option ['d'] ["localstatedir"]
(ReqArg OptLSDir "DIR")
- ("Path to the database directory. (default: " ++ LOCALSTATEDIR ++ ")")
+ ("Path to the database directory. (default: " ++ defaultLocalStateDir ++ ")")
, Option ['u'] ["user"]
(ReqArg OptUserName "USER")
exitWith $ ExitFailure 1
portNum <- getPortNum opts
- uid <- getUserID opts
+ uid <- getUserID opts
+ gid <- getGroupID opts
+ lsdir <- getLocalStateDir opts
+
+ createLocalStateDir lsdir uid gid
+
+ setGroupID gid
+ setUserID uid
+
+ env <- setupEnv lsdir portNum
+ runHttpd (envLucuConf env) (resTree env) [fallbackPage env]
- print portNum
- print uid
+
+resTree :: Environment -> ResTree
+resTree env
+ = mkResTree [ ([] , resIndex env)
+ , (["object"], resObject env)
+ ]
getPortNum :: [CmdOpt] -> IO PortNumber
userEnt <- getUserEntryForName name
return $ userID userEnt
-
\ No newline at end of file
+
+
+getGroupID :: [CmdOpt] -> IO GroupID
+getGroupID opts
+ = do let xs = mapMaybe (\ x -> case x of
+ OptGroupName n -> Just n
+ _ -> Nothing) opts
+ name = case xs of
+ [] -> defaultGroupName
+ (x:[]) -> x
+ _ -> error "too many --group options."
+
+ groupEnt <- getGroupEntryForName name
+ return $ groupID groupEnt
+
+
+getLocalStateDir :: [CmdOpt] -> IO FilePath
+getLocalStateDir opts
+ = do let xs = mapMaybe (\ x -> case x of
+ OptLSDir n -> Just n
+ _ -> Nothing) opts
+ path = case xs of
+ [] -> defaultLocalStateDir
+ (x:[]) -> x
+ _ -> error "too many --localstatedir options."
+
+ return path
+
+
+createLocalStateDir :: FilePath -> UserID -> GroupID -> IO ()
+createLocalStateDir path uid gid
+ = do createDirectoryIfMissing True path
+ setOwnerAndGroup path uid gid
GHC == 6.6.1
Build-Depends:
base, network, unix, Lucu
+Data-Files:
+ defaultPages/Main_Page
+ schemas/rakka-page-1.0.rng
Executable:
rakka
--- /dev/null
+module Rakka.Environment
+ ( Environment(..)
+ , setupEnv
+ )
+ where
+
+import Network
+import qualified Network.HTTP.Lucu.Config as LC
+
+
+data Environment = Environment {
+ envLocalStateDir :: FilePath
+ , envLucuConf :: LC.Config
+ }
+
+
+setupEnv :: FilePath -> PortNumber -> IO Environment
+setupEnv lsdir portNum
+ = do let lucuConf = LC.defaultConfig {
+ LC.cnfServerPort = PortNumber portNum
+ }
+ return $ Environment {
+ envLocalStateDir = lsdir
+ , envLucuConf = lucuConf
+ }
\ No newline at end of file
--- /dev/null
+module Rakka.Resource.Index
+ ( resIndex
+ )
+ where
+
+import Network.HTTP.Lucu
+import Rakka.Environment
+
+
+resIndex :: Environment -> ResourceDef
+resIndex env
+ = ResourceDef {
+ resUsesNativeThread = False
+ , resIsGreedy = False
+ , resGet = Just $ do setContentType $ read "text/plain"
+ output "FIXME: not implemented"
+ , resHead = Nothing
+ , resPost = Nothing
+ , resPut = Nothing
+ , resDelete = Nothing
+ }
+
--- /dev/null
+module Rakka.Resource.Object
+ ( resObject
+ )
+ where
+
+import Network.HTTP.Lucu
+import Rakka.Environment
+
+
+resObject :: Environment -> ResourceDef
+resObject env
+ = ResourceDef {
+ resUsesNativeThread = False
+ , resIsGreedy = False
+ , resGet = Just $ do setContentType $ read "text/plain"
+ output "FIXME: not implemented"
+ , resHead = Nothing
+ , resPost = Nothing
+ , resPut = Nothing
+ , resDelete = Nothing
+ }
+
--- /dev/null
+module Rakka.Resource.Page
+ ( fallbackPage
+ )
+ where
+
+import Data.Char
+import Network.HTTP.Lucu
+import Rakka.Environment
+
+
+fallbackPage :: Environment -> [String] -> IO (Maybe ResourceDef)
+fallbackPage env path
+ | null path = return Nothing
+ | null $ head path = return Nothing
+ | not $ isUpper $ head $ head path = return Nothing -- /Foo/bar のような形式でない。
+ | otherwise
+ = return $ Just $ ResourceDef {
+ resUsesNativeThread = False
+ , resIsGreedy = True
+ , resGet = Just $ handleGet env path
+ , resHead = Nothing
+ , resPost = Nothing
+ , resPut = Just $ handlePut env path
+ , resDelete = Just $ handleDelete env path
+ }
+
+
+handleGet :: Environment -> [String] -> Resource ()
+handleGet = fail "FIXME: not implemented"
+
+
+handlePut :: Environment -> [String] -> Resource ()
+handlePut = fail "FIXME: not implemented"
+
+
+handleDelete :: Environment -> [String] -> Resource ()
+handleDelete = fail "FIXME: not implemented"
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<page xmlns="http://cielonegro.org/schema/Rakka/Page/1.0"
+ type="text/x-rakka">
+ <textData>
+ This is the main page. Hello, world!
+ </textData>
+</page>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<element name="page"
+ ns="http://cielonegro.org/schema/Rakka/Page/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns="http://relaxng.org/ns/structure/1.0">
+
+ <attribute name="type">
+ <text />
+ </attribute>
+
+ <choice>
+ <element name="textData">
+ <text />
+ </element>
+
+ <element name="binaryData">
+ <text />
+ </element>
+ </choice>
+</element>