Skip to main content

Django-Websocket-laajennos

Project description

django-pistoke

PyPI Tox Codecov

Django-laajennos, joka mahdollistaa Websocket-pyyntöjen käsittelemisen Django-näkymien kautta tasavertaisesti HTTP-pyyntöjen rinnalla.

Sisältää seuraavat työkalut:

Käyttöönotto

Järjestelmävaatimukset

  • Python 3.6 tai uudempi
  • Django 3.1 tai uudempi
  • ASGI-palvelinohjelmisto (tuotannossa): Daphne, Uvicorn, Hypercorn tms.

Asennus

pip install django-pistoke

Django-projektiasetukset

Lisää Django-projektiasetuksiin:

  • pistoke.Pistoke asennettuihin sovelluksiin (ennen mahdollista staticfiles-sovellusta) ja
  • pistoke.ohjain.WebsocketOhjain asennettuihin ohjaimiin:
# projekti/asetukset.py
...
INSTALLED_APPS = [
  ...
  'pistoke.Pistoke',
  ...
  'django.contrib.staticfiles', # tarvittaessa
  ...
]
MIDDLEWARE = [
  ...
  'pistoke.ohjain.WebsocketOhjain',
]

Tämä järjestys vaaditaan, jotta käsillä olevan paketin toteuttama runserver-komento ohittaa staticfiles-toteutuksen.

Jakeluun sisältyvä django-protoni-yhteensopiva asetuslaajennos (pistoke/asetukset.py) tekee nämä lisäykset automaattisesti.

ASGI-määritys

Luo tai täydennä Django-projektin ASGI-määritystiedosto. Alla kuvattu esimerkkimääritys:

  • alustaa Django-oletuskäsittelijän HTTP-pyynnöille,
  • alustaa Pistoke-käsittelijän Websocket-pyynnöille ja
  • ajaa kunkin saapuvan ASGI-pyynnön oikean käsittelijän läpi, jolloin pyyntö ohjautuu tavanomaisen Django-reititystaulun (ROOT_URLCONF) mukaiselle näkymälle riippumatta sen tyypistä.
# projekti/asgi.py

import os
from django.core.asgi import get_asgi_application
from pistoke.kasittelija import WebsocketKasittelija

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'projekti.asetukset')

kasittelija = {
  'http': get_asgi_application(),
  'websocket': WebsocketKasittelija(),
}

async def application(scope, receive, send):
  return await kasittelija.get(scope['type'])(scope, receive, send)

Ohjaimet

Ohjaimet HTTP-pyynnöllä

