Git Product home page Git Product logo

Comments (22)

SergioBenitez avatar SergioBenitez commented on May 3, 2024 25

Support has landed! See the EventStream and Event docs and the new chat example.

from rocket.

greglearns avatar greglearns commented on May 3, 2024 19

@SergioBenitez There are a number of differences between Server Send Events (SSE) and WebSockets (WS) -- definitely worth reading up on. They both have value for their specific use-cases. SSE has some great features, and WS has some problem that only become apparent once you investigate them. For example, WS don't currently work with AWS ELBs unless the ELB is in PROXY-mode, which removes a lot of the benefit of an ELB! Also, the security model for WS is different than standard HTTP, which complicates securely implementing WS. WS need an UPGRADE on the HTTP protocol to work, whereas SSE does not. There are a number of other advantages to SSE (easy to implement, browsers automatically reconnect if they become disconnected, ... more ... more), and are good for when you don't have to have the bi-directional capabilities or super-low-latency of WS. I would definitely vote +1 for SSE support in Rocket (which, I'm still loving!)

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 17

Bringing this back to 0.5, thanks to @jebrosen's nearly complete implementation!

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 14

Pushing this up to 0.5.

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 13

I believe Rocket should be able to handle Server Sent Events. It's likely that the implementation would reside in contrib, but core should make such an implementation as simple as possible. That being said, the current synchronous architecture isn't amenable to SSE. As a result, I'm slating this for a later milestone. Nonetheless, I am committed to seeing this in Rocket.

from rocket.

bradleybeddoes avatar bradleybeddoes commented on May 3, 2024 12

+1 on the native support for web sockets within Rocket

from rocket.

valpackett avatar valpackett commented on May 3, 2024 5

why would someone use server-sent events instead of web sockets

Because if you only need unidirectional (server to browser) notifications, why set up the more complex WebSocket protocol? Okay, I know WS is not actually complex, but still. SSE just feels lighter.

from rocket.

gfriloux avatar gfriloux commented on May 3, 2024 5

Ok, I managed to patch version 0.10.13 of hyper to force flush sockets.
I know i said i would stop posting here, but this may help more people than me.
This enables to do streaming "properly", so SSE and that kind of stuff.
Latest Hyper versions does use flush, but rocket.rs can't build with latest hyper due to various changes.

Basically, for hyper 0.10.13, edit src/server/response.rs and you need to have :

217 impl<'a> Write for Response<'a, Streaming> {
218     #[inline]
219     fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
220         debug!("write {:?} bytes", msg.len());
221         let r = self.body.write(msg);
222         self.body.flush();
223         r
224     }

This will properlly flush the socket and make it possible to send only a few bytes.
The sample codes i pasted above will then work perfectly well.

from rocket.

killkrt avatar killkrt commented on May 3, 2024 4

In my opinion it would be great to have an example that shows how to currently implement a simple SSE or websocket solution using the current API (I guess using Stream in some way).

from rocket.

ijackson avatar ijackson commented on May 3, 2024 4

I think my MR #1365 would satisfy this request for Rocket 0.4.x.

Having read the discussion, I wanted to respond to a few points:

"will block" has the serious consequence that the maximum number of clients with open SSE channels is bounded by the number of worker threads

Yes. Depending on the application, it will be necessary to significantly increase the number of worker threads (and hope the system doesn't overload or get DOS'd). Also there is a browser limitation, see https://developer.mozilla.org/en-US/docs/Web/API/EventSource for which traditional workaround is to make the SSE requests to a wildcard domain with a randomly-chosen leafname, or similar (the client maximum connections limit being per domain, not per IP address).

Ok, I managed to patch version 0.10.13 of hyper to force flush sockets.

I don't think that change is necessary (everything works for me with hyper 0.10.16) or desirable. If rocket can be persuaded to complete a chunk, and issue a flush call, hyper seems to do the right things.

In my opinion it would be great to have an example that shows how to currently implement a simple SSE

I have code that could easily become such a thing if my MR #1365 is accepted. If there is interest I could produce a suitable git branch.

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 3

Unless otherwise stated, everything is streaming in Rocket by default, not just Stream. If you'd like, you can implement server sent events via Responder. You'd need to create a new Read type that does the appropriate thing. Of course, that Responder will block while sending events, a side effect of Rocket being synchronous. This will eventually stop being the case.

On a more fundamental level: why would someone use server-sent events instead of web sockets? I think seeing some kind of native support for web sockets would be nice, and it would be even nicer if that supplanted the need for server-sent events.

from rocket.

sporto avatar sporto commented on May 3, 2024 2

This would be great. I tried to make my own implementation using a Responder but my rust knowledge is not there yet. I would love to see an example of how to do SSE in Rocket.

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 1

I'm, sadly, going to push this to 0.6 to clear the way for 0.5. It's likely we can have a solution as a point release in the 0.5 series, however.

from rocket.

SergioBenitez avatar SergioBenitez commented on May 3, 2024 1

@lpgeiger You're mixing documentation/examples, and perhaps code, from master and 0.4. Neither master nor v0.4 include built-in support for SSE. v0.4 recently gained the ability to implement SSE externally, and we added an sse example to the repository doing just this. master has had support for external implementation of SSE since it became async, but we do not have an example on how to implement support externally; @jebrosen has as example, however.

In general, "nice" SSE support is blocked on a write-based API for responses. We can emulate such an API in Rocket with a performance cost, but it sub-optimal. Ideally, an underlying HTTP library would support such an API, but that is not the case today.

BTW, (and you may be aware of this) when I try the same example code, except using published rocket and rocket-contrib as the dependencies leads to a this error:

This example works in both v0.4 and master, and is tested by the CI on every commit. I suspect you're mixing versions in your Cargo.toml, however. Ensure that your rocket and rocket_contrib versions point at the same version.

from rocket.

gfriloux avatar gfriloux commented on May 3, 2024

Hello, i am having (almost) the same need.

As i am a complete beginner with rust (im trying to see how hard it would be to port an existing project from C to Rust), but i still have been able to come up with this code :
https://gist.github.com/gfriloux/5f82c702e445fdc4b447586bb6721dbd

What it does is simply read on a unix pipe.
If i only return a File structure from the pending function, rocket.rs will only read the pipe once and return this result to the HTTP client (so it wont be a "stream" or a chunked answer).

So i create a PipeLoop structure, implement Responder and Read for it, and each read call will be blocking.
This allows any other app to write into the pipe as it has things to write, and rocket.rs to be aware of it.

Still, there is a thing that doesnt work properlly : rocket.rs will bufferise on its side.
It seems to wait for around 16KB of data to start sending the first bytes.

For example, if my pipe is /tmp/testfifo, i have to do this :

# echo "toto" >/tmp/testfifo
# perl -E 'say "=" x 8000' >/tmp/testfifo
# perl -E 'say "=" x 8000' >/tmp/testfifo

Only to receive "toto" on the client side.

This is where i begin to not know what to do.
I am reading rocket's source code, trying to find an answer, but if you know the last bits needed to get it working, it would be awesome.

I'd like to come up with a workaround before v0.8.0 (having a long running thread isn't a problem in my case).

