packages feed

haskell-ftp-0.1.0.0: Network/FTP/Backend/FileSystem.hs

{-# LANGUAGE GeneralizedNewtypeDeriving
           , OverloadedStrings
           , TypeFamilies
           , MultiParamTypeClasses
           , CPP
           #-}
module Network.FTP.Backend.FileSystem
  ( FSConf(..)
  , FSBackend(..)
  , runFSBackend
  ) where

{-|
 - Simple file system backend.
 -}

import qualified Prelude
import BasicPrelude
import System.Directory
import Filesystem.Path.CurrentOS

import Control.Monad.Trans.Reader
import Control.Monad.Trans.Control
import Control.Monad.Base

import qualified Data.ByteString.Char8 as S
import Data.Conduit
import qualified Data.Conduit.List as C
import qualified Data.Conduit.Binary as C
import qualified Data.Conduit.Process as C

import Network.FTP.Utils (dropHeadingPathSeparator)
import Network.FTP.Backend (FTPBackend(..))

data FSConf = FSConf
  { fsBase :: FilePath
  }

newtype FSBackend a = FSBackend { unFSBackend :: ReaderT FSConf (ResourceT IO) a }
    deriving ( Functor, Applicative, Monad, MonadIO
             , MonadUnsafeIO, MonadThrow, MonadResource
             )

instance MonadBase IO FSBackend where
    liftBase = FSBackend . liftBase

instance MonadBaseControl IO FSBackend where
    newtype StM FSBackend a = FSBackendStM { unFSBackendStM :: StM (ReaderT FSConf (ResourceT IO)) a }
    liftBaseWith f = FSBackend . liftBaseWith $ \runInBase -> f $ liftM FSBackendStM . runInBase . unFSBackend
    restoreM = FSBackend . restoreM . unFSBackendStM

runFSBackend :: FSConf -> FSBackend a -> IO a
runFSBackend st m = runResourceT $ runReaderT (unFSBackend m) st

makeAbsolute :: FilePath -> FSBackend FilePath
makeAbsolute path = do
    b <- FSBackend (asks fsBase)
    return $ b </> dropHeadingPathSeparator path

instance FTPBackend FSBackend where
    type UserId FSBackend = ByteString

    ftplog = liftIO . S.putStrLn

    authenticate user pass =
        if user==pass
          then return (Just user)
          else return Nothing

    list dir = do
        dir' <- lift (makeAbsolute dir)
        C.sourceCmd $ "ls -l " ++ encodeString dir'

    nlst dir = do
        dir'  <- lift (makeAbsolute dir)
        paths <- liftIO $ getDirectoryContents (encodeString dir')
        C.sourceList $ map (S.pack . (++"\n")) paths

    mkd dir =
        makeAbsolute dir >>= liftIO . createDirectory . encodeString

    dele name =
        makeAbsolute name >>= liftIO . removeFile . encodeString

    rename fname tname = do
        fname' <- makeAbsolute fname
        tname' <- makeAbsolute tname
        liftIO $ renameFile (encodeString fname') (encodeString tname')

    rmd dir = do
        dir' <- makeAbsolute dir
        liftIO $ removeDirectory (encodeString dir')

    download name =
        lift (makeAbsolute name) >>= C.sourceFile . encodeString

    upload   name =
        lift (makeAbsolute name) >>= C.sinkFile . encodeString