Network-NineP 0.1.1 → 0.2.0
raw patch · 4 files changed
+121/−56 lines, 4 filesdep +convertibledep +staterefdep ~binarydep ~monad-loopsdep ~network
Dependencies added: convertible, stateref
Dependency ranges changed: binary, monad-loops, network
Files
- Network-NineP.cabal +14/−11
- Network/NineP/File.hs +30/−43
- Network/NineP/File/Instances.hs +75/−0
- Network/NineP/Server.hs +2/−2
Network-NineP.cabal view
@@ -1,5 +1,5 @@ Name: Network-NineP-Version: 0.1.1+Version: 0.2.0 Description: A library providing one with a somewhat higher level interface to 9P2000 protocol than existing implementations. Designed to facilitate rapid development of synthetic filesystems. Synopsis: High-level abstraction over 9P protocol Maintainer: Sergey Alirzaev <zl29ah@gmail.com>@@ -9,16 +9,16 @@ Build-Type: Simple Cabal-Version: >= 1.6 Stability: Experimental-Tested-With: GHC == 7.6.1+Tested-With: GHC == 7.8.2 Source-repository head- type: darcs- location: http://patch-tag.com/r/L29Ah/Network-NineP+ type: git+ location: https://github.com/l29ah/Network-NineP.git Source-repository this- type: darcs- location: http://patch-tag.com/r/L29Ah/Network-NineP- tag: 0.1.1+ type: git+ location: https://github.com/l29ah/Network-NineP.git+ tag: 0.2.0 Library Build-Depends:@@ -26,18 +26,21 @@ bytestring >= 0.9.2.1 && < 0.11, containers >= 0.4.2.1 && < 0.6, NineP >= 0.0.2 && < 0.1,- network >= 2.3.0.14 && < 2.5,- binary >= 0.5.1.0 && < 0.7,+ network >= 2.3.0.14 && < 2.6,+ binary >= 0.5.1.0 && < 0.8, mtl >= 2.1.2 && < 2.2,- monad-loops >= 0.3.3.0 && < 0.4,+ monad-loops >= 0.3.3.0 && < 0.5, regex-posix >= 0.95.2 && < 0.96, mstate >= 0.2.4 && < 0.3,- transformers >= 0.3.0.0 && < 0.4+ transformers >= 0.3.0.0 && < 0.4,+ stateref >= 0.3 && < 0.4,+ convertible >= 1.0.11.1 && < 1.2 Exposed-modules: Control.Monad.EmbedIO Network.NineP Network.NineP.Error Network.NineP.File+ Network.NineP.File.Instances Network.NineP.Server Other-modules: Network.NineP.Internal.File
Network/NineP/File.hs view
@@ -3,85 +3,72 @@ -- Portability : I'm too young to die -- Higher-level file patterns. Don't support read/write operations at offsets and handling stat changes as for now. -{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, OverloadedStrings #-} module Network.NineP.File- ( chanFile- , mVarFile+ ( simpleFile+ , simpleFileBy , rwFile ) where import Control.Concurrent.Chan-import Control.Concurrent.MVar import Control.Exception import Control.Monad.EmbedIO import Data.ByteString.Lazy.Char8 (ByteString) import qualified Data.ByteString.Lazy.Char8 as B+import Data.Convertible.Base+import Data.StateRef import Data.Word import Prelude hiding (read) import Network.NineP.Error import Network.NineP.Internal.File -simpleRead_ :: (Monad m, EmbedIO m) => m ByteString -> Word64 -> Word32 -> ErrorT NineError m ByteString-simpleRead_ get offset count = case offset of+simpleRead :: (Monad m, EmbedIO m) => m ByteString -> Word64 -> Word32 -> ErrorT NineError m ByteString+simpleRead get offset count = case offset of _ -> do r <- lift $ tryE $ get either (throwError . OtherError . (show :: SomeException -> String)) (return . B.take (fromIntegral count)) r --_ -> throwError $ OtherError "can't read at offset" -simpleWrite_ :: (Monad m, EmbedIO m) => (ByteString -> m ()) -> Word64 -> ByteString -> ErrorT NineError m Word32-simpleWrite_ put offset d = case offset of+simpleWrite :: (Monad m, EmbedIO m) => (ByteString -> m ()) -> Word64 -> ByteString -> ErrorT NineError m Word32+simpleWrite put offset d = case offset of _ -> do r <- lift $ tryE $ put d either (throwError . OtherError . (show :: SomeException -> String)) (const $ return $ fromIntegral $ B.length d) r --_ -> throwError $ OtherError "can't write at offset" -simpleRead :: (Monad m, EmbedIO m) => IO ByteString -> Word64 -> Word32 -> ErrorT NineError m ByteString-simpleRead get offset count = case offset of- _ -> do- d <- lift $ liftIO $ get- return $ B.take (fromIntegral count) $ d- --_ -> throwError $ OtherError "can't read at offset" -simpleWrite :: (Monad m, EmbedIO m) => (ByteString -> IO ()) -> Word64 -> ByteString -> ErrorT NineError m Word32-simpleWrite put offset d = case offset of- _ -> do- lift $ liftIO $ put d- return $ fromIntegral $ B.length d- --_ -> throwError $ OtherError "can't write at offset"---- |A file that reads and writes using simple user-specified callbacks+-- TODO remove+-- |A file that reads and writes using simple user-specified callbacks. rwFile :: forall m. (EmbedIO m) => String -- ^File name -> Maybe (m ByteString) -- ^Read handler -> Maybe (ByteString -> m ()) -- ^Write handler -> NineFile m-rwFile name rc wc = (boringFile name :: NineFile m) {- read = maybe (read $ (boringFile "" :: NineFile m)) (simpleRead_) rc,- write = maybe (write $ (boringFile "" :: NineFile m)) (simpleWrite_) wc- }+rwFile name rc wc = simpleFileBy name (maybe (fst nulls) id rc, maybe (snd nulls) id wc) (id, id) --- |A file that reads from and writes to the specified Chans-chanFile :: forall m. (Monad m, EmbedIO m)- => String -- ^File name- -> Maybe (Chan ByteString) -- ^@Chan@ to read from- -> Maybe (Chan ByteString) -- ^@Chan@ to write to+-- FIXME sane errors+nulls :: MonadIO m => (m a, a -> m ())+nulls = (throw $ Underflow, const $ return ())++-- |A file that reads from and writes to the supplied 'Ref' instances, with converstion to the appropriate types. See 'Network.NineP.File.Instances', 'Data.Convertible.Instances' and 'Data.StateRef.Instances'. Use '()', if the file is meant to be read-only/write-only.+simpleFile :: forall a b m rr wr. (Monad m, EmbedIO m, ReadRef rr m a, Convertible a ByteString, WriteRef wr m b, Convertible ByteString b)+ => String+ -> rr+ -> wr -> NineFile m-chanFile name rc wc = (boringFile name :: NineFile m) {- read = maybe (read $ (boringFile "" :: NineFile m)) (simpleRead . readChan) rc,- write = maybe (write $ (boringFile "" :: NineFile m)) (simpleWrite . writeChan) wc- }+simpleFile name rr wr = simpleFileBy name (readReference rr, writeReference wr) (convert, convert) --- |A file that reads from and writes to the specified MVars-mVarFile :: forall m. (Monad m, EmbedIO m)- => String -- ^File name- -> Maybe (MVar ByteString) -- ^@MVar@ to read from- -> Maybe (MVar ByteString) -- ^@MVar@ to write to+-- |Typeclass-free version of 'simpleFile'.+simpleFileBy :: forall a b m. (Monad m, EmbedIO m)+ => String+ -> (m a, b -> m ())+ -> (a -> ByteString, ByteString -> b) -> NineFile m-mVarFile name rc wc = (boringFile name :: NineFile m) {- read = maybe (read $ (boringFile "" :: NineFile m)) (simpleRead . takeMVar) rc,- write = maybe (write $ (boringFile "" :: NineFile m)) (simpleWrite . putMVar) wc+simpleFileBy name (rd, wr) (rdc, wrc) = (boringFile name :: NineFile m) {+ read = simpleRead $ liftM rdc $ rd,+ write = simpleWrite $ wr . wrc }
+ Network/NineP/File/Instances.hs view
@@ -0,0 +1,75 @@+-- |+-- Stability : Ultra-Violence+-- Portability : I'm too young to die+-- Instances for dealing with the usual data.++{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverloadedStrings, OverlappingInstances, ViewPatterns #-}++module Network.NineP.File.Instances+ ( Convertible+ , ReadRef+ , WriteRef+ ) where++import Control.Concurrent.Chan+import Control.Monad+import Control.Exception+import Data.ByteString.Lazy.Char8 (ByteString)+import qualified Data.ByteString.Lazy.Char8 as B+import Data.Char+import Data.Convertible.Base+import Data.Convertible.Instances+import Data.StateRef+import Data.Typeable+import Network.NineP.File++-- How do I avoid writing that?+trim xs = dropSpaceTail "" $ dropWhile isSpace xs++dropSpaceTail maybeStuff "" = ""+dropSpaceTail maybeStuff (x:xs)+ | isSpace x = dropSpaceTail (x:maybeStuff) xs+ | null maybeStuff = x : dropSpaceTail "" xs+ | otherwise = reverse maybeStuff ++ x : dropSpaceTail "" xs++-- | @'read'@ in @'Maybe'@.+safeRead :: (Read a) => String -> Maybe a+safeRead (reads -> [(v,"")]) = Just v+safeRead _ = Nothing++instance Convertible ByteString ByteString where+ safeConvert = Right . id++instance Convertible () ByteString where+ safeConvert x = convError "impossible to read that" x+instance Convertible ByteString () where+ safeConvert _ = Right ()++instance Convertible ByteString Bool where+ safeConvert s+ | l == "1" = Right True+ | l == "true" = Right True+ | l == "0" = Right False+ | l == "false" = Right False+ | otherwise = convError "doesn't look like a boolean value" l+ where l = trim $ B.unpack s+instance Convertible Bool ByteString where+ safeConvert True = Right "true"+ safeConvert False = Right "false"++instance (Show a, Num a) => Convertible a ByteString where+ safeConvert = Right . B.pack . show +instance (Read a, Num a, Typeable a) => Convertible ByteString a where+ safeConvert s = maybe (convError "doesn't look like an integral value" l) id $ liftM Right =<< safeRead l+ where l = trim $ B.unpack s++-- TODO sane error+instance ReadRef () m ByteString where+ readReference = throw $ Underflow+instance Monad m => WriteRef () m ByteString where+ writeReference _ = return $ return ()++instance MonadIO m => ReadRef (Chan a) m a where+ readReference = liftIO . readChan+instance MonadIO m => WriteRef (Chan a) m a where+ writeReference r = liftIO . writeChan r
Network/NineP/Server.hs view
@@ -62,14 +62,14 @@ listen' :: HostName -> PortNumber -> IO Socket listen' hostname port = do proto <- getProtocolNumber "tcp"- bracketOnError (socket AF_INET Stream proto) sClose (\sock -> do+ bracketOnError (socket AF_INET Stream proto) Network.Socket.sClose (\sock -> do setSocketOption sock ReuseAddr 1 he <- getHostByName hostname bindSocket sock (SockAddrInet port (hostAddress he)) listen sock maxListenQueue return sock) --- |Run the actual server+-- |Run the actual server using the supplied configuration. run9PServer :: (EmbedIO m) => Config m -> IO () run9PServer cfg = do s <- connection $ addr cfg