Giter Site home page Giter Site logo

django-instant's Introduction

Django Instant

pub package Django CI

Websockets for Django with Centrifugo.

  • Push events into public or private channels.
  • Handle the events in javascript client-side.

☀️ Compatible: plug it on an existing Django instance without any modification in your main stack

Example

Push events in channels from anywhere in the code:

from instant.producers import publish

# Publish to a public channel
publish("public", "Message for everyone")

# Publish to a private channel with an event class set
publish("$users", "Message in logged in users channel", event_class="important")

# Publish to a group channel
publish("$group1", "Message for users in group1")

# Publish to the staff channel with an extra json data payload
data = {"field1":"value1","field2":[1,2]}
publish("$staff", "Message for staff", data=data)

Quick start

Install the Django package

pip install django-instant

Add "instant" to INSTALLED_APPS and update urls.py:

urlpatterns = [
    # ...
    path("instant/", include("instant.urls")),
]

Install the websockets server

Using the installer

Use the Centrifugo installer management command (for Linux and MacOs):

python manage.py installws

This will download a Centrifugo binary release and install it under a centrifugo directory. It will generate the Django settings to use.

Install manualy

Install the Centrifugo websockets server: see the detailled doc


Download a release https://github.com/centrifugal/centrifugo/releases/latest and generate a configuration file:
./centrifugo genconfig

The generated config.json file looks like this:

{
  "v3_use_offset": true,
  "token_hmac_secret_key": "46b38493-147e-4e3f-86e0-dc5ec54f5133",
  "admin_password": "ad0dff75-3131-4a02-8d64-9279b4f1c57b",
  "admin_secret": "583bc4b7-0fa5-4c4a-8566-16d3ce4ad401",
  "api_key": "aaaf202f-b5f8-4b34-bf88-f6c03a1ecda6",
  "allowed_origins": []
}

Configure the Django settings

Use the parameters from the installer's output or from Centrifugo's config.json file to update your Django's settings.py:

CENTRIFUGO_HOST = "http://localhost"
CENTRIFUGO_PORT = 8001
CENTRIFUGO_HMAC_KEY = "46b38493-147e-4e3f-86e0-dc5ec54f5133"
CENTRIFUGO_API_KEY = "aaaf202f-b5f8-4b34-bf88-f6c03a1ecda6"
SITE_NAME = "My site" # used in the messages to identify where they come from

Create channels

Go into the admin to create channels or create them programatically:

from instant.models import Channel

Channel.objects.create(name="superuser", level=Channel.Level.Superuser) 

Api: channel create parameters:

  • name: the channel name. Required and unique
  • level: access authorization level for a channel: Public, Users, Groups, Staff, Superuser. Default: Superuser
  • is_active: a boolean to disable a channel
  • groups: a list of authorized Django groups for a channel

Avalailable endpoints

/instant/login/: takes a username and password as parameter and will login the user in Django and return a Centrifugo connection token

/instant/get_token/: get a Centrifugo connection token for a logged in user

The two methods above return some connection information: a token for the websockets connection, a Django csrf token and a list of authorized channels for the user:

{
  "csrf_token": "fvO61oyhcfzrW3SjPCYxYfzDAQFO6Yz7yaAQkxDbhC0NhlwoP1cecqLEYv8SCDLK",
  "ws_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJnZ2ciLCJleHAiOjE2M..",
  "channels": [
    {
      "name": "public",
      "level": "public"
    },
    {
      "name": "$users",
      "level": "users"
    },
    {
      "name": "$group1",
      "level": "groups"
    }
  ]
}

/instant/subscribe/: get tokens for Centrifugo channels subscriptions (doc)

Publish method

The required parameters are channel and either message or data

publish("$users", "A message", data={
        "foo": "bar"}, event_class="important", bucket="notifications")

The other parameters are optional

Javascript client

Several options are available for the client side

Use the official Centrifugo js client

Manage your websockets connection manually with the official Centrifugo js library: Centrifuge-js

Use the embeded client in a script tag

In a Django template:

{% load static %}
<script src="{% static 'instant/index.min.js' %}"></script>
<script>
  const instant = $instant.useInstant();
</script>

Api doc

Use the npm client

A dedicated client is available from npm to handle the messages and connections client side in javascript or typescript

Example

An example with a backend and a frontend is available

Tests

To run the tests:

tox

django-instant's People

Contributors

mbeacom avatar synw avatar tboulogne avatar terminator14 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-instant's Issues

Could not custumize messages handlers

Hello,

Could you explain how to customize this handlers please ? Look into documentation and try to apply but did not works.

Note : debug works fine.

Thanks for help.

Regards,

Thierry

python 3.x compatible

There are a few print which require () for instant to run smoothly with python 3.x

ImportError: cannot import name 'instant_auth'

There is an import referenced here:
https://django-instant.readthedocs.io/en/latest/src/install.html

