add sse server

This commit is contained in:
rmanach 2023-09-17 14:06:23 +02:00
parent bf365b1204
commit bd11ddbd60
9 changed files with 165 additions and 15 deletions

View File

@ -0,0 +1,22 @@
# Generated by Django 4.2.5 on 2023-09-16 17:21
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
("deployment", "0006_alter_deployment_id_alter_deployment_status_and_more"),
]
operations = [
migrations.AlterField(
model_name="deployment",
name="id",
field=models.UUIDField(
default=uuid.UUID("0cc4ae03-f52e-4f3a-9fe1-fecda707b20e"),
primary_key=True,
serialize=False,
),
),
]

View File

@ -4,6 +4,9 @@ from uuid import uuid4
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.db.models.signals import pre_save, pre_delete
from django.dispatch import receiver
from django_eventstream import send_event
class Type(Enum): class Type(Enum):
@ -41,3 +44,9 @@ class Deployment(models.Model):
def __str__(self): def __str__(self):
return f"{self.name} | {self.type} | {self.status}" return f"{self.name} | {self.type} | {self.status}"
@receiver(pre_save, sender=Deployment)
@receiver(pre_delete, sender=Deployment)
def deployment_update_handler(sender, instance, **kwargs):
send_event("deployment", "update", {"id": instance.id, "status": instance.status})

View File

