@@ -28,9 +28,19 @@ where Upstream.Element == ArraySlice<UInt8> {
2828 /// The upstream sequence.
2929 private let upstream : Upstream
3030
31+ /// A closure that determines whether the given byte chunk should be forwarded to the consumer.
32+ /// - Parameter: A byte chunk.
33+ /// - Returns: `true` if the byte chunk should be forwarded, `false` if this byte chunk is the terminating sequence.
34+ private let predicate : @Sendable ( ArraySlice < UInt8 > ) -> Bool
35+
3136 /// Creates a new sequence.
32- /// - Parameter upstream: The upstream sequence of arbitrary byte chunks.
33- public init ( upstream: Upstream ) { self . upstream = upstream }
37+ /// - Parameters:
38+ /// - upstream: The upstream sequence of arbitrary byte chunks.
39+ /// - predicate: A closure that determines whether the given byte chunk should be forwarded to the consumer.
40+ public init ( upstream: Upstream , while predicate: @escaping @Sendable ( ArraySlice < UInt8 > ) -> Bool ) {
41+ self . upstream = upstream
42+ self . predicate = predicate
43+ }
3444}
3545
3646extension ServerSentEventsDeserializationSequence : AsyncSequence {
@@ -46,7 +56,16 @@ extension ServerSentEventsDeserializationSequence: AsyncSequence {
4656 var upstream : UpstreamIterator
4757
4858 /// The state machine of the iterator.
49- var stateMachine : StateMachine = . init( )
59+ var stateMachine : StateMachine
60+
61+ /// Creates a new sequence.
62+ /// - Parameters:
63+ /// - upstream: The upstream sequence of arbitrary byte chunks.
64+ /// - predicate: A closure that determines whether the given byte chunk should be forwarded to the consumer.
65+ init ( upstream: UpstreamIterator , while predicate: @escaping ( ( ArraySlice < UInt8 > ) -> Bool ) ) {
66+ self . upstream = upstream
67+ self . stateMachine = . init( while: predicate)
68+ }
5069
5170 /// Asynchronously advances to the next element and returns it, or ends the
5271 /// sequence if there is no next element.
@@ -70,7 +89,7 @@ extension ServerSentEventsDeserializationSequence: AsyncSequence {
7089 /// Creates the asynchronous iterator that produces elements of this
7190 /// asynchronous sequence.
7291 public func makeAsyncIterator( ) -> Iterator < Upstream . AsyncIterator > {
73- Iterator ( upstream: upstream. makeAsyncIterator ( ) )
92+ Iterator ( upstream: upstream. makeAsyncIterator ( ) , while : predicate )
7493 }
7594}
7695
@@ -79,26 +98,30 @@ extension AsyncSequence where Element == ArraySlice<UInt8>, Self: Sendable {
7998 /// Returns another sequence that decodes each event's data as the provided type using the provided decoder.
8099 ///
81100 /// Use this method if the event's `data` field is not JSON, or if you don't want to parse it using `asDecodedServerSentEventsWithJSONData`.
101+ /// - Parameter: A closure that determines whether the given byte chunk should be forwarded to the consumer.
82102 /// - Returns: A sequence that provides the events.
83- public func asDecodedServerSentEvents( ) -> ServerSentEventsDeserializationSequence <
84- ServerSentEventsLineDeserializationSequence < Self >
85- > { . init( upstream: ServerSentEventsLineDeserializationSequence ( upstream: self ) ) }
86-
103+ public func asDecodedServerSentEvents(
104+ while predicate: @escaping @Sendable ( ArraySlice < UInt8 > ) -> Bool = { _ in true }
105+ ) -> ServerSentEventsDeserializationSequence < ServerSentEventsLineDeserializationSequence < Self > > {
106+ . init( upstream: ServerSentEventsLineDeserializationSequence ( upstream: self ) , while: predicate)
107+ }
87108 /// Returns another sequence that decodes each event's data as the provided type using the provided decoder.
88109 ///
89110 /// Use this method if the event's `data` field is JSON.
90111 /// - Parameters:
91112 /// - dataType: The type to decode the JSON data into.
92113 /// - decoder: The JSON decoder to use.
114+ /// - predicate: A closure that determines whether the given byte sequence is the terminating byte sequence defined by the API.
93115 /// - Returns: A sequence that provides the events with the decoded JSON data.
94116 public func asDecodedServerSentEventsWithJSONData< JSONDataType: Decodable > (
95117 of dataType: JSONDataType . Type = JSONDataType . self,
96- decoder: JSONDecoder = . init( )
118+ decoder: JSONDecoder = . init( ) ,
119+ while predicate: @escaping @Sendable ( ArraySlice < UInt8 > ) -> Bool = { _ in true }
97120 ) -> AsyncThrowingMapSequence <
98121 ServerSentEventsDeserializationSequence < ServerSentEventsLineDeserializationSequence < Self > > ,
99122 ServerSentEventWithJSONData < JSONDataType >
100123 > {
101- asDecodedServerSentEvents ( )
124+ asDecodedServerSentEvents ( while : predicate )
102125 . map { event in
103126 ServerSentEventWithJSONData (
104127 event: event. event,
@@ -118,10 +141,10 @@ extension ServerSentEventsDeserializationSequence.Iterator {
118141 struct StateMachine {
119142
120143 /// The possible states of the state machine.
121- enum State : Hashable {
144+ enum State {
122145
123146 /// Accumulating an event, which hasn't been emitted yet.
124- case accumulatingEvent( ServerSentEvent , buffer: [ ArraySlice < UInt8 > ] )
147+ case accumulatingEvent( ServerSentEvent , buffer: [ ArraySlice < UInt8 > ] , predicate : ( ArraySlice < UInt8 > ) -> Bool )
125148
126149 /// Finished, the terminal state.
127150 case finished
@@ -134,7 +157,9 @@ extension ServerSentEventsDeserializationSequence.Iterator {
134157 private( set) var state : State
135158
136159 /// Creates a new state machine.
137- init ( ) { self . state = . accumulatingEvent( . init( ) , buffer: [ ] ) }
160+ init ( while predicate: @escaping ( ArraySlice < UInt8 > ) -> Bool ) {
161+ self . state = . accumulatingEvent( . init( ) , buffer: [ ] , predicate: predicate)
162+ }
138163
139164 /// An action returned by the `next` method.
140165 enum NextAction {
@@ -156,20 +181,24 @@ extension ServerSentEventsDeserializationSequence.Iterator {
156181 /// - Returns: An action to perform.
157182 mutating func next( ) -> NextAction {
158183 switch state {
159- case . accumulatingEvent( var event, var buffer) :
184+ case . accumulatingEvent( var event, var buffer, let predicate ) :
160185 guard let line = buffer. first else { return . needsMore }
161186 state = . mutating
162187 buffer. removeFirst ( )
163188 if line. isEmpty {
164189 // Dispatch the accumulated event.
165- state = . accumulatingEvent( . init( ) , buffer: buffer)
166190 // If the last character of data is a newline, strip it.
167191 if event. data? . hasSuffix ( " \n " ) ?? false { event. data? . removeLast ( ) }
192+ if let data = event. data, !predicate( ArraySlice ( data. utf8) ) {
193+ state = . finished
194+ return . returnNil
195+ }
196+ state = . accumulatingEvent( . init( ) , buffer: buffer, predicate: predicate)
168197 return . emitEvent( event)
169198 }
170199 if line. first! == ASCII . colon {
171200 // A comment, skip this line.
172- state = . accumulatingEvent( event, buffer: buffer)
201+ state = . accumulatingEvent( event, buffer: buffer, predicate : predicate )
173202 return . noop
174203 }
175204 // Parse the field name and value.
@@ -193,7 +222,7 @@ extension ServerSentEventsDeserializationSequence.Iterator {
193222 }
194223 guard let value else {
195224 // An unknown type of event, skip.
196- state = . accumulatingEvent( event, buffer: buffer)
225+ state = . accumulatingEvent( event, buffer: buffer, predicate : predicate )
197226 return . noop
198227 }
199228 // Process the field.
@@ -214,11 +243,11 @@ extension ServerSentEventsDeserializationSequence.Iterator {
214243 }
215244 default :
216245 // An unknown or invalid field, skip.
217- state = . accumulatingEvent( event, buffer: buffer)
246+ state = . accumulatingEvent( event, buffer: buffer, predicate : predicate )
218247 return . noop
219248 }
220249 // Processed the field, continue.
221- state = . accumulatingEvent( event, buffer: buffer)
250+ state = . accumulatingEvent( event, buffer: buffer, predicate : predicate )
222251 return . noop
223252 case . finished: return . returnNil
224253 case . mutating: preconditionFailure ( " Invalid state " )
@@ -240,11 +269,11 @@ extension ServerSentEventsDeserializationSequence.Iterator {
240269 /// - Returns: An action to perform.
241270 mutating func receivedValue( _ value: ArraySlice < UInt8 > ? ) -> ReceivedValueAction {
242271 switch state {
243- case . accumulatingEvent( let event, var buffer) :
272+ case . accumulatingEvent( let event, var buffer, let predicate ) :
244273 if let value {
245274 state = . mutating
246275 buffer. append ( value)
247- state = . accumulatingEvent( event, buffer: buffer)
276+ state = . accumulatingEvent( event, buffer: buffer, predicate : predicate )
248277 return . noop
249278 } else {
250279 // If no value is received, drop the existing event on the floor.
0 commit comments