With Suave 2.4.0 supporting TransferEncoding.chunked
and HttpOutput.writeChunk
I have written the below code to stream out data over HTTP.
let sendStrings getStringsFromProducer : WebPart =
Writers.setStatus HTTP_200 >=>
TransferEncoding.chunked (fun conn -> socket {
let refConn = ref conn
for str in getStringsFromProducer do
let! (_, conn) = (str |> stringToBytes |> HttpOutput.writeChunk) !refConn
refConn := conn
return! HttpOutput.writeChunk [||] !refConn
}
)
While this works, I question the reliability of using ref
and hoping there are better way out there to do the same in a more functional manner. Are there better way to do this? Assuming I cannot change getStringsFromProducer
?
I think you cannot avoid all mutation in this case - writing chunks one by one is a fairly imperative operation and iterating over a lazy sequence also requires (mutable) iterator, so there is no way to avoid all mutation. I think your
sendStrings
function does a nice job at hiding the mutation from the consumer and provides a nice functional API.You can avoid using
ref
cells and replace them with local mutable variable, which is a bit safer - because the mutable variable cannot escape the local scope:You could avoid the mutable
conn
variable by using recursion, but this requires you to work withIEnumerator<'T>
rather than using a nicefor
loop to iterate over the sequence, so I think this is actually less nice than the version using a mutable variable: