Uniform.hs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. foldOverInput,
  12. uGetContents
  13. ) where
  14. import Data.ByteString (ByteString)
  15. import qualified Data.ByteString.Lazy as LBS
  16. import Control.Monad.IO.Class
  17. import Data.Default.Class
  18. import Debug.Trace
  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. -- | True when the target is at end of file
  47. isEOF :: a -> IO Bool
  48. -- | A type that wraps any type in the UniformIO class.
  49. data SomeIO = forall a. (UniformIO a) => SomeIO a
  50. instance UniformIO SomeIO where
  51. uRead (SomeIO s) = uRead s
  52. uPut (SomeIO s) = uPut s
  53. uClose (SomeIO s) = uClose s
  54. startTls set (SomeIO s) = SomeIO <$> startTls set s
  55. isSecure (SomeIO s) = isSecure s
  56. isEOF (SomeIO s) = isEOF s
  57. -- | Settings for starttls functions.
  58. data TlsSettings = TlsSettings {tlsPrivateKeyFile :: String, tlsCertificateChainFile :: String, tlsDHParametersFile :: String} deriving (Read, Show)
  59. instance Default TlsSettings where
  60. def = TlsSettings "" "" ""
  61. {- |
  62. foldOverInput io block_size f initial
  63. Reads io untill the end of file, evaluating a(i) <- f a(i-1) read_data
  64. where a(0) = initial and the last value after io reaches EOF is returned.
  65. Notice that the length of read_data might not be equal block_size.
  66. -}
  67. foldOverInput :: forall a io. UniformIO io => io -> Int -> (a -> ByteString -> IO a) -> a -> IO a
  68. foldOverInput io block f initial = do
  69. eof <- liftIO $ isEOF io
  70. if eof
  71. then return initial
  72. else do
  73. dt <- uRead io block
  74. traceShowM dt
  75. i <- f initial dt
  76. foldOverInput io block f i
  77. {- |
  78. Returns the entire contents recieved from this target.
  79. -}
  80. uGetContents :: UniformIO io => io -> Int -> IO LBS.ByteString
  81. uGetContents io block = LBS.fromChunks <$> concatData
  82. where
  83. concatData = do
  84. eof <- liftIO $ isEOF io
  85. if eof
  86. then return []
  87. else do
  88. dt <- uRead io block
  89. (dt :) <$> concatData