github.com/anycable/anycable-go@v1.5.1/docs/sse.md (about)

     1  # Server-sent events
     2  
     3  In addition to WebSockets and [long polling](./long_polling.md)), AnyCable also allows you to use [Server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE) as a transport for receiving live updates.
     4  
     5  SSE is supported by all modern browsers (see [caniuse](https://caniuse.com/eventsource)) and is a good alternative to WebSockets if you don't need to send messages from the client to the server and don't want to deal with Action Cable or AnyCable SDKs: you can use native browsers `EventSource` API to establish a reliable connection or set up HTTP streaming manually using your tool of choice (e.g., `fetch` in a browser, `curl` in a terminal, etc.).
     6  
     7  ## Configuration
     8  
     9  You must opt-in to enable SSE support in AnyCable. To do so, you must provide the `--sse` or set the `ANYCABLE_SSE` environment variable to `true`:
    10  
    11  ```sh
    12  $ anycable-go --sse
    13  
    14  INFO 2023-09-06T22:52:04.229Z context=main Starting GoBenchCable 1.4.4 (with mruby 1.2.0 (2015-11-17)) (pid: 39193, open file limit: 122880, gomaxprocs: 8)
    15  ...
    16  INFO 2023-09-06T22:52:04.229Z context=main Handle WebSocket connections at http://localhost:8080/cable
    17  INFO 2023-09-06T22:52:04.229Z context=main Handle SSE requests at http://localhost:8080/events
    18  ...
    19  ```
    20  
    21  The default path for SSE connections is `/events`, but you can configure it via the `--sse_path` configuration option.
    22  
    23  ## Usage with EventSource
    24  
    25  The easiest way to use SSE is to use the native `EventSource` API. For that, you MUST provide a URL to the SSE endpoint and pass the channel information in query parameters (EventSource only supports GET requests, so we cannot use the body). For example:
    26  
    27  ```js
    28  const source = new EventSource("http://localhost:8080/events?channel=ChatChannel");
    29  
    30  // Setup an event listener to handle incoming messages
    31  source.addEventListener("message", (e) => {
    32    // e.data contains the message payload as a JSON string, so we need to parse it
    33    console.log(JSON.parse(e.data));
    34  });
    35  ```
    36  
    37  The snippet above will establish a connection to the SSE endpoint and subscribe to the `ChatChannel` channel.
    38  
    39  If you need to subscribe to a channel with parameters, you MUST provide the fully qualified channel identifier via the `identifier` query parameter:
    40  
    41  ```js
    42  const identifier = JSON.stringify({
    43    channel: "BenchmarkChannel",
    44    room_id: 42,
    45  });
    46  
    47  const source = new EventSource(
    48    `http://localhost:8080/events?identifier=${encodeURIComponent(identifier)}`
    49  );
    50  
    51  // ...
    52  ```
    53  
    54  **IMPORTANT**: You MUST specify either `channel` or `identifier` query parameters. If you don't, the connection will be rejected.
    55  
    56  ### Usage with signed/public streams
    57  
    58  > @since v1.5.1
    59  
    60  When using with [signed streams](./signed_streams.md), you can provide the public or signed stream name via the `stream` or `signed_stream` parameter respectively:
    61  
    62  ```js
    63  const publicSource = new EventSource(
    64    `http://localhost:8080/events?stream=${encodeURIComponent(myStreamName)}`
    65  );
    66  
    67  const signedSource = new EventSource(
    68    `http://localhost:8080/events?signed_stream=${encodeURIComponent(mySecretStreamName)}`
    69  );
    70  ```
    71  
    72  ### Reliability
    73  
    74  EventSource is a reliable transport, which means that it will automatically reconnect if the connection is lost.
    75  
    76  EventSource also keeps track of received messages and sends the last consumed ID on reconnection. To leverage this feature, you MUST enable AnyCable [reliable streams](./reliable_streams.md) functionality. No additional client-side configuration is required.
    77  
    78  **IMPORTANT**: EventSource is assumed to be used with a single stream of data. If you subscribe a client to multiple Action Cable streams (e.g., multiple `stream_from` calls), the last consumed ID will be sent only for the last observed stream.
    79  
    80  ### Requesting initial history
    81  
    82  > @since v1.5.1
    83  
    84  You can also specify the timestamp (Unix seconds) from which request initial stream history (if any):
    85  
    86  ```js
    87  // Last 5 minutes
    88  const ts = ((Date.now() / 1000) - 5*60) | 0;
    89  
    90  const publicSourceWithHistory = new EventSource(
    91    `http://localhost:8080/events?stream=${encodeURIComponent(myStreamName)}&history_since=${ts}`
    92  );
    93  ```
    94  
    95  ### Unauthorized connections or rejected subscriptions
    96  
    97  If the connection is unauthorized or the subscription is rejected, the server will respond with a `401` status code and close the connection. EventSource will automatically reconnect after a short delay. Please, make sure you handle `error` events and close the connection if you don't want to reconnect.
    98  
    99  ## Usage with other HTTP clients
   100  
   101  You can also use any other HTTP client to establish a connection to the SSE endpoint. For example, you can use `curl`:
   102  
   103  ```sh
   104  $ curl -N "http://localhost:8080/events?channel=ChatChannel"
   105  
   106  event: welcome
   107  data: {"type":"welcome"}
   108  
   109  event: confirm_subscription
   110  data: {"type":"confirm_subscription","identifier":"{\"channel\":\"ChatChannel\"}"}
   111  
   112  event: ping
   113  data: {"type":"ping","message":1694041735}
   114  
   115  data: {"message":"hello"}
   116  ...
   117  ```
   118  
   119  AnyCable also supports setting up a streaming HTTP connection via POST requests. In this case, you can provide a list of client-server commands in the request body using the JSONL (JSON lines) format.
   120  
   121  <!-- TODO: fetch example -->
   122  
   123  Note that you must process different event types yourself. See below for the format.
   124  
   125  ## Action Cable over SSE format
   126  
   127  The server-client communication format is designed as follows:
   128  
   129  - The `data` field contains the message payload. **IMPORTANT**: for clients connecting via a GET request, the payload only contains the `message` part of the original Action Cable payload; clients connecting via POST requests receive the full payload (e.g., `{"identifier":, "message": {"foo":1}}`).
   130  - The optional `event` field contains the message type (if any); for example, `welcome`, `confirm_subscription`, `ping`
   131  - The optional `id` field contains the message ID if reliable streaming is enabled. The message ID has a form or `<offset>/<stream_id>/<epoch>` (see [Extended Action Cable protocol](/misc/action_cable_protocol.md#action-cable-extended-protocol))
   132  - The optional `retry` field contains the reconnection interval in milliseconds. We only set this field for `disconnect` messages with `reconnect: false` (it's set to a reasonably high number to prevent automatic reconnection attempts by EventSource).
   133  
   134  Here is an example of a stream of messages from the server:
   135  
   136  ```txt
   137  event: welcome
   138  data: {"type":"welcome"}
   139  
   140  
   141  event: confirm_subscription
   142  data: {"type":"confirm_subscription","identifier":"{\"channel\":\"ChatChannel\"}"}
   143  
   144  
   145  event: ping
   146  data: {"type":"ping","message":1694041735}
   147  
   148  
   149  <!-- GET connection (e.g., EventSource) -->
   150  data: {"message":"hello"}
   151  id: 1/chat_42/y2023
   152  
   153  data: {"message":"good-bye"}
   154  id: 2/chat_42/y2023
   155  
   156  
   157  <!-- POST connection  -->
   158  data: {"identifier":"{\"channel\":\"ChatChannel\"}","message":{"message":"hello"}}
   159  id: 1/chat_42/y2023
   160  
   161  
   162  data: {"identifier":"{\"channel\":\"ChatChannel\"}","message":{"message":"good-bye"}}
   163  id: 2/chat_42/y2023
   164  
   165  
   166  event: ping
   167  data: {"type":"ping","message":1694044435}
   168  
   169  
   170  event: disconnect
   171  data: {"type":"disconnect","reason":"remote","reconnect":false}
   172  retry: 31536000000
   173  ```