Uniform.hs 2.9 KB

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