Which does not work:

Python 3.10.6 (main, Aug  3 2022, 21:50:35) [GCC 11.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from instant.views import instant_auth
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 from instant.views import instant_auth

ImportError: cannot import name 'instant_auth' from 'instant.views' (/home/amnesia/.pyenv/versions/veems/lib/python3.10/site-packages/instant/views.py)

Benchmarks

This issue is opened following to a request posted in Centrifugo's repository.

I imagine we can start comparing numbers for sending x messages vs django-channels. Please note that I know nothing about benchmarks and the methodology. How should we proceed?

AttributeError at /instant/login/ 'User' object has no attribute 'is_superuser'

I am trying to use django-instant but I am getting this problem. I am using the superuser account.

Traceback (most recent call last):
  File "C:\instant\views.py", line 55, in login_and_get_tokens
    return _get_response(request)
  File "C:\instant\views.py", line 41, in _get_response
    channels = user_channels(request.user)
  File "C:\instant\views.py", line 12, in user_channels
    user_chans = Channel.objects.for_user(user)
  File "C:\instant\models.py", line 11, in for_user
    if user.is_superuser:

Exception Type: AttributeError at /instant/login/
Exception Value: 'User' object has no attribute 'is_superuser'

Updates for centrifugo v4

Is this package actively maintained? A new release to centrifugo v4 came out in July 2022. Latest update is Mar 2022.

Example not working

I have installed django-instant, and since I am using ubuntu 18.04, I have downloaded centrifugo vv1.8.0 in my django project folder, unzipped it and ran the ./centrifugo genconfig command. After which I can successfully run centrifugo server.

./centrifugo --config=config.json

[I]: 2019/02/09 04:54:35 Config path: /vagrant/instant_server/centrifugo-1.8.0-linux-amd64/config.json
[I]: 2019/02/09 04:54:35 Version: 1.8.0
[I]: 2019/02/09 04:54:35 PID: 1348
[I]: 2019/02/09 04:54:35 Engine: In memory – single node only
[I]: 2019/02/09 04:54:35 GOMAXPROCS: 1
[I]: 2019/02/09 04:54:35 SockJS url: //cdn.jsdelivr.net/sockjs/1.1/sockjs.min.js
[I]: 2019/02/09 04:54:35 Start serving raw websocket, SockJS, API endpoints on :8000

In the django project settings I have added:

MIDDLEWARE = [
   ...
   'corsheaders.middleware.CorsMiddleware',
   'django.middleware.common.CommonMiddleware',
   ...
]

# required settings
CENTRIFUGO_SECRET_KEY = "fe3ad3c2-41ce-4d7c-8034-a42a1a3569d3" # updated the key generated in config.json
SITE_SLUG = "my_site" # used internaly to prefix the channels
SITE_NAME = "My site"

CORS_ORIGIN_WHITELIST = ('localhost:8001',)

# optionnal settings
# CENTRIFUGO_HOST = 'http://ip_here' #default: localhost
CENTRIFUGO_PORT = 8000 # default: 8001
# CENTRIFUGO_PROXY = True # default: False - remove port from URL if you are behind a proxy.

And to test the frontend example, I have installed the package pip install django-vitevue. And have added the required apps into the settings.py and urls.py:

# settings.py
INSTALLED_APPS = [
    ...
    "corsheaders",
    "instant",
    "vv",
]

# urls.py
urlpatterns = [
     # ...
     url(r'^centrifuge/auth/$', instant_auth, name='instant-auth'),
     url('^instant/', include('instant.urls')),
     ]

Finally, I ran the django server and centrifugo server separately on different terminals, and both are running properly.

After I logged in as superuser, opened up two separate browser tab, go to the /instant/ URL and go the mysite channel. But after I send a message, there is no message in either of the browser tabs.

Can you please help me figure out what's wrong? If it helps, the ubuntu server is working on a vagrant machine.

Issue: Not compatible with Custom User Model (without username)

On instant.token.py Exception Value: 'User' object has no attribute 'username'

I rely on a custom User with email instead of username with USERNAME_FIELD = 'email' set on the User class.
AbstractBaseUser.get_username is better suited
https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser.get_username

Traceback (most recent call last):
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/.../lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/orderoom/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/orderoom/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/orderoom/lib/python3.8/site-packages/instant/views.py", line 77, in get_connection_token
    return _get_response(request)
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/orderoom/lib/python3.8/site-packages/instant/views.py", line 42, in _get_response
    "ws_token": connection_token(request.user),
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/orderoom/lib/python3.8/site-packages/instant/token.py", line 11, in connection_token
    claims = {"sub": user.username, "exp": int(time.time()) + 24 * 60 * 60}
  File "/Users/maximeabry/.pyenv/versions/3.8.14/envs/orderoom/lib/python3.8/site-packages/django/utils/functional.py", line 268, in inner
    return func(_wrapped, *args)

Exception Type: AttributeError at /instant/get_token/
Exception Value: 'User' object has no attribute 'username'

Behind a proxy

Hello,

Any tips to make it run behind a proxy like nginx ?
I run the installer then setup NGINX like

https://github.com/centrifugal/documentation/blob/master/deploy/nginx.md

But no luck ;-(

any idea ?

from string import lower => lower()

if lower(event_class.lower() == "debug":
should be
if event_class.lower() == "debug":

in instant/producers.py def broadcast_py
otherwise from string import lower throws an error in python 3.x

centrifuge/auth/

I'm getting an error 500 from centrifuge.js

 setTimeout(function() {
        // method == 'get' ? self.xhr.send() : self.xhr.send(JSON.stringify(ops.data));
        xhr.send(JSON.stringify(data));
    }, 20);
    return xhr;
};

Running centrifugo and getting correct :
New SockJS session established with uid bf3add4a-4887-4c7b-a4f2-82f08429ee9f
Could I have missed something in the setup ?

running the python3 manage.py installws throws this error

File "/root/centr/lib/python3.5/site-packages/django/template/backends/django.py", line 121, in get_package_libraries module = import_module(entry[1]) File "/root/centr/lib/python3.5/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 986, in _gcd_import File "<frozen importlib._bootstrap>", line 969, in _find_and_load File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 673, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 665, in exec_module File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed File "/root/centr/lib/python3.5/site-packages/instant/templatetags/instant_tags.py", line 14, in <module> SECRET_KEY = getattr(settings, 'CENTRIFUGO_SECRET_KEY') File "/root/centr/lib/python3.5/site-packages/django/conf/__init__.py", line 80, in __getattr__ val = getattr(self._wrapped, name) AttributeError: 'Settings' object has no attribute 'CENTRIFUGO_SECRET_KEY'

Embed channels in external modules

A new feature is being developed in the database_channels branch #10 : the ability to create and remove channels at runtime using the Django admin. This make it possible to embed channels in other modules.

A test implementation lives in django-rechat: a ChatRoom model with a foreign key to the Channel model in Instant. The ChatRoom model handles the channel creation via a signal. This way the users can automate the channels management in their app.

Note: group channels had been added in this branch

New frontend

The frontend has been modernized. Features:

  • Send a message and optionally data in any channel
  • Active channels are marked
  • Per channel messages counter
  • Datatable with ordering capabilities to display the messages
  • Timeline

frontend

The original frontend was more like a demo, this one should be more useful to monitor what's going on and test channels.

It will be integrated in the 0.7 release to come (I still have to upgrade to Centrifugo 2 before releasing). To test the frontend from master:

pip install django-vitevue

Add "vv", to INSTALLED_APPS

Add the urls:

url(r'^centrifuge/auth/$', instant_auth, name='instant-auth'),
url('^instant/', include('instant.urls')),

Go to /instant/ as superuser

Note: as the upgrade to Centrifugo 2 has not already been made the cent 3.0 module must not be used: pip install cent<3

Declarative channels

A new feature is shipped in the 0.6 version: ability to declare channels in settings. Since this we had just generic public/staff/superuser channels.
I needed more specific channels and implemented a way where the user just have to declare his channels in settings to make them work, the client will autoconnect them after checking credentials. To declare a channel:

INSTANT_SUPERUSER_CHANNELS = (
  # connect from these two paths only
   ("$mysite_admin1", ("/a/path", "/another/path")),
  # connect everywhere
   ('$mysite_admin2',)
)

A specific handler for client-side can optionally be implemented for each channel. This can be used to embed channels in some other Django modules. Check the doc.

Note: this feature is still experimental: do not use in production yet [Update] : ok now

  • Declarative channels mechanism
  • Optional custom handlers for each channel

Database channels

Goal

The channels are declared in settings, which means that they can not be changed at runtime. I needed something more flexible as I was refactoring django-rechat with rooms: the ability to add and remove channels at runtime becomes required.

How it works

The new database channels are created in the admin like any other model. When the object is saved or deleted the channels list is updated in memory, so that it does not need to query the database for the channels list when auto connecting the channels at page load, or when the backend authenticates a user.

Each time a channel is created/updated/deleted the clients auto-connect process for the next requests will be updated (it's possible to specify the paths to connect from) after checking credentials.

Todo

  • Manage the javascript handlers for the database channels

Handle the events in Python-side.

Hello,

I really like the idea of this library but still scratching my head to figure out how to handle the events in Python. Could you please elaborate more on this ? What I would like to do is creating bi-directional communication channels between Django projects.

Thank you

Channels handlers

Hello,

I put a default.js handler working well.
I create a staff channel ($mysite_staff1). Create the appropriate handler ($mysite_staff1.js).

It does not work ?

Note debug :

No handlers found for custom channels

any idea please ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.