github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/docs/realtime.md (about)

     1  [Table of contents](README.md#table-of-contents)
     2  
     3  # Realtime
     4  
     5  The stack offers a way for applications to be notified in real-time of what
     6  happens on the server via a websocket connection.
     7  
     8  We start with a normal websocket handshake.
     9  
    10  Websockets include a protocol description in handshake, the protocol described
    11  below is hereby named `io.cozy.websocket`.
    12  
    13  Changes to the websocket protocol should be given versions, support for older
    14  version should be maintained when reasonable.
    15  
    16  ```http
    17  GET /realtime/ HTTP/1.1
    18  Host: mycozy.example.com
    19  Upgrade: websocket
    20  Connection: Upgrade
    21  Origin: http://calendar.mycozy.example.com
    22  Sec-WebSocket-Key: x3JrandomLkh9GBhXDw==
    23  Sec-WebSocket-Protocol: io.cozy.websocket
    24  Sec-WebSocket-Version: 13
    25  ```
    26  
    27  Then messages are sent using json:
    28  
    29  ```
    30  client > {"method": "AUTH",
    31            "payload": "xxAppOrAuthTokenxx="}
    32  client > {"method": "SUBSCRIBE",
    33            "payload": {"type": "io.cozy.files"}}
    34  client > {"method": "SUBSCRIBE",
    35            "payload": {"type": "io.cozy.contacts"}}
    36  server > {"event": "UPDATED",
    37            "payload": {"id": "idA", "rev": "2-705...", "type": "io.cozy.contacts", "doc": {embeded doc ...}}}
    38  server > {"event": "DELETED",
    39            "payload": {"id": "idA", "rev": "3-541...", "type": "io.cozy.contacts"}}
    40  client > {"method": "UNSUBSCRIBE",
    41            "payload": {"type": "io.cozy.contacts"}}
    42  server > {"event": "UPDATED",
    43            "payload": {"id": "idB", "rev": "6-457...", "type": "io.cozy.files", "doc": {embeded doc ...}}}
    44  ```
    45  
    46  ## AUTH
    47  
    48  It must be the first command to be sent. The client gives its token with this
    49  command, and the stack will use it to know which are the permissions of the app.
    50  
    51  ```
    52  {"method": "AUTH", "payload": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhcHAiLCJpYXQiOjE0OTg4MTY1OTEsImlzcyI6ImNvenkudG9vbHM6ODA4MCIsInN1YiI6Im1pbmkifQ.eH9DhoHz7rg8gR7noAiKfeo8eL3Q_PzyuskO_x3T8Hlh9q_IV-4zqoGtjTiO7luD6_VcLboEU-6o3XBek84VTg"}
    53  ```
    54  
    55  ## SUBSCRIBE
    56  
    57  A client can send a SUBSCRIBE request to be notified of changes. The payload is
    58  a selector for the events it wishes to receive For now the only possible
    59  selector is on type & optionally id.
    60  
    61  ```
    62  {"method": "SUBSCRIBE", "payload": {"type": "[desired doctype]"}}
    63  {"method": "SUBSCRIBE", "payload": {"type": "[desired doctype]", "id": "idA"}}
    64  ```
    65  
    66  In order to subscribe, a client must have permission `GET` on the passed
    67  selector. Otherwise an error is passed in the message feed.
    68  
    69  ```
    70  server > {"event": "error",
    71            "payload": {
    72              "status": "403 Forbidden"
    73              "code": "forbidden"
    74              "title":"The Application can't subscribe to io.cozy.files"
    75              "source": {"method": "SUBSCRIBE", "payload": {"type":"io.cozy.files"} }
    76            }}
    77  ```
    78  
    79  ## UNSUBSCRIBE
    80  
    81  A client can send an UNSUBSCRIBE request to no longer be notified of changes
    82  from a previous request.
    83  
    84  ```
    85  {"method": "UNSUBSCRIBE", "payload": {"type": "[desired doctype]"}}
    86  {"method": "UNSUBSCRIBE", "payload": {"type": "[desired doctype]", "id": "idA"}}
    87  ```
    88  
    89  ## Response messages
    90  
    91  A message sent by the server after a subscribe will be a JSON object with two
    92  keys at root: `event` and `payload`. `event` will be one of `CREATED`,
    93  `UPDATED`, `DELETED` (when a document is written in CouchDB), `NOTIFIED` (see
    94  below), or `error`. The `payload` will be a map with `type`, `id`, and `doc`.
    95  The `payload` can also contain an optional `old` with the old values for the
    96  document in case of `UPDATED` or `DELETED`.
    97  
    98  ## Synthetic types
    99  
   100  The stack an inject some synthetic events for documents that are not persisted
   101  in CouchDB like classical doctypes:
   102  
   103  - [Auth confirmations](https://docs.cozy.io/en/cozy-stack/auth/#real-time-via-websockets)
   104  - [Initial sync for sharings](https://docs.cozy.io/en/cozy-stack/sharing/#real-time-via-websockets)
   105  - [Thumbnails for files](https://docs.cozy.io/en/cozy-stack/files/#real-time-via-websockets)
   106  - [Telepointers for notes](https://docs.cozy.io/en/cozy-stack/notes/#real-time-via-websockets)
   107  
   108  ## `POST /realtime/:doctype/:id`
   109  
   110  This route can be used to send documents in the real-time without having to
   111  persist them in CouchDB (and they can't be used for triggers).
   112  
   113  A permission on POST for the document `:doctype/:id` is required to use this
   114  endpoint.
   115  
   116  ### Request
   117  
   118  ```http
   119  POST /realtime/io.cozy.jobs/2c577f00-145a-0138-f569-543d7eb8149c HTTP/1.1
   120  Content-Type: application/json
   121  ```
   122  
   123  ```json
   124  {
   125    "subtype": "progress",
   126    "imported": 10,
   127    "total": 42
   128  }
   129  ```
   130  
   131  ### Response
   132  
   133  ```http
   134  HTTP/1.1 204 No Content
   135  ```
   136  
   137  ### Websocket
   138  
   139  ```
   140  server > {"event": "NOTIFIED",
   141            "payload": {"id": "2c577f00-145a-0138-f569-543d7eb8149c",
   142                        "type": "io.cozy.jobs",
   143                        "doc": {"subtype": "progress",
   144                                "imported": 10,
   145                                "total": 42}}}
   146  ```