sse-relay-server


Namesse-relay-server JSON
Version 1.0.14 PyPI version JSON
download
home_page
SummaryAn SSE Relay Service: Perfect for Adding Real-Time Features to Your Django Project Without Introducing ASGI or Async Code.
upload_time2023-12-08 15:43:39
maintainer
docs_urlNone
author
requires_python>=3.8
licenseMIT License Copyright (c) 2022 Tobi DEGNON Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords django postgresql python realtime redis
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # sse-relay-server

[![Docker](https://github.com/Tobi-De/sse_relay_server/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/Tobi-De/sse_relay_server/actions/workflows/docker-publish.yml)
[![pypi](https://badge.fury.io/py/sse-relay-server.svg)](https://pypi.org/project/sse-relay-server/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Tobi-De/fuzzy-couscous/blob/main/LICENSE)
[![GitHub Container Registry](https://img.shields.io/badge/Docker%20Pulls-GitHub%20Container%20Registry-blue)](https://github.com/Tobi-De/sse_relay_server/pkgs/container/sse_relay_server)

For some background information, read https://github.com/Tobi-De/sse_server_postgres_listen_notify.

Originally designed for Django, now a simple, standalone Server-Sent Events relay service, ideal for Django projects
seeking
straightforward real-time capabilities without the need for Daphne and async Django setup.

![SSE relay message transmission diagram](diagram.png)

<details>
<summary>Explanation</summary>

1. The browser establishes an SSE connection to the running relay service (this project).
2. The relay service listens on the channel specified in the user request via the path parameter `channel`.
3. When a user action occurs on your Django server, you run the [`notify`](#sending-messages-from-your-django-app) function, sending an event to either `PostgreSQL` or `Redis` based on your configuration.
4. The relay service receives the message from the broker (`Redis`/`PostgreSQL`).
5. Subsequently, the relay sends the message via SSE to all web browsers subscribed to the specified channel.

</details>

## Installation

You can install sse-relay-server as a package using pip:

```sh
pip install "sse-relay-server[postgres,redis]"
```

Alternatively, you can use a container by pulling the Docker image:

```sh
docker pull ghcr.io/tobi-de/sse_relay_server:latest
```

## Supported Protocols

- PostgreSQL [LISTEN](https://www.postgresql.org/docs/current/sql-listen.html)/[NOTIFY](https://www.postgresql.org/docs/15/sql-notify.html)
- Redis [Pub/Sub](https://redis.io/topics/pubsub)

## Environment Variables

To configure sse-relay-server, you can use the following environment variables:

- `ALLOWED_ORIGINS`: Comma-separated URLs allowed to request SSE connections.
- `DATABASE_URL`: PostgreSQL database URL.
- `REDIS_URL`: Redis URL (if you prefer to use Redis instead of PostgreSQL).
- `RELAY_USE_PG`: Force the use of PostgreSQL if you have both `REDIS_URL` and `DATABASE_URL` set, but prefer to use PostgreSQL.
- `RELAY_SERVER_DEBUG`: Boolean for enabling debug mode (default to False).
- `LOG_LEVEL`: CRITICAL | ERROR | WARNING | INFO | DEBUG | TRACE   (default to INFO)

If the `REDIS_URL` environment variable is set, the redis pubsub protocol will be used instead of the PostgreSQL
listen/notify.

## Running the Relay Service

If installed via pip, simply execute the following command, adjusting the options as needed:

```sh
sse-relay-server --port 8001 --host 0.0.0.0 --workers 4
```

For Docker users, override the running command as follows:

```sh
docker run -it sse_relay_server sse-relay-server --port 8001:8001 --workers 4
```

## Establishing an SSE Connection with the Relay Service

```javascript
const channelName = "NOTIFICATIONS"
const severURL = "http://<server_host>:<relay_port>"

const eventSource = new EventSource(`${serverURL}/channel=${channelName}`);

eventSource.addEventListener('NEW_NOTIFICATION', (e) => {
    console.log(e.data)
})
```

## Sending Messages from Your Django App

Once you've installed this package in your Django project, you can use a simple `notify` function to send messages. This
function works for both Redis and PostgreSQL.

```python
from sse_relay_server import notify

notify(
    channel="Notifications",
    sse_payload={
        "event": "NEW_NOTIFICATION",
        "id": 1,
        "data": json.dumps({"message": "A new notification"}),
    },
)
```

- `channel`: The PostgreSQL/Redis channel for sending the message.
- `sse_payload`: A Python dictionary containing all the details of the SSE event. For a complete list of available
  options, refer to [this class definition](https://github.com/sysid/sse-starlette/blob/main/sse_starlette/sse.py#L50).

To ensure smooth operation, avoid using excessively lengthy channel names, overly large payloads for PostgreSQL `NOTIFY`
messages, and bulky data for SSE event payloads, as there are size limitations for each of these aspects. If you need to
retrieve a large database object, consider sending just the key and fetching the full data on the frontend using another
request (such as an htmx request). While this extra request may not be the most ideal solution, for simplicity's sake,
it's often a worthwhile trade-off.

At my workplace, we successfully implemented a straightforward real-time notification system using this approach,
transmitting all the necessary notification data without any issues. However, be aware of the potential risk of sending
overly large data. For more in-depth information, you can refer to the following links:

- [PostgreSQL NOTIFY](https://www.postgresql.org/docs/15/sql-notify.html)
- [PostgreSQL LISTEN](https://www.postgresql.org/docs/current/sql-listen.html)
- [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
- [Redis Pub/Sub](https://redis.io/topics/pubsub)

If for some reason you don't want or cannot install this package, the code for sending events for both PostgreSQL and
Redis is quite simple, and you can easily copy and paste it from below.

### Postgres

```python
import json
from django.db import connection


def notify(channel: str, sse_payload: dict) -> None:
    with connection.cursor() as cursor:
        cursor.execute(f"NOTIFY {channel}, '{json.dumps(sse_payload)}'")
```

### Redis

```python
import json
import redis

REDIS_URL = "redis://localhost:6379/0"


def notify(channel: str, sse_payload: dict) -> None:
    r = redis.from_url(REDIS_URL)
    r.publish(channel=channel, message=json.dumps(sse_payload))
```

## Stopping the SSE Connection

As far as I know, there is no standard method for stopping an established SSE connection. The most straightforward solution is to send a specific event, such as one named `STOP`, and handle it on the frontend.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "sse-relay-server",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "django,postgresql,python,realtime,redis",
    "author": "",
    "author_email": "Tobi DEGNON <tobidegnon@proton.me>",
    "download_url": "https://files.pythonhosted.org/packages/30/02/3785e716bd767b4166dcb00ee8c8ee568de9c62e11b26c027c64f7c7c004/sse_relay_server-1.0.14.tar.gz",
    "platform": null,
    "description": "# sse-relay-server\n\n[![Docker](https://github.com/Tobi-De/sse_relay_server/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/Tobi-De/sse_relay_server/actions/workflows/docker-publish.yml)\n[![pypi](https://badge.fury.io/py/sse-relay-server.svg)](https://pypi.org/project/sse-relay-server/)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Tobi-De/fuzzy-couscous/blob/main/LICENSE)\n[![GitHub Container Registry](https://img.shields.io/badge/Docker%20Pulls-GitHub%20Container%20Registry-blue)](https://github.com/Tobi-De/sse_relay_server/pkgs/container/sse_relay_server)\n\nFor some background information, read https://github.com/Tobi-De/sse_server_postgres_listen_notify.\n\nOriginally designed for Django, now a simple, standalone Server-Sent Events relay service, ideal for Django projects\nseeking\nstraightforward real-time capabilities without the need for Daphne and async Django setup.\n\n![SSE relay message transmission diagram](diagram.png)\n\n<details>\n<summary>Explanation</summary>\n\n1. The browser establishes an SSE connection to the running relay service (this project).\n2. The relay service listens on the channel specified in the user request via the path parameter `channel`.\n3. When a user action occurs on your Django server, you run the [`notify`](#sending-messages-from-your-django-app) function, sending an event to either `PostgreSQL` or `Redis` based on your configuration.\n4. The relay service receives the message from the broker (`Redis`/`PostgreSQL`).\n5. Subsequently, the relay sends the message via SSE to all web browsers subscribed to the specified channel.\n\n</details>\n\n## Installation\n\nYou can install sse-relay-server as a package using pip:\n\n```sh\npip install \"sse-relay-server[postgres,redis]\"\n```\n\nAlternatively, you can use a container by pulling the Docker image:\n\n```sh\ndocker pull ghcr.io/tobi-de/sse_relay_server:latest\n```\n\n## Supported Protocols\n\n- PostgreSQL [LISTEN](https://www.postgresql.org/docs/current/sql-listen.html)/[NOTIFY](https://www.postgresql.org/docs/15/sql-notify.html)\n- Redis [Pub/Sub](https://redis.io/topics/pubsub)\n\n## Environment Variables\n\nTo configure sse-relay-server, you can use the following environment variables:\n\n- `ALLOWED_ORIGINS`: Comma-separated URLs allowed to request SSE connections.\n- `DATABASE_URL`: PostgreSQL database URL.\n- `REDIS_URL`: Redis URL (if you prefer to use Redis instead of PostgreSQL).\n- `RELAY_USE_PG`: Force the use of PostgreSQL if you have both `REDIS_URL` and `DATABASE_URL` set, but prefer to use PostgreSQL.\n- `RELAY_SERVER_DEBUG`: Boolean for enabling debug mode (default to False).\n- `LOG_LEVEL`: CRITICAL | ERROR | WARNING | INFO | DEBUG | TRACE   (default to INFO)\n\nIf the `REDIS_URL` environment variable is set, the redis pubsub protocol will be used instead of the PostgreSQL\nlisten/notify.\n\n## Running the Relay Service\n\nIf installed via pip, simply execute the following command, adjusting the options as needed:\n\n```sh\nsse-relay-server --port 8001 --host 0.0.0.0 --workers 4\n```\n\nFor Docker users, override the running command as follows:\n\n```sh\ndocker run -it sse_relay_server sse-relay-server --port 8001:8001 --workers 4\n```\n\n## Establishing an SSE Connection with the Relay Service\n\n```javascript\nconst channelName = \"NOTIFICATIONS\"\nconst severURL = \"http://<server_host>:<relay_port>\"\n\nconst eventSource = new EventSource(`${serverURL}/channel=${channelName}`);\n\neventSource.addEventListener('NEW_NOTIFICATION', (e) => {\n    console.log(e.data)\n})\n```\n\n## Sending Messages from Your Django App\n\nOnce you've installed this package in your Django project, you can use a simple `notify` function to send messages. This\nfunction works for both Redis and PostgreSQL.\n\n```python\nfrom sse_relay_server import notify\n\nnotify(\n    channel=\"Notifications\",\n    sse_payload={\n        \"event\": \"NEW_NOTIFICATION\",\n        \"id\": 1,\n        \"data\": json.dumps({\"message\": \"A new notification\"}),\n    },\n)\n```\n\n- `channel`: The PostgreSQL/Redis channel for sending the message.\n- `sse_payload`: A Python dictionary containing all the details of the SSE event. For a complete list of available\n  options, refer to [this class definition](https://github.com/sysid/sse-starlette/blob/main/sse_starlette/sse.py#L50).\n\nTo ensure smooth operation, avoid using excessively lengthy channel names, overly large payloads for PostgreSQL `NOTIFY`\nmessages, and bulky data for SSE event payloads, as there are size limitations for each of these aspects. If you need to\nretrieve a large database object, consider sending just the key and fetching the full data on the frontend using another\nrequest (such as an htmx request). While this extra request may not be the most ideal solution, for simplicity's sake,\nit's often a worthwhile trade-off.\n\nAt my workplace, we successfully implemented a straightforward real-time notification system using this approach,\ntransmitting all the necessary notification data without any issues. However, be aware of the potential risk of sending\noverly large data. For more in-depth information, you can refer to the following links:\n\n- [PostgreSQL NOTIFY](https://www.postgresql.org/docs/15/sql-notify.html)\n- [PostgreSQL LISTEN](https://www.postgresql.org/docs/current/sql-listen.html)\n- [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)\n- [Redis Pub/Sub](https://redis.io/topics/pubsub)\n\nIf for some reason you don't want or cannot install this package, the code for sending events for both PostgreSQL and\nRedis is quite simple, and you can easily copy and paste it from below.\n\n### Postgres\n\n```python\nimport json\nfrom django.db import connection\n\n\ndef notify(channel: str, sse_payload: dict) -> None:\n    with connection.cursor() as cursor:\n        cursor.execute(f\"NOTIFY {channel}, '{json.dumps(sse_payload)}'\")\n```\n\n### Redis\n\n```python\nimport json\nimport redis\n\nREDIS_URL = \"redis://localhost:6379/0\"\n\n\ndef notify(channel: str, sse_payload: dict) -> None:\n    r = redis.from_url(REDIS_URL)\n    r.publish(channel=channel, message=json.dumps(sse_payload))\n```\n\n## Stopping the SSE Connection\n\nAs far as I know, there is no standard method for stopping an established SSE connection. The most straightforward solution is to send a specific event, such as one named `STOP`, and handle it on the frontend.\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2022 Tobi DEGNON  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
    "summary": "An SSE Relay Service: Perfect for Adding Real-Time Features to Your Django Project Without Introducing ASGI or Async Code.",
    "version": "1.0.14",
    "project_urls": {
        "Documentation": "https://github.com/Tobi-De/sse_relay_server",
        "Homepage": "https://github.com/Tobi-De/sse_relay_server",
        "Repository": "https://github.com/Tobi-De/sse_relay_server"
    },
    "split_keywords": [
        "django",
        "postgresql",
        "python",
        "realtime",
        "redis"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ac02f5db2007b8e1a433fd37909d62b866f2ab9f2354c1e16d9e42afe124dd16",
                "md5": "67c915dc50ec5287bfae338637025812",
                "sha256": "319eb5d5c79c3d5f275d9fa0b8ce324130bb16398633eefba9ba635c8e1dc3bb"
            },
            "downloads": -1,
            "filename": "sse_relay_server-1.0.14-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "67c915dc50ec5287bfae338637025812",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 15527,
            "upload_time": "2023-12-08T15:43:35",
            "upload_time_iso_8601": "2023-12-08T15:43:35.484717Z",
            "url": "https://files.pythonhosted.org/packages/ac/02/f5db2007b8e1a433fd37909d62b866f2ab9f2354c1e16d9e42afe124dd16/sse_relay_server-1.0.14-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "30023785e716bd767b4166dcb00ee8c8ee568de9c62e11b26c027c64f7c7c004",
                "md5": "ca2c650fd008965d691f045e2f99b407",
                "sha256": "0cd2af9e1f32539101c53f21e8d195b863b28f45d0e1dfd568a352528335bd2c"
            },
            "downloads": -1,
            "filename": "sse_relay_server-1.0.14.tar.gz",
            "has_sig": false,
            "md5_digest": "ca2c650fd008965d691f045e2f99b407",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 105419,
            "upload_time": "2023-12-08T15:43:39",
            "upload_time_iso_8601": "2023-12-08T15:43:39.298945Z",
            "url": "https://files.pythonhosted.org/packages/30/02/3785e716bd767b4166dcb00ee8c8ee568de9c62e11b26c027c64f7c7c004/sse_relay_server-1.0.14.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-12-08 15:43:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Tobi-De",
    "github_project": "sse_relay_server",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "sse-relay-server"
}
        
Elapsed time: 0.18085s