2021/03/15

Walkthrough the basic of Django + ASGI + Daphne

Goal of writing this blog

  • Figure out terminologies in ASGI
    • Say, how to map Django & Daphne into ASGI terminologies
  • Figure out how Daphne interact with Django by using ASGI
    • Say, the code path for Daphne forward a http request to Django application, and the code path for reply
  • Figure out how Websocket implemented in Daphne
    • Understand how Daphne process websocket messages from Browser
    • Understand how Daphne process websocket messages from Django or other applications

      Terminologies in ASGI

      ASGI

      ASGI (Asynchronous Server Gateway Interface) is a spiritual successor to WSGI, intended to provide a standard interface between async-capable Python web servers, frameworks, and applications.

      WSGI

      WSGI provided a standard for synchronous Python apps

      WSGI applications

      WSGI applications are a single, synchronous callable that takes a request and returns a response; this doesn’t allow for long-lived connections, like you get with long-poll HTTP or WebSocket connections.

      ASGI applications[1][2]

  • ASGI application is structured as a single, asynchronous callable with 3 arguments: scope, send, and receive
    Below is an example of a simple asgi application.
    async def example_asgi_application(
      scope: dict,
      receive: callable[[], Awaitable[dict]],
      send: callable[[dict], Awaitable[None]]
    ):
      asgiEvent = await receive()
      ...
      await send(anotherAsgiEvent)
    
  • An application, which lives inside a protocol server, is called once per connection, and handles event messages as they happen, emitting its own event messages back when necessary.
  • Each call of the application callable maps to a single incoming “socket” or connection, and is expected to last the lifetime of that connection plus a little longer if there is cleanup to do.

    (ASGI) Events[1][2]

  • A simple python dict. You can put anything in this dict but it must contain a key type. This data structure is used on send(), and receive() in ASGI applications
    {'type': "some type", .....}
    
  • Events, which are messages sent to the application as things happen on the connection, and messages sent back by the application to be received by the server, including data to be transmitted to the client.

    (ASGI) Connection scope

  • A connection scope, which represents a protocol (asgi) connection to a user and survives until the connection closes.
  • Every connection by a user to an ASGI application results in a call of the application callable to handle that connection entirely. How long this lives, and the information that describes each specific connection, is called the connection scope.
  • scope must be a dict. The key scope["type"] will always be present, and can be used to work out which protocol is incoming. The key scope["asgi"] will also be present as a dictionary containing a scope["asgi"]["version"] key that corresponds to the ASGI version the server implements.

    (ASGI) protocol server

    A protocol server, which terminates sockets and translates them into connections and per-connection event messages.

    ASGI Connections

    The definition of a connection and its lifespan are dictated by the protocol specification in question. For example, with HTTP it is one request, whereas for a WebSocket it is a single WebSocket connection.

    Django / Daphne in ASGI terminologies

  • Django will be a kind of ASGI application
  • Daphne will be the protocol server

    Code path between Django, and Daphne

    Daphne main loop

  • daphne.server.Server.run

    From Daphne to Django

  • twisted.internet.endpoints.TCP4ServerEndpoint.listen
  • daphne.http_protocol.HTTPFactory.doStart
  • daphne.http_protocol.HTTPFactory.startFactory
  • twisted.internet.tcp.Port.doRead
  • daphne.http_protocol.HTTPFactory.buildProtocol
  • twisted.web.http.HTTPChannel.connectionMade
  • twisted.web.http.HTTPChannel.lineReceived
  • daphne.http_protocol.WebRequest
  • daphne.http_protocol.WebRequest.requestReceived
  • daphne.http_protocol.WebRequest.process
  • daphne.server.Server.create_application
  • … django application …

    From Django to Daphne

  • send() from django asgi application
  • daphne.server.Server.handle_reply
  • ….

    How Websocket works

    From Browser to Daphne

  • daphne.http_protocol.WebRequest.process
  • daphne.ws_protocol.WebSocketFactory.buildProtocol
  • daphne.ws_protocol.WebSocketProtocol
  • daphne.ws_protocol.WebSocketProtocol.applicationCreateWorked
  • … handled in asgi applications …

    From Other applications to Browser

  • … WS connection has been setup in above section …
  • … inputQueue from daphne.server.Server.create_application …
  • daphne.ws_protocol.WebSocketProtocol.handle_reply
  • … back to the server & back to the browser …

沒有留言:

張貼留言