Uniform.hs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. {-# LANGUAGE ExistentialQuantification #-}
  2. {- |
  3. Uniform-IO provides a typeclass for uniform access of different types of targets,
  4. and implementations for abstracting standard streams, files and network connections.
  5. This module also provides TLS wraping over other IO targets.
  6. -}
  7. module System.IO.Uniform (
  8. UniformIO(..),
  9. TlsSettings(..),
  10. SomeIO(..),
  11. mapOverInput,
  12. uGetContents
  13. ) where
  14. import Data.ByteString (ByteString)
  15. import qualified Data.ByteString.Lazy as LBS
  16. import Control.Exception
  17. import Control.Applicative ((<$>))
  18. import System.IO.Error
  19. import Data.Default.Class
  20. -- | Typeclass for uniform IO targets.
  21. class UniformIO a where
  22. {- |
  23. uRead fd n
  24. Reads a block of at most n bytes of data from the IO target.
  25. Reading will block if there's no data available, but will return immediately
  26. if any amount of data is availble.
  27. Must thow System.IO.Error.EOFError if reading beihond EOF.
  28. -}
  29. uRead :: a -> Int -> IO ByteString
  30. -- | uPut fd text
  31. --
  32. -- Writes all the bytes of text into the IO target. Takes care of retrying if needed.
  33. uPut :: a -> ByteString -> IO ()
  34. -- | fClose fd
  35. --
  36. -- Closes the IO target, releasing any allocated resource. Resources may leak if not called
  37. -- for every oppened fd.
  38. uClose :: a -> IO ()
  39. -- | startTLS fd
  40. --
  41. -- Starts a TLS connection over the IO target.
  42. startTls :: TlsSettings -> a -> IO a
  43. -- | isSecure fd
  44. --
  45. -- Indicates whether the data written or read from fd is secure at transport.
  46. isSecure :: a -> Bool
  47. -- | A type that wraps any type in the UniformIO class.
  48. data SomeIO = forall a. (UniformIO a) => SomeIO a
  49. instance UniformIO SomeIO where
  50. uRead (SomeIO s) n = uRead s n
  51. uPut (SomeIO s) t = uPut s t
  52. uClose (SomeIO s) = uClose s
  53. startTls set (SomeIO s) = SomeIO <$> startTls set s
  54. isSecure (SomeIO s) = isSecure s
  55. -- | Settings for starttls functions.
  56. data TlsSettings = TlsSettings {tlsPrivateKeyFile :: String, tlsCertificateChainFile :: String, tlsDHParametersFile :: String} deriving (Read, Show)
  57. instance Default TlsSettings where
  58. def = TlsSettings "" "" ""
  59. {- |
  60. mapOverInput io block_size f initial
  61. Reads io untill the end of file, evaluating a(i) <- f a(i-1) read_data
  62. where a(0) = initial and the last value after io reaches EOF is returned.
  63. Notice that the length of read_data might not be equal block_size.
  64. -}
  65. mapOverInput :: forall a io. UniformIO io => io -> Int -> (a -> ByteString -> IO a) -> a -> IO a
  66. mapOverInput io block f initial = do
  67. a <- tryIOError $ uRead io block
  68. case a of
  69. Left e -> if isEOFError e then return initial else throw e -- EOF
  70. Right dt -> do
  71. i <- f initial dt
  72. mapOverInput io block f i
  73. {- |
  74. Returns the entire contents recieved from this target.
  75. -}
  76. uGetContents :: UniformIO io => io -> Int -> IO LBS.ByteString
  77. uGetContents io block = LBS.fromChunks <$> mapOverInput io block atEnd []
  78. where
  79. atEnd :: [ByteString] -> ByteString -> IO [ByteString]
  80. atEnd bb b = return $ bb ++ [b]