Skip to main content

Simplified Django websocket processes designed to work with cloud caches

Project description

Django Sockets

PyPI version License: MIT

Simplified Django websocket processes designed to work with cloud caches (valkey|redis on single|distributed|serverless)

Setup

General

Make sure you have Python 3.10.x (or higher) installed on your system. You can download it here.

Installation

pip install django_sockets

Other Requirements

  • Make sure a cache (valkey or redis) is setup and accessible from your server.

    • To run one locally (using docker) for testing, you can use the following command:

      docker run -d -p 6379:6379 --name django_sockets_cache valkey/valkey:7
      
    • To run the container after it has been created, you can use the following command:

      docker start django_sockets_cache
      
    • To kill the container later, you can use the following command:

      docker kill django_sockets_cache
      

Usage

Low level docs: https://connor-makowski.github.io/django_sockets/django_sockets.html

Implement in a Django Project

TODO

Examples Without Django

Example Subscribing & Broadcasting

from django_sockets.sockets import BaseSocketServer
import asyncio, time

DJANGO_SOCKETS_CONFIG = {
    "hosts": [
        {"address": f"redis://0.0.0.0:6379"}
    ],
}

# Override the send method to print the data being sent
# instead of sending it over a non existent websocket connection
async def send(ws_data):
    print("WS SENDING:", ws_data)


# Create a receive queue to simulate receiving messages from a websocket client
base_receive = asyncio.Queue()
# Create a base socket server with a scope of {}
base_socket_server = BaseSocketServer(scope={}, receive=base_receive.get, send=send, config=DJANGO_SOCKETS_CONFIG)
# Start the listeners for the base socket server
base_socket_server.start_listeners()
# Subscribe to the test_channel
base_socket_server.subscribe("test_channel")
# Broadcast a message to the test_channel
base_socket_server.broadcast("test_channel", "test message")
# Give the async functions a small amount of time to complete
time.sleep(.5)


#=> Output:
#=> WS SENDING: {'type': 'websocket.send', 'text': '"test message"'}

Example Handle Websocket Messages

from django_sockets.sockets import BaseSocketServer
import asyncio, time

DJANGO_SOCKETS_CONFIG = {
    "hosts": [
        {"address": f"redis://0.0.0.0:6379"}
    ],
}

class CustomSocketServer(BaseSocketServer):
    def receive(self, data):
        """
        When a data message is received from a websocket client:
            - Print the data
            - Broadcast the data to a channel (the same channel that the socket server is subscribed to)

        Normally you would want to override the receive method to do any server side processing of the data that is received
        then broadcast any changes back to relevant channels.
        """
        print("WS RECEIVED: ", data)
        print(f"BROADCASTING TO '{self.scope['username']}'")
        self.broadcast(self.scope['username'], data)

    def connect(self):
        """
        When the websocket connects, subscribe to the channel of the user.

        This is an important method to override if you want to subscribe to a channel when a user frist connects.

        Otherwise, you can always subscribe to a channel based on the data that is received in the receive method.
        """
        print(f"CONNECTED")
        print(f"SUSCRIBING TO '{self.scope['username']}'")
        self.subscribe(self.scope['username'])

# Override the send method to print the data being sent
async def send(data):
    """
    Normally you would not override the send method, but since we are not actually sending data over a websocket connection
    we are just going to print the data that would be sent.

    This is useful for testing the socket server without having to actually send data over a websocket connection

    Note: This only sends the first 64 characters of the data
    """
    print("WS SENDING:", str(data)[:64])

# Create a receive queue to simulate receiving messages from a websocket client
custom_receive = asyncio.Queue()
# Create a custom socket server defined above with a scope of {'username':'adam'}, the custom_receive queue, and the send method defined above
custom_socket_server = CustomSocketServer(scope={'username':'adam'}, receive=custom_receive.get, send=send)
# Start the listeners for the custom socket server
#    - Websocket Listener - Listens for websocket messages
#    - Broadcast Listener - Listens for messages that were broadcasted to a channel that the socket server is subscribed to
custom_socket_server.start_listeners()
# Give the async functions a small amount of time to complete
time.sleep(.1)
# Simulate a WS connection request
custom_receive.put_nowait({'type': 'websocket.connect'})
# Give the async functions a small amount of time to complete
time.sleep(.1)
# Simulate a message being received from a WS client
# This will call the receive method which is defined above
custom_receive.put_nowait({'type': 'websocket.receive', 'text': '{"data": "test"}'})
# Give the async functions a small amount of time to complete
time.sleep(.1)
# Simulate a WS disconnect request
custom_receive.put_nowait({'type': 'websocket.disconnect'})
# Give the async functions a small amount of time to complete
time.sleep(.1)
# Simulate a message being received from a WS client after the connection has been closed
# This will not do anything since the connection has been closed and the listeners have been killed
custom_receive.put_nowait({'type': 'websocket.receive', 'text': '{"data_after_close": "test"}'})
# Give the async functions a small amount of time to complete
time.sleep(.1)

#=> Output:
#=> WS SENDING: {'type': 'websocket.accept'}
#=> CONNECTED
#=> SUSCRIBING TO 'adam'
#=> WS RECEIVED:  {'data': 'test'}
#=> BROADCASTING TO 'adam'
#=> WS SENDING: {'type': 'websocket.send', 'text': '{"data": "test"}'}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_sockets-2.0.0b2.tar.gz (14.3 kB view details)

Uploaded Source

Built Distribution

django_sockets-2.0.0b2-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file django_sockets-2.0.0b2.tar.gz.

File metadata

  • Download URL: django_sockets-2.0.0b2.tar.gz
  • Upload date:
  • Size: 14.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.3

File hashes

Hashes for django_sockets-2.0.0b2.tar.gz
Algorithm Hash digest
SHA256 e1b5223917c11807106f3bcc53339786a3e738bf6ec36a5d6a9913e39184a106
MD5 039166211298653b2fcb16facaae64b1
BLAKE2b-256 6244ed53fe8bce25a9df088280f2292ed41cc18f3d634b8f0dc5afb6c1d8ffce

See more details on using hashes here.

File details

Details for the file django_sockets-2.0.0b2-py3-none-any.whl.

File metadata

File hashes

Hashes for django_sockets-2.0.0b2-py3-none-any.whl
Algorithm Hash digest
SHA256 1d516f22b46601e3734d280167430db5afdedf33730b10be4624f33f909f5fab
MD5 cf0ff980c924d0c04dffe0bdaf8d5e03
BLAKE2b-256 29f36cdf7bb499c24c1488c623b6b24c8bb801fce9e519529c8e87a5e497faaa

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page