WIP
This commit is contained in:
		
						commit
						70dcfa328b
					
				| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					*.pyc
 | 
				
			||||||
 | 
					__pycache__
 | 
				
			||||||
 | 
					*.sqlite3
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					from celery import Celery
 | 
				
			||||||
 | 
					from xmlrpc.client import ServerProxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server = ServerProxy('http://localhost:9001/RPC2')
 | 
				
			||||||
 | 
					app = Celery('tasks', broker='redis://localhost')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print(server.supervisor.getState())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.task
 | 
				
			||||||
 | 
					def start_restream(name):
 | 
				
			||||||
 | 
					    print(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.task
 | 
				
			||||||
 | 
					def stop_restream(name):
 | 
				
			||||||
 | 
					    print(name)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					from celery import Celery
 | 
				
			||||||
 | 
					from xmlrpc.client import ServerProxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server = ServerProxy('http://localhost:9001/RPC2')
 | 
				
			||||||
 | 
					app = Celery('tasks', broker='redis://localhost')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print(server.supervisor.getState())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.task
 | 
				
			||||||
 | 
					def start_restream(name):
 | 
				
			||||||
 | 
					    print(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.task
 | 
				
			||||||
 | 
					def stop_restream(name):
 | 
				
			||||||
 | 
					    print(name)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					"""Django's command-line utility for administrative tasks."""
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'portier.settings')
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        from django.core.management import execute_from_command_line
 | 
				
			||||||
 | 
					    except ImportError as exc:
 | 
				
			||||||
 | 
					        raise ImportError(
 | 
				
			||||||
 | 
					            "Couldn't import Django. Are you sure it's installed and "
 | 
				
			||||||
 | 
					            "available on your PYTHONPATH environment variable? Did you "
 | 
				
			||||||
 | 
					            "forget to activate a virtual environment?"
 | 
				
			||||||
 | 
					        ) from exc
 | 
				
			||||||
 | 
					    execute_from_command_line(sys.argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					from __future__ import absolute_import, unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This will make sure the app is always imported when
 | 
				
			||||||
 | 
					# Django starts so that shared_task will use this app.
 | 
				
			||||||
 | 
					from .celery import app as celery_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = ('celery_app',)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					ASGI config for portier project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It exposes the ASGI callable as a module-level variable named ``application``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For more information on this file, see
 | 
				
			||||||
 | 
					https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.core.asgi import get_asgi_application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'portier.settings')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					application = get_asgi_application()
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					from __future__ import absolute_import, unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from celery import Celery
 | 
				
			||||||
 | 
					os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')
 | 
				
			||||||
 | 
					app = Celery('proj')
 | 
				
			||||||
 | 
					app.config_from_object('django.conf:settings', namespace='CELERY')
 | 
				
			||||||
 | 
					app.autodiscover_tasks()
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,129 @@
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					Django settings for portier project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generated by 'django-admin startproject' using Django 3.0.5.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For more information on this file, see
 | 
				
			||||||
 | 
					https://docs.djangoproject.com/en/3.0/topics/settings/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For the full list of settings and their values, see
 | 
				
			||||||
 | 
					https://docs.djangoproject.com/en/3.0/ref/settings/
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
 | 
				
			||||||
 | 
					BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Quick-start development settings - unsuitable for production
 | 
				
			||||||
 | 
					# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SECURITY WARNING: keep the secret key used in production secret!
 | 
				
			||||||
 | 
					SECRET_KEY = '-xcxbgd8w&w&nv0-e!5=kd%u5esjt07$h5*+$goica9nc$l!(9'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SECURITY WARNING: don't run with debug turned on in production!
 | 
				
			||||||
 | 
					DEBUG = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALLOWED_HOSTS = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application definition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSTALLED_APPS = [
 | 
				
			||||||
 | 
					    'django.contrib.admin',
 | 
				
			||||||
 | 
					    'django.contrib.auth',
 | 
				
			||||||
 | 
					    'django.contrib.contenttypes',
 | 
				
			||||||
 | 
					    'django.contrib.sessions',
 | 
				
			||||||
 | 
					    'django.contrib.messages',
 | 
				
			||||||
 | 
					    'django.contrib.staticfiles',
 | 
				
			||||||
 | 
					    'srs.apps.SrsConfig',
 | 
				
			||||||
 | 
					    'restream.apps.RestreamConfig',
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MIDDLEWARE = [
 | 
				
			||||||
 | 
					    'django.middleware.security.SecurityMiddleware',
 | 
				
			||||||
 | 
					    'django.contrib.sessions.middleware.SessionMiddleware',
 | 
				
			||||||
 | 
					    'django.middleware.common.CommonMiddleware',
 | 
				
			||||||
 | 
					    'django.middleware.csrf.CsrfViewMiddleware',
 | 
				
			||||||
 | 
					    'django.contrib.auth.middleware.AuthenticationMiddleware',
 | 
				
			||||||
 | 
					    'django.contrib.messages.middleware.MessageMiddleware',
 | 
				
			||||||
 | 
					    'django.middleware.clickjacking.XFrameOptionsMiddleware',
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ROOT_URLCONF = 'portier.urls'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEMPLATES = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        'BACKEND': 'django.template.backends.django.DjangoTemplates',
 | 
				
			||||||
 | 
					        'DIRS': [],
 | 
				
			||||||
 | 
					        'APP_DIRS': True,
 | 
				
			||||||
 | 
					        'OPTIONS': {
 | 
				
			||||||
 | 
					            'context_processors': [
 | 
				
			||||||
 | 
					                'django.template.context_processors.debug',
 | 
				
			||||||
 | 
					                'django.template.context_processors.request',
 | 
				
			||||||
 | 
					                'django.contrib.auth.context_processors.auth',
 | 
				
			||||||
 | 
					                'django.contrib.messages.context_processors.messages',
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WSGI_APPLICATION = 'portier.wsgi.application'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Database
 | 
				
			||||||
 | 
					# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DATABASES = {
 | 
				
			||||||
 | 
					    'default': {
 | 
				
			||||||
 | 
					        'ENGINE': 'django.db.backends.sqlite3',
 | 
				
			||||||
 | 
					        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Password validation
 | 
				
			||||||
 | 
					# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTH_PASSWORD_VALIDATORS = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Internationalization
 | 
				
			||||||
 | 
					# https://docs.djangoproject.com/en/3.0/topics/i18n/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LANGUAGE_CODE = 'en-us'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TIME_ZONE = 'UTC'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USE_I18N = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USE_L10N = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USE_TZ = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Static files (CSS, JavaScript, Images)
 | 
				
			||||||
 | 
					# https://docs.djangoproject.com/en/3.0/howto/static-files/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					STATIC_URL = '/static/'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CELERY_BROKER_URL = 'redis://localhost:6379'
 | 
				
			||||||
 | 
					CELERY_RESULT_BACKEND = 'redis://localhost:6379'
 | 
				
			||||||
 | 
					CELERY_ACCEPT_CONTENT = ['application/json']
 | 
				
			||||||
 | 
					CELERY_RESULT_SERIALIZER = 'json'
 | 
				
			||||||
 | 
					CELERY_TASK_SERIALIZER = 'json'
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					"""portier URL Configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `urlpatterns` list routes URLs to views. For more information please see:
 | 
				
			||||||
 | 
					    https://docs.djangoproject.com/en/3.0/topics/http/urls/
 | 
				
			||||||
 | 
					Examples:
 | 
				
			||||||
 | 
					Function views
 | 
				
			||||||
 | 
					    1. Add an import:  from my_app import views
 | 
				
			||||||
 | 
					    2. Add a URL to urlpatterns:  path('', views.home, name='home')
 | 
				
			||||||
 | 
					Class-based views
 | 
				
			||||||
 | 
					    1. Add an import:  from other_app.views import Home
 | 
				
			||||||
 | 
					    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
 | 
				
			||||||
 | 
					Including another URLconf
 | 
				
			||||||
 | 
					    1. Import the include() function: from django.urls import include, path
 | 
				
			||||||
 | 
					    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					from django.contrib import admin
 | 
				
			||||||
 | 
					from django.urls import include, path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					urlpatterns = [
 | 
				
			||||||
 | 
					    path('admin/', admin.site.urls),
 | 
				
			||||||
 | 
					    path('srs/', include('srs.urls'))
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					WSGI config for portier project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It exposes the WSGI callable as a module-level variable named ``application``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For more information on this file, see
 | 
				
			||||||
 | 
					https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.core.wsgi import get_wsgi_application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'portier.settings')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					application = get_wsgi_application()
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					from django.contrib import admin
 | 
				
			||||||
 | 
					from .models import RestreamConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RestreamConfigAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					    fields = ['name', 'active', 'streamkey', 'target']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					admin.site.register(RestreamConfig, RestreamConfigAdmin)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					from django.apps import AppConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RestreamConfig(AppConfig):
 | 
				
			||||||
 | 
					    name = 'restream'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ready(self):
 | 
				
			||||||
 | 
					        import restream.signals  #noqa
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					# Generated by Django 3.0.5 on 2020-04-13 17:45
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initial = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('srs', '0005_auto_20200413_1745'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='RestreamConfig',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('target', models.CharField(max_length=500)),
 | 
				
			||||||
 | 
					                ('name', models.CharField(max_length=100)),
 | 
				
			||||||
 | 
					                ('active', models.BooleanField()),
 | 
				
			||||||
 | 
					                ('streamkey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='srs.Streamkey')),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					from django.db import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create your models here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from srs.models import Application, Streamkey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RestreamConfig(models.Model):
 | 
				
			||||||
 | 
					    streamkey = models.ForeignKey(Streamkey, on_delete=models.CASCADE)
 | 
				
			||||||
 | 
					    target = models.CharField(max_length=500)
 | 
				
			||||||
 | 
					    name = models.CharField(max_length=100)
 | 
				
			||||||
 | 
					    active = models.BooleanField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return '{} to {}'.format(self.streamkey, self.name)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.dispatch import receiver
 | 
				
			||||||
 | 
					from srs.signals import on_publish, on_unpublish
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from portier.celery import app as celery
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .models import RestreamConfig
 | 
				
			||||||
 | 
					from srs.models import Streamkey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@receiver(on_unpublish)
 | 
				
			||||||
 | 
					def callback_on_unpublish(sender, **kwargs):
 | 
				
			||||||
 | 
					    logger.info("stop publish - {}".format(kwargs['name']))
 | 
				
			||||||
 | 
					    celery.send_task('main.stop_restream', kwargs={'name':kwargs['name']})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@receiver(on_publish)
 | 
				
			||||||
 | 
					def callback_on_publish(sender, **kwargs):
 | 
				
			||||||
 | 
					    logger.info("start publish - {}".format(kwargs['name']))
 | 
				
			||||||
 | 
					    streamkey = Streamkey.objects.get(key=kwargs['streamkey'])
 | 
				
			||||||
 | 
					    configs = RestreamConfig.objects.filter(streamkey=streamkey)
 | 
				
			||||||
 | 
					    for config in configs:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					        celery.send_task('main.start_restream', kwargs={
 | 
				
			||||||
 | 
					            'app': kwargs['app'],
 | 
				
			||||||
 | 
					            'streamkey': kwargs['streamkey'],
 | 
				
			||||||
 | 
					            'target': config.target,
 | 
				
			||||||
 | 
					            'id': config.id
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					from django.test import TestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create your tests here.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					from django.shortcuts import render
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create your views here.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					from django.contrib import admin
 | 
				
			||||||
 | 
					from .models import Application, Streamkey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ApplicationAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					    fields = ['name']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StreamkeyAdmin(admin.ModelAdmin):
 | 
				
			||||||
 | 
					    fields = ['application', 'key', 'name']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					admin.site.register(Application, ApplicationAdmin)
 | 
				
			||||||
 | 
					admin.site.register(Streamkey, StreamkeyAdmin)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					from django.apps import AppConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SrsConfig(AppConfig):
 | 
				
			||||||
 | 
					    name = 'srs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ready(self):
 | 
				
			||||||
 | 
					        import srs.signals  #noqa
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					# Generated by Django 3.0.5 on 2020-04-13 15:30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initial = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='Application',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('name', models.CharField(max_length=16)),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='Streamkey',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('key', models.CharField(max_length=64)),
 | 
				
			||||||
 | 
					                ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='srs.Application')),
 | 
				
			||||||
 | 
					                ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					# Generated by Django 3.0.5 on 2020-04-13 15:40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('srs', '0001_initial'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='streamkey',
 | 
				
			||||||
 | 
					            name='name',
 | 
				
			||||||
 | 
					            field=models.CharField(default='', max_length=16),
 | 
				
			||||||
 | 
					            preserve_default=False,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					# Generated by Django 3.0.5 on 2020-04-13 17:21
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('srs', '0002_streamkey_name'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.RemoveField(
 | 
				
			||||||
 | 
					            model_name='streamkey',
 | 
				
			||||||
 | 
					            name='owner',
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					# Generated by Django 3.0.5 on 2020-04-13 17:36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('srs', '0003_remove_streamkey_owner'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='application',
 | 
				
			||||||
 | 
					            name='name',
 | 
				
			||||||
 | 
					            field=models.CharField(max_length=100, unique=True),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='streamkey',
 | 
				
			||||||
 | 
					            name='key',
 | 
				
			||||||
 | 
					            field=models.CharField(max_length=64, unique=True),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='streamkey',
 | 
				
			||||||
 | 
					            name='name',
 | 
				
			||||||
 | 
					            field=models.CharField(max_length=100),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					# Generated by Django 3.0.5 on 2020-04-13 17:45
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('srs', '0004_auto_20200413_1736'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='streamkey',
 | 
				
			||||||
 | 
					            name='key',
 | 
				
			||||||
 | 
					            field=models.CharField(default=uuid.UUID('b5777854-4533-49dc-b38d-69738d8844d6'), max_length=64, unique=True),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					from django.db import models
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import signals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Application(models.Model):
 | 
				
			||||||
 | 
					    name = models.CharField(max_length=100, unique=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Streamkey(models.Model):
 | 
				
			||||||
 | 
					    application = models.ForeignKey(Application, on_delete=models.CASCADE)
 | 
				
			||||||
 | 
					    key = models.CharField(max_length=64, unique=True, default=uuid.uuid4())
 | 
				
			||||||
 | 
					    name = models.CharField(max_length=100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_publish(self, client_ip, client_id, vhost, param):
 | 
				
			||||||
 | 
					        signals.on_publish.send(sender=self.__class__,
 | 
				
			||||||
 | 
					                                name=self.name,
 | 
				
			||||||
 | 
					                                streamkey=self.key,
 | 
				
			||||||
 | 
					                                app=str(self.application),
 | 
				
			||||||
 | 
					                                client_ip=client_ip,
 | 
				
			||||||
 | 
					                                client_id=client_id,
 | 
				
			||||||
 | 
					                                vhost=vhost,
 | 
				
			||||||
 | 
					                                param=param
 | 
				
			||||||
 | 
					                                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_unpublish(self, client_ip, client_id, vhost, param):
 | 
				
			||||||
 | 
					        signals.on_unpublish.send(sender=self.__class__,
 | 
				
			||||||
 | 
					                                name=self.name,
 | 
				
			||||||
 | 
					                                streamkey=self.key,
 | 
				
			||||||
 | 
					                                app=str(self.application),
 | 
				
			||||||
 | 
					                                client_ip=client_ip,
 | 
				
			||||||
 | 
					                                client_id=client_id,
 | 
				
			||||||
 | 
					                                vhost=vhost,
 | 
				
			||||||
 | 
					                                param=param
 | 
				
			||||||
 | 
					                                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return '{}'.format(self.name)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					from django.dispatch import Signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on_publish = Signal(providing_args=['application','streamkey','node'])
 | 
				
			||||||
 | 
					on_unpublish = Signal(providing_args=['application','streamkey','node'])
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					from django.test import TestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create your tests here.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					from django.urls import path
 | 
				
			||||||
 | 
					from . import views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					urlpatterns = [
 | 
				
			||||||
 | 
					    path('callback', views.callback, name='callback'),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.http import HttpResponse
 | 
				
			||||||
 | 
					from django.shortcuts import render
 | 
				
			||||||
 | 
					from django.views.decorators.csrf import csrf_exempt
 | 
				
			||||||
 | 
					from django.core.exceptions import ObjectDoesNotExist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@csrf_exempt
 | 
				
			||||||
 | 
					def callback(request):
 | 
				
			||||||
 | 
					    if request.method != 'POST':
 | 
				
			||||||
 | 
					        return HttpResponse('1', status=405)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_data = json.loads(request.body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        client_ip = json_data['ip']
 | 
				
			||||||
 | 
					        client_id = json_data['client_id']
 | 
				
			||||||
 | 
					        vhost = json_data['vhost']
 | 
				
			||||||
 | 
					        param = json_data['param']
 | 
				
			||||||
 | 
					        app_name = json_data['app']
 | 
				
			||||||
 | 
					        stream_name = json_data['stream']
 | 
				
			||||||
 | 
					    except KeyError:
 | 
				
			||||||
 | 
					        return HttpResponse('1', status=401)
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        app = models.Application.objects.get(name=app_name)
 | 
				
			||||||
 | 
					        streamkey = models.Streamkey.objects.get(key=stream_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    except ObjectDoesNotExist:
 | 
				
			||||||
 | 
					        return HttpResponse('1', status=401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if json_data.get('action') == 'on_publish':
 | 
				
			||||||
 | 
					      streamkey.on_publish(client_ip=client_ip,
 | 
				
			||||||
 | 
					                         client_id=client_id,
 | 
				
			||||||
 | 
					                         vhost=vhost,
 | 
				
			||||||
 | 
					                         param=param
 | 
				
			||||||
 | 
					                         )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if json_data.get('action') == 'on_unpublish':
 | 
				
			||||||
 | 
					      streamkey.on_unpublish(client_ip=client_ip,
 | 
				
			||||||
 | 
					                         client_id=client_id,
 | 
				
			||||||
 | 
					                         vhost=vhost,
 | 
				
			||||||
 | 
					                         param=param
 | 
				
			||||||
 | 
					                         )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return HttpResponse('0')
 | 
				
			||||||
		Loading…
	
		Reference in New Issue