Crow
Crow copied to clipboard
server-sent events
I'm using crow for a lightweight webservices server and I have to implement a CZML one, which requires event-stream. Is it already supported in any way?
If I understand correctly, an event-stream allows a server to push data to a client line by line, rather than in 1 body. This is currently not implemented in Crow (with the exception of static files). Furthermore it might require quite a few changes to how routes work, although such changes would be similar to how Transfer-Encoding: Chunked would work.
I have kept trying, but to no result: I have extended "response":
- With a pointer to a class of mine ("pEventStream"), which has a function "bool getEvent(std::string &buf)". This function will ask for each new packet to be sent by streaming, until it returns "false", in which case the sending must be finished.
- "bool is_event_stream()", to identify this new type of sending.
- New functions:
template<typename Adaptor>
void do_stream_event(Adaptor& adaptor)
{
if (is_event_stream())
{
write_streamed_event(pEventStream, adaptor);
}
}
template<typename Adaptor>
void write_streamed_event(CEventStream * pEventStream, Adaptor& adaptor)
{
// TODO: Here I have tried sending loops, and everything I could think of...
}
I have extended "Connection":
void do_write_general()
{
// New case
if (res.is_event_stream())
{
...
res.do_stream_event(adaptor_);
...
}
...
I have tried a lot of things, without getting any results. I don't think this kind of botched job will work, and the engine will have to be completely reworked.
I tried passing a lambda instead of the CEventStream object, but the Adaptor template made it quite complicated, I'm also looking into having a custom type of handler (similar to CROW_ROUTE.websocket())
I found a much easier way to handle this. It seems that requests in crow store the IO Service object, which is what you need to send data between the server and the client, meaning a method could be easily created to take advantage of that and send data without relying on the Connection object.
only potential hiccup would be SSL (as in OpenSSL) support, since an SSL connection also requires SSL context to function, so some form of that.
I believe most people don't use SSL so I'll try to create some example code that uses the IO Service to send data before the response is completed and will update this comment.
Update:
I edited some bits in the res-push branch, this will not work with SSL, IDK if it'll compile even, it's just a patch to get the ability to send data in chunks.
Here's what I put in a simple CROW_ROUTE to allow chunked encoding, I'm not fully sure on how to use event-stream
res.set_header("Transfer-Encoding", "Chunked");
res.send_chunk(*req.adaptor, "6\r\nHello \r\n");
res.send_chunk(*req.adaptor, "5\r\nWorld\r\n");
res.send_chunk(*req.adaptor, "0\r\n\r\n");
There's no need for res.end() because res.send_chunk() already sets it.
Sorry it took me almost a day to get this done, There was a problem with sending strings because of C strings.
Thanks a lot! I'll try!
I'm trying, but I'm having problems with the client reading the data from the server correctly. It could be my code's fault, of course.
I am having a similar issue with receiving data as it comes in e.g. File uploads Maybe something that wraps the read_async/write_async events in the ioservice?
Regarding the SSL, I think when I played with it in the past, I am by far not an expert on ASIO, I had to wrap it such that the interface for ssl and non-ssl was type erased and unified. Most things only need to send/recv after the server starts up, I think.
@beached I'm not sure this is the same issue @jsanchezfr was facing.. Could you provide more detail?
Crow already has a wrapper for that abstracts plaintext and SSL adaptors. The reason I didn't include the SSL part is because response isn't a template class and I wasn't sure making it one (or making a template function inside it) was the best idea.