@ -9,7 +9,7 @@ from django.http import (
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from deployment.forms import DeploymentForm from deployment.forms import DeploymentForm
from deployment.models import Deployment from deployment.models import Deployment, Status
def index(request): def index(request):
@ -19,14 +19,16 @@ def index(request):
page_number = request.GET.get("page") page_number = request.GET.get("page")
page_obj = paginator.get_page(page_number) page_obj = paginator.get_page(page_number)
return render(request, "deployment/board.html", {"page_obj": page_obj}) return render(
request, "deployment/board.html", {"page_obj": page_obj, "url": "/events/"}
)
def details(request, deployment_id): def details(request, deployment_id):
deployment = get_object_or_404(Deployment, id=deployment_id) deployment = get_object_or_404(Deployment, id=deployment_id)
if request.method == "POST": if request.method == "POST":
if deployment.status == deployment.RUNNING: if deployment.status == Status.RUNNING:
return HttpResponseBadRequest("deployment is running") return HttpResponseBadRequest("deployment is running")
try: try:
deployment.delete() deployment.delete()

View File

@ -8,9 +8,27 @@ https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
""" """
import os import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
from django.urls import path, re_path
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import django_eventstream
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mumui.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
application = get_asgi_application() application = ProtocolTypeRouter(
{
"http": URLRouter(
[
path(
"events/",
AuthMiddlewareStack(
URLRouter(django_eventstream.routing.urlpatterns)
),
{"channels": ["test"]},
),
re_path(r"", get_asgi_application()),
]
),
}
)

View File

@ -38,9 +38,12 @@ INSTALLED_APPS = [
"django.contrib.messages", "django.contrib.messages",
"django.contrib.staticfiles", "django.contrib.staticfiles",
"deployment", "deployment",
"channels",
"django_eventstream",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
"django_grip.GripMiddleware",
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
@ -125,3 +128,5 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
LOGIN_REDIRECT_URL = "home" LOGIN_REDIRECT_URL = "home"
LOGOUT_REDIRECT_URL = "home" LOGOUT_REDIRECT_URL = "home"
ASGI_APPLICATION = "mumui.asgi.application"

43
requirements.txt Normal file
View File

@ -0,0 +1,43 @@
asgiref==3.7.2
attrs==23.1.0
autobahn==23.6.2
Automat==22.10.0
black==23.9.1
certifi==2023.7.22
cffi==1.15.1
channels==3.0.5
charset-normalizer==3.2.0
click==8.1.7
constantly==15.1.0
cryptography==41.0.3
daphne==3.0.2
Django==4.2.5
django-eventstream==4.5.1
django-grip==3.4.0
gripcontrol==4.2.0
hyperlink==21.0.0
idna==3.4
incremental==22.10.0
MarkupSafe==2.1.3
mypy-extensions==1.0.0
packaging==23.1
pathspec==0.11.2
platformdirs==3.10.0
pubcontrol==3.5.0
pyasn1==0.5.0
pyasn1-modules==0.3.0
pycparser==2.21
PyJWT==2.8.0
pyOpenSSL==23.2.0
requests==2.31.0
ruff==0.0.290
service-identity==23.1.0
six==1.16.0
sqlparse==0.4.4
tomli==2.0.1
Twisted==23.8.0
txaio==23.1.1
typing_extensions==4.7.1
urllib3==2.0.4
Werkzeug==2.3.7
zope.interface==6.0

View File

@ -3,8 +3,9 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>{% block title %}mumui{% endblock %}</title> <title>{% block title %}mumui{% endblock %}</title>
{% block headscript %}{% endblock %}
</head> </head>
<body> <body {% block bodyattr %}{% endblock %}>
<main> <main>
{% if user.is_authenticated or "login" in request.path %} {% if user.is_authenticated or "login" in request.path %}
{% block content %} {% block content %}
@ -17,5 +18,6 @@
<a href="{% url 'login' %}">log In</a> <a href="{% url 'login' %}">log In</a>
{% endif %} {% endif %}
</main> </main>
{% block script %}{% endblock %}
</body> </body>
</html> </html>

View File

@ -1,15 +1,42 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %}
{% block title %}deployment's board{% endblock %} {% block title %}deployment's board{% endblock %}
{% block headscript %}
<script src="{% static 'django_eventstream/json2.js' %}"></script>
<script src="{% static 'django_eventstream/eventsource.min.js' %}"></script>
<script src="{% static 'django_eventstream/reconnecting-eventsource.js' %}"></script>
{% endblock %}
{% block bodyattr %}
onload="start();"
{% endblock %}
{% block content %} {% block content %}
{{ user.username }}'s board {{ user.username }}'s board
{% if page_obj %} {% if page_obj %}
<ul> <table>
<tr>
<th>name</th>
<th>type</th>
<th>status</th>
<th></th>
</tr>
{% for deployment in page_obj %} {% for deployment in page_obj %}
<li><a href="{% url 'deployment-details' deployment.id %}">{{ deployment.name }} | {{ deployment.type }} | {{ deployment.status }}</a></li> <tr id="{{ deployment.id }}">
<th name="name">{{ deployment.name }}</th>
<th name="type">{{ deployment.type }}</th>
<th name="status">{{ deployment.status }}</th>
<th>
<a href="{% url 'deployment-details' deployment.id %}">
<button>details</button>
</a>
</th>
</tr>
{% endfor %} {% endfor %}
</ul> </table>
<div class="pagination"> <div class="pagination">
<span class="step-links"> <span class="step-links">
{% if page_obj.has_previous %} {% if page_obj.has_previous %}
@ -34,3 +61,25 @@
<button>create</button> <button>create</button>
</a> </a>
{% endblock %} {% endblock %}
{% block script %}
<script>
var start = function () {
var es = new ReconnectingEventSource('{{ url|safe }}');
es.onopen = function () {
console.log('connected');
};
es.onerror = function () {
console.log('connection error');
};
es.addEventListener('deployment', function (e) {
e = JSON.parse(e.data);
console.log('stream reset: ' + JSON.stringify(e.channels));
}, false);
};
</script>
{% endblock %}

View File

@ -10,11 +10,11 @@
<th>type</th> <th>type</th>
<th>status</th> <th>status</th>
</tr> </tr>
<tr> <tr id="{{ deployment.id }}">
<th>{{ deployment.id }}</th> <th name="id">{{ deployment.id }}</th>
<th>{{ deployment.name }}</th> <th name="name">{{ deployment.name }}</th>
<th>{{ deployment.type }}</th> <th name="type">{{ deployment.type }}</th>
<th>{{ deployment.status }}</th> <th name="status">{{ deployment.status }}</th>
</tr> </tr>
</table> </table>
<form action="" method="post"> <form action="" method="post">