Käsillä oleva paketti sisältää tavanomaisen Django/HTTP-ohjaimen pistoke.ohjain.WebsocketOhjain, joka asettaa saapuvalle HTTP-pyynnölle määritteen websocket.

  • tämä sisältää URI-osoitteen, esim. ws://palvelin.org, Websocket-pyyntöjen ohjaamiseksi samalle palvelimelle (http://palvelin.org) kuin kyseinen HTTP-pyyntö;
  • mikäli HTTP-yhteys on salattu (esim. https://palvelin.org), käytetään salattua Websocket-protokollaa: wss://palvelin.org.

Ohjaimet Websocket-pyynnöllä

Tavanomaiset Django-ohjaimet ajetaan Websocket-pyynnölle samalla tavoin kuin HTTP-pyynnölle, pl. HTTP-paluusanoman käsittely.

CSRF-ohjainta muokataan siten, että saapuvan Websocket-pyynnön CSRF-tunnistetta ei yritetä tarkistaa ohjaimessa (sitä ei ole saatavilla ilman POST-dataa). Sen sijaan pyynnölle lisätään metodi tarkista_csrf Websocket-yhteyden kautta vastaanotetun CSRF-datan tarkistamiseksi ajonaikaisesti.

Lisäksi Websocket-pyynnöille käytetään ohjainta, joka tarkistaa web-selaimen asettaman Origin-otsakkeen arvon. Ohjain hyväksyy oletusarvoisesti vain ALLOWED_HOSTS-asetuksen mukaiset pyyntölähteet; muista lähteistä tuleville pyynnöille palautuu hylkäävä paluusanoma (403).

Websocket-protokolla

Kullekin Websocket-pyyntöjä käsittelevälle näkymälle on määriteltävä protokolla, jonka mukaan yhteys luodaan ja katkaistaan ja viestinvälitys tapahtuu.

Näkymä voi joko

  • itse toteuttaa ASGI-määrityksen mukaisen viestinvaihdon ({"type": "websocket.connect"}, {"type": "websocket.send", "text": "..."} jne.),
  • käyttää käsillä olevan paketin tarjoamaa protokollatoteutusta: pistoke.protokolla.WebsocketProtokolla ja sen alaluokat; tai
  • käyttää oletusarvoista protokolla joka otetaan automaattisesti käyttöön.

Protokollaa käytetään sellaisenaan koristeena Websocket-näkymäfunktiolle tai Django-method_decoratorin avulla koristeena näkymäluokan websocket-metodille.

Huomaa, että samaan näkymään liittyvien koristeiden keskinäisellä määritysjärjestyksellä on merkitystä. Kun Websocket-näkymässä käytetään protokollan P lisäksi esimerkiksi Django-pääsynhallintaan liittyvää koristetta D:

  • Mikäli protokolla P on sisempänä (alempana) kuin D, palautuu käyttäjälle tavanomainen HTTP-virhesanoma 401 tai 403, kun oikeudet eivät riitä.
  • Mikäli protokolla P on ulompana (ylempänä) kuin D, avautuu Websocket-yhteys normaalisti myös silloin, kun oikeudet eivät riitä. Yhteys kuitenkin päättyy tällöin heti poikkeukseen.

Huomaa, että käsillä olevan paketin toteuttama automaattinen protokollamääritys muodostaa aina uloimman kerroksen näkymän ympärillä.

Yleiskäyttöisen kantaluokan (WebsocketProtokolla) lisäksi käytettävissä ovat seuraavat, rajatumpiin tilanteisiin soveltuvat protokollat:

  • WebsocketAliProtokolla("protokolla-a", "protokolla-b"): Websocket-aliprotokollamääritys
  • WebsocketJSONProtokolla: JSON-muotoinen viestinvaihto.

Yhteensopivuus: django-pistoke v0.x vs. v1.x

Yhteensopivuuden varmistamiseksi taaksepäin käytetään versioon 1.1 asti seuraavaa automatiikkaa:

  • mikäli Websocket-näkymälle on asetettu jokin edellä mainittu protokolla, sitä käytetään sellaisenaan
  • muussa tapaksessa näkymä koristellaan automaattisesti WebsocketProtokolla-tyyppiseksi.

Versioon 1.2 asti on lisäksi käytettävissä seuraava ohitus edellämainittuun automatiikkaan:

  • mikäli näkymäluokka toteuttaa itse ASGI-viestinvaihdon, tämä voidaan määrittää TyhjaWebsocketProtokolla-koristetta käyttäen.

Websocket-näkymä

Websocket-käsittelijä ohjaa saapuvat pyynnöt Django-näkymille tavanomaisen urlpatterns-reititystaulun mukaisesti. Websocket-pyynnön metodiksi (request.method) asetetaan Websocket. Näkymän toteutus voi olla funktio- tai luokkapohjainen:

  • django.views.generic.View.dispatch ohjaa WS-pyynnön käsiteltäväksi näkymäluokan websocket-metodiin;
  • funktiopohjainen näkymä voi vastata pyynnön metodin perusteella eri tavoin HTTP- ja Websocket-pyyntöihin.

Kummassakin tapauksessa WS-pyynnön käsittelystä vastaavan metodin tai funktion tulee olla tyyppiä async def.

Huomaa, että luokkapohjaisen näkymän tapauksessa Websocket-metodi pitää erikseen sallia näkymäluokalle (HTTP-metodien kuten GET ja POST ohella), jotta tämän tyyppiset pyynnöt sallitaan. Saateluokka pistoke.nakyma:WebsocketNakyma tekee tämän automaattisesti.

Seuraava listaus on esimerkki yhdysrakenteisesta, luokkapohjaisesta näkymätoteutuksesta, joka

  • palauttaa GET-pyynnöllä Django-sivuaihion ja
  • vastaa Websocket-pyyntöön jatkuvana viestivaihtona:
# sovellus/nakyma.py

from django.urls import path
from django.utils.decorators import method_decorator
from django.views import generic

from pistoke.nakyma import WebsocketNakyma
from pistoke.protokolla import WebsocketProtokolla

@method_decorator(WebsocketProtokolla(), name='websocket')
class Nakyma(WebsocketNakyma, generic.TemplateView):
  template_name = 'sovellus/nakyma.html'

  async def websocket(self, request, *args, **kwargs):
    while True:
      syote = await request.receive()
      if isinstance(syote, str):
        await request.send(
          f'Kirjoitit "{syote}".'
        )
      elif isinstance(syote, bytes):
        await request.send(
          f'Kirjoitit "{syote.decode("latin-1")}".'.encode('latin-1')
        )
     # white True
   # async def websocket
 # class Nakyma

urlpatterns = [path('nakyma/', Nakyma.as_view())]

Esimerkki tähän näkymään liittyvästä HTML-aihiosta:

<!-- sovellus/templates/sovellus/nakyma.html -->
<input
  id="syote"
  type="text"
  placeholder="Syötä viesti"
  />
<button
  onclick="websocket.send(document.getElementById('syote').value);"
  >Lähetä</button>
<script>
  websocket = new WebSocket(
    "{{ request.websocket }}{{ request.path }}"
  );
  websocket.onmessage = function (e) { alert(e.data); };
</script>

ASGI-kehityspalvelin

Paketti sisältää runserver-ylläpitokomentototeutuksen (Django-kehityspalvelin), joka periytetään joko:

  • Djangon tavanomaisesta runserver-komennosta tai
  • django.contrib.staticfiles-sovelluksen periyttämästä komennosta, mikäli tämä on asennettu.

Käsillä olevan paketin toteuttama runserver lisää seuraavat vivut edellä mainittuihin toteutuksiin nähden:

  • vipu --wsgi käynnistää tavanomaisen (sisäänrakennetun) WSGI-palvelimen;
  • vipu --asgi käynnistää ASGI-palvelimen (uvicorn-pakettia käyttäen);
  • oletus näistä on ASGI, jos ja vain jos uvicorn on asennettu.

Huomaa, että --asgi-vipu edellyttää Uvicorn-paketin asentamisen ja aiheuttaa poikkeuksen, mikäli tätä ei löydy.

Vakiona runserver-komennon hyväksymä --verbose-vipu hyväksyy, silloin kuin käytössä on --asgi-tila, tavanomaisten numeroarvojensa (0–3) lisäksi myös uvicorn --log-level-vivun hyväksymät tekstimuotoiset määreet:

  • critical: vastaa Django-tasoa 0
  • error
  • warning
  • info: vastaa Django-tasoa 1
  • debug: vastaa Django-tasoa 2
  • trace: vastaa Django-tasoa 3

Palvelinasennus

Palvelinasennukseen sopii hyvin vaikkapa yhdistelmä Nginx + Circus + Uvicorn; ks. https://www.uvicorn.org/deployment/#running-behind-nginx.

Käyttöesimerkkejä

  • Reaaliaikainen keskusteluyhteys kahden käyttäjän välillä: django-juttulaatikko
  • Datan reaaliaikainen, kaksisuuntainen synkronointi Django-palvelimen ja selaimen välillä Websocket-yhteyden välityksellä: django-synkroni
  • Xterm-pääteyhteys Django-sovelluksena: django-xterm
  • Django-ilmoitusten (messages) reaaliaikainen toimitus selaimelle Celery-pinon ja Websocket-yhteyden avulla: django-celery-ilmoitus
  • jQuery-Datatables-liitännäinen Websocket-pohjaiseen tiedonsiirtoon erillisten Ajax-pyyntöjen asemesta: datatables-websocket

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_pistoke-0.9.11.tar.gz (26.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_pistoke-0.9.11-py3-none-any.whl (30.9 kB view details)

Uploaded Python 3

File details

Details for the file django_pistoke-0.9.11.tar.gz.

File metadata

  • Download URL: django_pistoke-0.9.11.tar.gz
  • Upload date:
  • Size: 26.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_pistoke-0.9.11.tar.gz
Algorithm Hash digest
SHA256 2c79e9e08b8f061a600eb09a25993d73b72ba391c8f5618e5d62513b4955e7b8
MD5 9d19a6a2e972d57a6881707209eb43be
BLAKE2b-256 1f20cd9e6e2073be725e3677eddcc0b47589cba0e8bfc974aaf5b25dbd80f208

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_pistoke-0.9.11.tar.gz:

Publisher: ci.yaml on an7oine/django-pistoke

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_pistoke-0.9.11-py3-none-any.whl.

File metadata

File hashes

Hashes for django_pistoke-0.9.11-py3-none-any.whl
Algorithm Hash digest
SHA256 bf3cdc1e7f6321f3cb50fbc410a3378b3637ec1b5eb0b4ceb27bc623f94dface
MD5 e1b3176f775e787d3852a4ba8561eb8d
BLAKE2b-256 6e2bf68dbef0307e8ee8cb5cd7727f34cdc7722c6e474bcf47abf672b793455a

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_pistoke-0.9.11-py3-none-any.whl:

Publisher: ci.yaml on an7oine/django-pistoke

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page