from rocket.

gfriloux avatar gfriloux commented on May 3, 2024

Using chunked_body() (with a size of 5 bytes for example) will trigger a lot of read() calls into my PipeLoop structure, but it won't send anything until i pile thousands of chars.

This makes me believe (i am not yet able to determine it) that hyper will bufferize on its side.

from rocket.

gfriloux avatar gfriloux commented on May 3, 2024

Using Stream instead of writing my own Responder makes the code more simple, but gives the same result.

Here is a code example : https://gist.github.com/gfriloux/c8846afed6d2bfceffd13fc5375bced3

from rocket.

gfriloux avatar gfriloux commented on May 3, 2024

I dont know where its blocking (my low rust knowledge doesnt help) but i assume it should not wait to have the buffer filled to send data.

Data should be sent either immediately or after a very short window.
This would unblock this issue the time you implement SSE inside rocket.rs.

Comparing to C functions, write() or send() won't block data until a fixed amount of data is given.
You can send 1 byte without any problem, it won't delay it indefinitly, waiting for more data.

from rocket.

gfriloux avatar gfriloux commented on May 3, 2024

Ok, after spending some days on other stuff, im back at this.
The problem isnt in rocket.rs itself.

setting logs at debug level, i can see that hyper writes the data, but the HTTP client doesnt get it :

--> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.13/src/server/response.rs:220
write 10 bytes
chunked write, size = 10

You need to write a bunch of data for it to be received by the HTTP client (it wont even send the HTTP headers, in some cases).
As i had doubts about curl, i directly went with telnet, and the same problem occurs.
My first hint is that hyper is missing a few flushes.

So i will stop reporting here this behavior.

from rocket.

jebrosen avatar jebrosen commented on May 3, 2024

The problem with an example of SSE in the current API is related to this point:

Of course, that Responder will block while sending events, a side effect of Rocket being synchronous

"will block" has the serious consequence that the maximum number of clients with open SSE channels is bounded by the number of worker threads, at which point the server will "hang" until those clients disconnect. If I'm reading #33 (comment) correctly, then hyper also needs modifications for SSE to work correctly.

#1065 will make doing this not-dangerous - open Response channels "waiting" on the server to push data will no longer prevent new incoming requests from being processed. And #1066 will make SSE easier to implement by eliminating the need to implement some kind of custom Read type.

from rocket.

0o-de-lally avatar 0o-de-lally commented on May 3, 2024

newb here. I see this is a long running thread, so unsure if this is the right place for these comments. I've run the sse demo in /examples. Looks powerful! Happy to contribute to get this to production.

As of Mar/2021 how do the proposal above change the behavior or API in the demo?
BTW, (and you may be aware of this) when I try the same example code, except using published rocket and rocket-contrib as the dependencies leads to a this error:

error[E0277]: the trait bound `Vec<Route>: std::convert::From<StaticFiles>` is not satisfied
  --> src/main.rs:58:10
   |
58 |         .mount("/", StaticFiles::from("static"))
   |          ^^^^^ the trait `std::convert::From<StaticFiles>` is not implemented for `Vec<Route>`

from rocket.

DanielJoyce avatar DanielJoyce commented on May 3, 2024

Reading up on this very thing, http2 can basically do websockets with fetch api and sse.

from rocket.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.