Skip to content

Commit

Permalink
Merge pull request #16 from ml-learning/channels-2
Browse files Browse the repository at this point in the history
Compatibility for django-channels v2.4
  • Loading branch information
yourcelf committed Mar 29, 2020
2 parents 92dfa4b + 45212f7 commit 499fc2f
Show file tree
Hide file tree
Showing 17 changed files with 326 additions and 281 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ dist/
build/
docs/_build
*.egg-info
.idea/
1 change: 0 additions & 1 deletion channels_presence/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from __future__ import unicode_literals

2 changes: 0 additions & 2 deletions channels_presence/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

from django.contrib import admin

# Register your models here.
2 changes: 0 additions & 2 deletions channels_presence/apps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

from django.apps import AppConfig


Expand Down
8 changes: 0 additions & 8 deletions channels_presence/channels.py

This file was deleted.

20 changes: 11 additions & 9 deletions channels_presence/decorators.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
from __future__ import unicode_literals

import functools

from channels_presence.models import Presence


def touch_presence(func):
@functools.wraps(func)
def inner(message, *args, **kwargs):
Presence.objects.touch(message.reply_channel.name)
if message.content.get('text') == '"heartbeat"':
def inner(consumer, text_data, *args, **kwargs):
Presence.objects.touch(consumer.channel_name)
if text_data == '"heartbeat"':
return
return func(message, *args, **kwargs)
return func(consumer, text_data, *args, **kwargs)

return inner


def remove_presence(func):
@functools.wraps(func)
def inner(message, *args, **kwargs):
Presence.objects.leave_all(message.reply_channel.name)
return func(message, *args, **kwargs)
def inner(consumer, *args, **kwargs):
Presence.objects.leave_all(consumer.channel_name)
return func(consumer, *args, **kwargs)

return inner
72 changes: 50 additions & 22 deletions channels_presence/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.9 on 2016-08-12 16:41
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
Expand All @@ -12,38 +8,70 @@ class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]

operations = [
migrations.CreateModel(
name='Presence',
name="Presence",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('channel_name', models.CharField(help_text='Reply channel for connection that is present', max_length=255)),
('last_seen', models.DateTimeField(default=django.utils.timezone.now)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"channel_name",
models.CharField(
help_text="Reply channel for connection that is present",
max_length=255,
),
),
("last_seen", models.DateTimeField(default=django.utils.timezone.now)),
],
),
migrations.CreateModel(
name='Room',
name="Room",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('channel_name', models.CharField(help_text='Group channel name for this room', max_length=255, unique=True)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"channel_name",
models.CharField(
help_text="Group channel name for this room",
max_length=255,
unique=True,
),
),
],
),
migrations.AddField(
model_name='presence',
name='room',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='channels_presence.Room'),
model_name="presence",
name="room",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="channels_presence.Room"
),
),
migrations.AddField(
model_name='presence',
name='user',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
model_name="presence",
name="user",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
migrations.AlterUniqueTogether(
name='presence',
unique_together=set([('room', 'channel_name')]),
name="presence", unique_together=set([("room", "channel_name")])
),
]
67 changes: 35 additions & 32 deletions channels_presence/models.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
from __future__ import unicode_literals, absolute_import

import json
from datetime import timedelta

from django.db import models
from django.conf import settings
from django.contrib.auth import get_user_model
from django.utils.encoding import python_2_unicode_compatible
from django.utils.timezone import now

from channels import Group
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from channels_presence.signals import presence_changed

channel_layer = get_channel_layer()


class PresenceManager(models.Manager):
def touch(self, channel_name):
self.filter(channel_name=channel_name).update(last_seen=now())

def leave_all(self, channel_name):
for presence in self.select_related('room').filter(channel_name=channel_name):
for presence in self.select_related("room").filter(channel_name=channel_name):
room = presence.room
room.remove_presence(presence=presence)

@python_2_unicode_compatible

