Skip to content
Snippets Groups Projects
Verified Commit dd5881f2 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Founndations for real-time event serialization/subscription/broadcasting

parent fd7c1e5d
No related branches found
No related tags found
No related merge requests found
......@@ -83,6 +83,7 @@ if RAVEN_ENABLED:
# Apps specific for this project go here.
LOCAL_APPS = (
'funkwhale_api.common',
'funkwhale_api.activity.apps.ActivityConfig',
'funkwhale_api.users', # custom users app
# Your stuff: custom apps go here
'funkwhale_api.instance',
......
from django.apps import AppConfig, apps
from . import record
class ActivityConfig(AppConfig):
name = 'funkwhale_api.activity'
def ready(self):
super(ActivityConfig, self).ready()
app_names = [app.name for app in apps.app_configs.values()]
record.registry.autodiscover(app_names)
import persisting_theory
class ActivityRegistry(persisting_theory.Registry):
look_into = 'activities'
def _register_for_model(self, model, attr, value):
key = model._meta.label
d = self.setdefault(key, {'consumers': []})
d[attr] = value
def register_serializer(self, serializer_class):
model = serializer_class.Meta.model
self._register_for_model(model, 'serializer', serializer_class)
return serializer_class
def register_consumer(self, label):
def decorator(func):
consumers = self[label]['consumers']
if func not in consumers:
consumers.append(func)
return func
return decorator
registry = ActivityRegistry()
def send(obj):
conf = registry[obj.__class__._meta.label]
consumers = conf['consumers']
if not consumers:
return
serializer = conf['serializer'](obj)
for consumer in consumers:
consumer(data=serializer.data, obj=obj)
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()
group_send = async_to_sync(channel_layer.group_send)
import pytest
from django.db import models
from rest_framework import serializers
from funkwhale_api.activity import record
class FakeModel(models.Model):
class Meta:
app_label = 'tests'
class FakeSerializer(serializers.ModelSerializer):
class Meta:
model = FakeModel
fields = ['id']
def test_can_bind_serializer_to_model(activity_registry):
activity_registry.register_serializer(FakeSerializer)
assert activity_registry['tests.FakeModel']['serializer'] == FakeSerializer
def test_can_bind_consumer_to_model(activity_registry):
activity_registry.register_serializer(FakeSerializer)
@activity_registry.register_consumer('tests.FakeModel')
def propagate(data, obj):
return True
assert activity_registry['tests.FakeModel']['consumers'] == [propagate]
def test_record_object_calls_consumer(activity_registry, mocker):
activity_registry.register_serializer(FakeSerializer)
stub = mocker.stub()
activity_registry.register_consumer('tests.FakeModel')(stub)
o = FakeModel(id=1)
data = FakeSerializer(o).data
record.send(o)
stub.assert_called_once_with(data=data, obj=o)
......@@ -5,6 +5,7 @@ from django.core.cache import cache as django_cache
from dynamic_preferences.registries import global_preferences_registry
from rest_framework.test import APIClient
from funkwhale_api.activity import record
from funkwhale_api.taskapp import celery
......@@ -81,3 +82,28 @@ def superuser_client(db, factories, client):
setattr(client, 'user', user)
yield client
delattr(client, 'user')
@pytest.fixture
def activity_registry():
r = record.registry
state = list(record.registry.items())
yield record.registry
record.registry.clear()
for key, value in state:
record.registry[key] = value
@pytest.fixture
def activity_registry():
r = record.registry
state = list(record.registry.items())
yield record.registry
record.registry.clear()
for key, value in state:
record.registry[key] = value
@pytest.fixture
def activity_muted(activity_registry, mocker):
yield mocker.patch.object(record, 'send')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment