0

So I am trying to simultaneously update two different webpages of the same application. For example: I have a slider in the both the pages and what I want to do is move the slider one page and the other one automatically updates. I am using server-sent-events for this.

I have written a small api using expressjs where I have two endpoints: a get and a post. My idea is to update the slider value using the post endpoint and then trigger the get endpoint which in turn writes an event to the stream. The get endpoint is registered with the EventSource so that every time the endpoint writes something to the stream, the value of the slider is received and can be updated on in the frontend.

The problem I am facing is after a few values, the post api calls get stuck and keeps showing pending in the network status of the chrome developer tools and the whole thing doesn't work anymore. Any idea how to do this efficiently?

Below is the partial code of the first html page and the server: index.js

const port = 8000;

const express = require('express');
const app = express();

let allowCrossDomain = function (req, res, next) {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Headers', "*");
  next();
}

var sliderValue = 50;

app.use(require("body-parser").json());

app.use(allowCrossDomain);

app.use(express.urlencoded({ extended: true }));

app.listen(port);

app.get('/sse', (req, res) => {

    sendSSE(req, res)
 })


 app.post('/value', (req, res) => {
    sliderValue = req.body.value

    console.log("Slider value = ", sliderValue);

    res.status(201).json({
    message: "Successfully updated value",
       });
     });


// Setup the SSE "service" :)
function sendSSE(request, res) {
  console.log("Inside SSE")
  // Setup headers
  // For ease of use: example for enabled CORS
  res.writeHead(200, {
  'Content-Type': 'text/event-stream',
  'Cache-Control': 'no-cache',
  'Connection': 'keep-alive',
});


res.write("data: " + sliderValue + '\n\n');
  }

client1.html

slider.oninput = async () => {

            let _data = {
                value: slider.value
            }

            console.log(_data);

            await fetch('http://localhost:8000/value', {
                method: "POST",
                body: JSON.stringify(_data),
                headers: { "Content-type": "application/json; charset=UTF-8" }
            })
                .then(response => response.json())
                .then(json => console.log(json))
                .then(res => {fetch('http://localhost:8000/sse');});

client2.html

const src = new EventSource("http://localhost:8000/sse", /* { withCredentials: true } */);
        src.onopen= (e) => {console.log("Connection established")};
        src.onmessage = fn;

AR17
  • 37
  • 4
  • Are client1.html and client2.html going to be running in the same browser? Or are they going to be running on two different machines? – Darren Cook Apr 25 '22 at 10:27
  • I don't get what you mean by "*trigger the get endpoint which in turn writes an event to the stream.*" – Bergi Apr 25 '22 at 11:05
  • @DarrenCook Same browser. – AR17 Apr 25 '22 at 11:48
  • @Bergi Basically make a get api call that does "res.write()" – AR17 Apr 25 '22 at 11:48
  • Well it does `res.write` to the response for *that request*. It does not write to the response stream of the `EventSource` in your other page. And really, you absolutely should not require that `GET` request - the `POST` request should be enough to emit the event! – Bergi Apr 25 '22 at 12:03
  • @AR17 If the same browser I would use local storage (see https://stackoverflow.com/a/12514384/841830 ). Using SSE brings in more moving parts (a server) than is needed. – Darren Cook Apr 25 '22 at 13:35
  • Or yet beter a broadcast channel API, then you don't have the changes persistent: https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API – entio Apr 28 '22 at 14:18

0 Answers0