Holumbus-Storage-0.0.1: source/Holumbus/FileSystem/Node/NodeData.hs
-- ----------------------------------------------------------------------------
{- |
Module : Holumbus.FileSystem.Node.NodeData
Copyright : Copyright (C) 2008 Stefan Schmidt
License : MIT
Maintainer : Stefan Schmidt (stefanschmidt@web.de)
Stability : experimental
Portability: portable
Version : 0.1
-}
-- ----------------------------------------------------------------------------
module Holumbus.FileSystem.Node.NodeData
(
-- * data types
NodeData
-- * creation and destruction
, newNode
)
where
import Prelude hiding (appendFile)
import Control.Concurrent
import Control.Monad
import Data.Maybe
import System.IO hiding (appendFile)
import System.Log.Logger
import Holumbus.Common.Debug
import Holumbus.Common.Utils
import Holumbus.FileSystem.Node
import Holumbus.FileSystem.Node.NodePort
import qualified Holumbus.FileSystem.Controller as C
import qualified Holumbus.FileSystem.Controller.ControllerPort as CP
import qualified Holumbus.FileSystem.Messages as M
import qualified Holumbus.FileSystem.Storage as S
import qualified Holumbus.FileSystem.Storage.FileStorage as FS
import Holumbus.Network.Communication
localLogger :: String
localLogger = "Holumbus.FileSystem.Node.NodeData"
-- ----------------------------------------------------------------------------
--
-- ----------------------------------------------------------------------------
-- | Node datatype.
data NodeData = NodeData {
nd_Client :: Client
, nd_Storage :: FS.FileStorage
}
data Node = Node (MVar NodeData)
-- ----------------------------------------------------------------------------
--
-- ----------------------------------------------------------------------------
newNode :: StreamName -> Maybe SocketId -> FS.FileStorage -> IO Node
newNode sn soid stor
= do
-- initialise the client
node <- newEmptyMVar
client <- newClient sn soid (dispatch (Node node))
-- open storage
stor' <- S.openStorage stor
putMVar node (NodeData client stor')
return (Node node)
dispatch
:: Node
-> M.NodeRequestMessage
-> IO (Maybe M.NodeResponseMessage)
dispatch nd msg
= do
case msg of
(M.NReqCreate i c) ->
do
createFile i c nd
return $ Just M.NRspSuccess
(M.NReqAppend i c) ->
do
appendFile i c nd
return $ Just M.NRspSuccess
(M.NReqDelete i b) ->
do
deleteFile i b nd
return $ Just M.NRspSuccess
(M.NReqCopy i cp) ->
do
copyFile i cp nd
return $ Just M.NRspSuccess
(M.NReqContains i)->
do
b <- containsFile i nd
return $ Just $ M.NRspContains b
(M.NReqGetFileContent i) ->
do
c <- getFileContent i nd
return $ Just $ M.NRspGetFileContent c
(M.NReqGetFileData i) ->
do
d <- getFileData i nd
return $ Just $ M.NRspGetFileData d
(M.NReqGetFileIds) ->
do
ls <- getFileIds nd
return $ Just $ M.NRspGetFileIds ls
_ -> return Nothing
-- ----------------------------------------------------------------------------
--
-- ----------------------------------------------------------------------------
changeStorage :: (FS.FileStorage -> IO FS.FileStorage) -> Node -> IO ()
changeStorage f (Node node)
= modifyMVar node $
\nd ->
do
stor' <- f (nd_Storage nd)
return (nd {nd_Storage = stor'}, ())
readStorage :: (FS.FileStorage-> IO a) -> Node -> IO a
readStorage f (Node node)
= withMVar node $ \nd -> f (nd_Storage nd)
-- ----------------------------------------------------------------------------
-- Typeclass instanciation (NodeClass)
-- ----------------------------------------------------------------------------
instance NodeClass Node where
closeNode (Node node)
= modifyMVar node $
\nd ->
do
infoM localLogger "closing filesystem node"
closeClient (nd_Client nd)
return (nd,())
--createFile :: S.FileId -> S.FileContent -> Node -> IO ()
createFile i c n@(Node node)
= do
client <- withMVar node $ \nd -> return (nd_Client nd)
nid <- getClientId client
case nid of
(Nothing) ->
do
--TODO better exception-handling
errorM localLogger $ "createFile \"" ++ i ++ "\" - no nid"
return ()
(Just nid') ->
do
changeStorage (\stor -> S.createFile stor i c) n
server <- getServerPort client
let cp = CP.newControllerPortFromServerPort server
C.createFile i nid' cp
return ()
--appendFile :: S.FileId -> S.FileContent -> Node -> IO ()
appendFile i c n@(Node node)
= do
client <- withMVar node $ \nd -> return (nd_Client nd)
nid <- getClientId client
case nid of
(Nothing) ->
do
--TODO better exception-handling
errorM localLogger $ "appendFile \"" ++ i ++ "\" - no nid"
return ()
(Just nid') ->
do
changeStorage (\stor -> S.appendFile stor i c) n
server <- getServerPort client
let cp = CP.newControllerPortFromServerPort server
-- Inform Controller that file has changed.
C.appendFile i nid' cp
return ()
--deleteFile :: S.FileId -> Node -> IO ()
deleteFile i b n@(Node node)
= do
client <- withMVar node $ \nd -> return (nd_Client nd)
nid <- getClientId client
case nid of
(Nothing) ->
do
--TODO better exception-handling
errorM localLogger $ "deleteFile \"" ++ i ++ "\" - no nid"
return ()
(Just nid') ->
do
changeStorage (\stor -> S.deleteFile stor i) n
if (b)
then do
server <- getServerPort client
let cp = CP.newControllerPortFromServerPort server
C.deleteFile i nid' cp
return ()
else return ()
copyFile i cp n
= do
let np = newNodePort cp
c <- getFileContent i np
-- TODO do not create new file data
--d <- getFileData i np
if (isJust c)
then do
createFile i (fromJust c) n
return ()
else do
errorM localLogger $ "copyFile: no content for \"" ++ i ++ "\" found"
return ()
--containsFile :: S.FileId -> Node -> IO Bool
containsFile i n
= do
readStorage (\stor -> S.containsFile stor i) n
--getFileContent :: S.FileId -> Node -> IO (Maybe S.FileContent)
getFileContent i n
= do
c <- readStorage (\stor -> S.getFileContent stor i) n
debugM localLogger $ "getFileContent: " ++ show c
return c
--getFileData :: S.FileId -> Node -> IO (Maybe S.FileData)
getFileData i nd
= do
readStorage (\stor -> S.getFileData stor i) nd
--getFileIds :: Node -> IO [S.FileId]
getFileIds nd
= do
readStorage (\stor -> S.getFileIds stor) nd
instance Debug Node where
printDebug (Node node)
= do
putStrLn "Node-Object (full)"
withMVar node $
\nd ->
do
printDebug (nd_Client nd)
putStrLn $ prettyRecordLine gap "Storage:" (nd_Storage nd)
where
gap = 20