class Presence(models.Model):
room = models.ForeignKey('Room', on_delete=models.CASCADE)
channel_name = models.CharField(max_length=255,
help_text="Reply channel for connection that is present")
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True,
on_delete=models.CASCADE)
room = models.ForeignKey("Room", on_delete=models.CASCADE)
channel_name = models.CharField(
max_length=255, help_text="Reply channel for connection that is present"
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE
)
last_seen = models.DateTimeField(default=now)

objects = PresenceManager()
Expand All @@ -36,7 +39,8 @@ def __str__(self):
return self.channel_name

class Meta:
unique_together = [('room', 'channel_name')]
unique_together = [("room", "channel_name")]


class RoomManager(models.Manager):
def add(self, room_channel_name, user_channel_name, user=None):
Expand All @@ -58,32 +62,27 @@ def prune_presences(self, channel_layer=None, age=None):
def prune_rooms(self):
Room.objects.filter(presence__isnull=True).delete()

@python_2_unicode_compatible

class Room(models.Model):
channel_name = models.CharField(max_length=255, unique=True,
help_text="Group channel name for this room")
channel_name = models.CharField(
max_length=255, unique=True, help_text="Group channel name for this room"
)

objects = RoomManager()

def __str__(self):
return self.channel_name

def add_presence(self, channel_name, user=None):
# Check user.is_authenticated for Django 1.10+ and
# user.is_authenticated() for prior versions.
# https://docs.djangoproject.com/en/1.11/ref/contrib/auth/#django.contrib.auth.models.User.is_authenticated
authenticated = user and (
user.is_authenticated == True or
(callable(user.is_authenticated) and user.is_authenticated())
)

if user and user.is_authenticated:
authed_user = user
else:
authed_user = None
presence, created = Presence.objects.get_or_create(
room=self,
channel_name=channel_name,
user=user if authenticated else None
room=self, channel_name=channel_name, user=authed_user
)
if created:
Group(self.channel_name).add(channel_name)
async_to_sync(channel_layer.group_add)(self.channel_name, channel_name)
self.broadcast_changed(added=presence)

def remove_presence(self, channel_name=None, presence=None):
Expand All @@ -92,7 +91,10 @@ def remove_presence(self, channel_name=None, presence=None):
presence = Presence.objects.get(room=self, channel_name=channel_name)
except Presence.DoesNotExist:
return
Group(self.channel_name).discard(presence.channel_name)

async_to_sync(channel_layer.group_discard)(
self.channel_name, presence.channel_name
)
presence.delete()
self.broadcast_changed(removed=presence)

Expand All @@ -101,8 +103,7 @@ def prune_presences(self, age_in_seconds=None):
age_in_seconds = getattr(settings, "CHANNELS_PRESENCE_MAX_AGE", 60)

num_deleted, num_per_type = Presence.objects.filter(
room=self,
last_seen__lt=now() - timedelta(seconds=age_in_seconds)
room=self, last_seen__lt=now() - timedelta(seconds=age_in_seconds)
).delete()
if num_deleted > 0:
self.broadcast_changed(bulk_change=True)
Expand All @@ -115,8 +116,10 @@ def get_anonymous_count(self):
return self.presence_set.filter(user=None).count()

def broadcast_changed(self, added=None, removed=None, bulk_change=False):
presence_changed.send(sender=self.__class__,
presence_changed.send(
sender=self.__class__,
room=self,
added=added,
removed=removed,
bulk_change=bulk_change)
bulk_change=bulk_change,
)
9 changes: 3 additions & 6 deletions channels_presence/signals.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from __future__ import unicode_literals

from django import dispatch

presence_changed = dispatch.Signal(providing_args=[
"room", "added", "removed", "bulk_change"
])

presence_changed = dispatch.Signal(
providing_args=["room", "added", "removed", "bulk_change"]
)
2 changes: 0 additions & 2 deletions channels_presence/tasks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

from celery import shared_task

from channels_presence.models import Room
Expand Down
2 changes: 0 additions & 2 deletions channels_presence/tests.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

from django.test import TestCase

# Create your tests here.
2 changes: 0 additions & 2 deletions channels_presence/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

from django.shortcuts import render

# Create your views here.

0 comments on commit 499fc2f

Please sign in to comment.