You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
--| Both 'StreamGenerator' and 'ResultStream' are equivalent
21
+
-- to some *source* in streaming libraries.
22
+
StreamGenerator (..),
23
+
ToStreamGenerator (..),
24
+
ResultStream (..),
25
+
FromResultStream (..),
26
+
-- * Framing
27
+
FramingRender (..),
28
+
FramingUnrender (..),
29
+
BoundaryStrategy (..),
30
+
ByteStringParser (..),
31
+
-- ** Strategies
32
+
NoFraming,
33
+
NewlineFraming,
34
+
NetstringFraming,
35
+
) where
15
36
16
37
importControl.Arrow
17
38
(first)
18
39
importData.ByteString.Lazy
19
40
(ByteString, empty)
20
41
importqualifiedData.ByteString.Lazy.Char8asLB
42
+
importData.Foldable
43
+
(traverse_)
44
+
importData.List.NonEmpty
45
+
(NonEmpty (..))
21
46
importData.Monoid
22
47
((<>))
23
48
importData.Proxy
@@ -30,35 +55,82 @@ import GHC.TypeLits
30
55
(Nat)
31
56
importNetwork.HTTP.Types.Method
32
57
(StdMethod (..))
58
+
importSystem.IO.Unsafe
59
+
(unsafeInterleaveIO)
33
60
importText.Read
34
61
(readMaybe)
35
62
36
-
--| A Stream endpoint for a given method emits a stream of encoded values at a given Content-Type, delimited by a framing strategy. Stream endpoints always return response code 200 on success. Type synonyms are provided for standard methods.
63
+
--| A Stream endpoint for a given method emits a stream of encoded values at a
64
+
-- given Content-Type, delimited by a framing strategy. Stream endpoints always
65
+
-- return response code 200 on success. Type synonyms are provided for standard
--| Stream endpoints may be implemented as producing a @StreamGenerator@ -- a function that itself takes two emit functions -- the first to be used on the first value the stream emits, and the second to be used on all subsequent values (to allow interspersed framing strategies such as comma separation).
--| ToStreamGenerator is intended to be implemented for types such as Conduit, Pipe, etc. By implementing this class, all such streaming abstractions can be used directly as endpoints.
47
80
classToStreamGeneratorab|a->bwhere
48
-
toStreamGenerator::a->StreamGeneratorb
49
-
50
-
instanceToStreamGenerator (StreamGeneratora) a
51
-
where toStreamGenerator x = x
52
-
53
-
--| Clients reading from streaming endpoints can be implemented as producing a @ResultStream@ that captures the setup, takedown, and incremental logic for a read, being an IO continuation that takes a producer of Just either values or errors that terminates with a Nothing.
--| BuildFromStream is intended to be implemented for types such as Conduit, Pipe, etc. By implementing this class, all such streaming abstractions can be used directly on the client side for talking to streaming endpoints.
--| FromResultStream is intended to be implemented for types such as Conduit, Pipe, etc. By implementing this class, all such streaming abstractions can be used directly on the client side for talking to streaming endpoints.
100
+
classFromResultStreamab|b->awhere
101
+
fromResultStream::ResultStreama->IOb
102
+
103
+
instanceFromResultStreama (ResultStreama) where
104
+
fromResultStream =return
105
+
106
+
--| Uses 'unsafeInterleaveIO'
107
+
instanceFromResultStreama [a] where
108
+
fromResultStream x = runResultStream x lazyRead
109
+
110
+
--| Uses 'unsafeInterleaveIO'
111
+
instanceFromResultStreama (NonEmptya) where
112
+
fromResultStream x = runResultStream x $\r ->do
113
+
e <- r
114
+
case e of
115
+
Nothing->fail"Empty stream"
116
+
Just (Left er) ->fail er
117
+
Just (Right y) ->do
118
+
ys <- lazyRead r
119
+
return (y :| ys)
120
+
121
+
lazyRead::IO (Maybe (EitherStringa)) ->IO [a]
122
+
lazyRead r = go
123
+
where
124
+
go = unsafeInterleaveIO loop
125
+
126
+
loop =do
127
+
e <- r
128
+
case e of
129
+
Nothing->return[]
130
+
Just (Left er) ->fail er
131
+
Just (Right y) ->do
132
+
ys <- go
133
+
return (y : ys)
62
134
63
135
--| The FramingRender class provides the logic for emitting a framing strategy. The strategy emits a header, followed by boundary-delimited data, and finally a termination character. For many strategies, some of these will just be empty bytestrings.
--| A type of parser that can never fail, and has different parsing strategies (incremental, or EOF) depending if more input can be sent. The incremental parser should return `Nothing` if it would like to be sent a longer ByteString. If it returns a value, it also returns the remainder following that value.
--| The FramingUnrender class provides the logic for parsing a framing strategy. The outer @ByteStringParser@ strips the header from a stream of bytes, and yields a parser that can handle the remainder, stepwise. Each frame may be a ByteString, or a String indicating the error state for that frame. Such states are per-frame, so that protocols that can resume after errors are able to do so. Eventually this returns an empty ByteString to indicate termination.
0 commit comments