packages feed

sync-mht-0.2.1.0: src/main/hs/Sync/MerkleTree/Server.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
module Sync.MerkleTree.Server where

import Control.Monad.State
import Sync.MerkleTree.CommTypes
import Sync.MerkleTree.Trie
import qualified Data.Text.IO as T
import Sync.MerkleTree.Types
import qualified Data.Map as M
import Data.Map(Map)
import qualified Data.ByteString as BS
import System.IO

data ServerState
    = ServerState
    { st_handles :: Map Int Handle
    , st_nextHandle :: Int
    , st_trie :: Trie Entry
    , st_path :: FilePath
    }

type ServerMonad = StateT ServerState IO

startServerState :: FilePath -> Trie Entry -> ServerState
startServerState fp trie =
    ServerState
    { st_handles = M.empty
    , st_nextHandle = 0
    , st_trie = trie
    , st_path = fp
    }

instance Protocol ServerMonad where
    querySetReq l = get >>= (\s -> return $ querySet (st_trie s) l)
    queryHashReq l = get >>= (\s -> return $ queryHash (st_trie s) l)
    logReq (SerText msg) = liftIO (T.hPutStrLn stderr msg) >> return True
    queryFileContReq (ContHandle n) =
        do s <- get
           let Just h = M.lookup n (st_handles s)
           withHandle h n
    queryFileReq f =
        do s <- get
           h <- liftIO $ openFile (toFilePath (st_path s) f) ReadMode
           let n = st_nextHandle s
           put $ s { st_handles = M.insert n h (st_handles s), st_nextHandle = n + 1 }
           withHandle h n
    terminateReq = return True

withHandle :: Handle -> Int -> ServerMonad QueryFileResponse
withHandle h n =
    do bs <- liftIO $ BS.hGet h (2^(17::Int))
       case () of
         () | BS.null bs ->
             do liftIO $ hClose h
                modify (\s -> s { st_handles = M.delete n (st_handles s) })
                return $ Final
            | otherwise -> return $ ToBeContinued bs $ ContHandle n