This patch was authored and released by @gwynne.
Also fixes a couple of minor formatting and wording issues in a couple of comments.
I would've added ContentConfiguration
for the .jsonSequence
media type, but its most effective use in a Vapor context would be via Request.Body.drain(_:)
and Response.Body.init(stream:)
, and ContentEncoder
/ContentDecoder
are not really set up for that. Here is a supposed-to-be-quick contrived example (which mostly has the effect of showcasing that BodyStreamWriter
could desperately use some Concurrency extensions!):
app.get("json-stream") { req -> Response in
var headers = HTTPHeaders()
headers.contentType = .jsonSequence
return Response(status: .ok, headers: headers, body: .init(stream: { writer in
_ = writer.eventLoop.performWithTask {
do {
let stream = AsyncStream<Int> { c in Task.detached {
for _ in 0..<100 {
try! await Task.sleep(nanoseconds: 1_000_000_000)
c.yield(Int.random(in: .min ... .max))
}
c.finish()
} }
for await i in stream {
var buffer = ByteBufferAllocator().buffer(capacity: 0)
buffer.writeBytes([0x1e]) // <RS>
try JSONEncoder().encode(["i": i], into: &buffer)
buffer.writeBytes([0x0a]) // <LF>
try await writer.eventLoop.flatSubmit { writer.write(.buffer(buffer)) }.get()
}
try await writer.eventLoop.flatSubmit { writer.write(.end) }.get()
} catch {
try? await writer.eventLoop.flatSubmit { writer.write(.error(error)) }.get()
}
}
}))
}