Saturday, 29 July 2023

Django Channel

ppt1

WebSocket

WebSocket is a full-duplex (two-way communication) protocol that is used in the same scenario of client-server communication.

It is a stateful protocol, which means the connection between client and server will keep alive until it is terminated by either client or server, after closing the connection by either of the client and server, the connection is terminated from both the end. 

WebSockets do not use the http:// or https:// scheme (because they do not follow the HTTP protocol).

Rather, WebSocket URIs use a new scheme ws: (or wss: for a secure WebSocket). 

The remainder of the URI is the same as an HTTP URI: a host, port, path and any query parameters.

Example:- ws://example.com:8000/ws/chat

Configuring Django Channel

gs1- ppt2

Install using pip

                pip install channels

Uninstall using pip

pip uninstall channels

Adding Channels to Django Project

INSTALLED_APPS = [

    ‘channels’,

    …

]

asgi.py

from channels.routing import ProtocolTypeRouter
application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    # Just HTTP for now. (We can add other protocols later.)
})

settings.py

#WSGI_APPLICATION = 'gs1.wsgi.application'
ASGI_APPLICATION = 'gs1.asgi.application'

gs2- ppt3

Consumers

A consumer is the basic unit of Channels code. Consumers are like Django views.

Creating Consumers:-

  1. SyncConsumer
  2. AsyncConsumer
1. SyncConsumer

A consumer is a subclass of either SyncConsumer or AsyncConsumer.
SyncConsumer will run your code synchronously in a threadpool.
app/consumers.py

2.AsyncConsumer

AsyncConsumer will expect you to write async-capable code.
app/consumers.py

consumers.py

# Topic - Consumer
from channels.consumer import SyncConsumer, AsyncConsumer
class MySyncConsumer(SyncConsumer):
  # This handler is called when client initially opens a connection and is about to finish the WebSocket handshake.
  def websocket_connect(self, event):
    print('Websocket Connected...')

  # This handler is called when data received from Client
  def websocket_receive(self, event):
    print('Messaged Received...')

  # This handler is called when either connection to the client is lost, either from the client closing the connection, the server closing the connection, or loss of the socket.  
  def websocket_disconnect(self, event):
    print('Websocket Disconnected...')

class MyAsyncConsumer(AsyncConsumer):
  # This handler is called when client initially opens a connection and is about to finish the WebSocket handshake.
  async def websocket_connect(self, event):
    print('Websocket Connected...')

  # This handler is called when data received from Client
  async def websocket_receive(self, event):
    print('Messaged Received...')

  # This handler is called when either connection to the client is lost, either from the client closing the connection, the server closing the connection, or loss of the socket.  
  async def websocket_disconnect(self, event):
    print('Websocket Disconnected...')

gs3- ppt4 

Routing

 This is similar to Django’s as_view(), which plays the same role for per-request instances of class-based views.

  • Create routing.py File then write all websocket url patterns inside this file.
  • Open asgi.py file and mentioned your routing.py file

app/routing.py

from django.urls import path
from . import consumers

websocket_urlpatterns = [
  path('ws/sc/', consumers.MySyncConsumer.as_asgi()),
  path('ws/ac/', consumers.MyAsyncConsumer.as_asgi()),
]

gs3/asgi.py

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
import app.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gs3.settings')

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
  'websocket': URLRouter(
    app.routing.websocket_urlpatterns
  )
})

gs4- ppt5

Consumers

A consumer is the basic unit of Channels code. Consumers are like Django views.

Allow you to write synchronous or async code and deals with handoffs and threading for you.

A consumer is a subclass of either SyncConsumer or AsyncConsumer.

  1. SyncConsumer will run your code synchronously in a threadpool.
  2. AsyncConsumer will expect you to write async-capable code.

app/consumers.py

# Topic - More on Consumer and Routing
from channels.consumer import SyncConsumer, AsyncConsumer
from channels.exceptions import StopConsumer

class MySyncConsumer(SyncConsumer):
  # when client(application) send somthing to the server ai event(message) call, handshake ar aga pajanta
  # two way connection enable hoya jaba
  def websocket_connect(self, event):
    print('Websocket Connected...', event)
    # client(application) thaka jata as66a sata accept karar janna
    self.send({
      'type':'websocket.accept',
    })
 
  # when Message received from Client ai event(message) call
  def websocket_receive(self, event):
    print('Message received from Client', event)
    print(event['text'])
    # when server send somthing to the client
    self.send({
      'type':'websocket.send', # for send
      'text':'Message Sent to Client' # what server wants to send
    })

  # when server or client au akjon disconnect kora connection ai event(message) call
  def websocket_disconnect(self, event):
    print('Websocket Disconnected...', event)
    # ata lik66i karon jata error na asa(ata ho66a exception(mana exception handel kor66i))
    raise StopConsumer()

class MyAsyncConsumer(AsyncConsumer):
  async def websocket_connect(self, event):
    print('Websocket Connected...', event)
    await self.send({
      'type':'websocket.accept',
    })
 
  async def websocket_receive(self, event):
    print('Message received from Client', event)
    print(event['text'])
    await self.send({
      'type':'websocket.send',
      'text':'Message Sent to Client'
    })

  async def websocket_disconnect(self, event):
    print('Websocket Disconnected...', event)
    raise StopConsumer()


Real Time Data (syncConsumer vs AsyncConsumer) No ppt gs5


gs6- ppt6

WebSocket

The WebSocket object provides the API for creating and managing a WebSocket connection to a server, as well as for sending and receiving data on the connection.

To construct a WebSocket, use the WebSocket() constructor.

Example:- 

var ws =  new WebSocket('ws://127.0.0.1:8000/ws/sc/’);

WebSocket Properties

onopen 

ws.onopen = function (event) {

      console.log("WebSocket Connection open“, event);

    };

onmessage 

 ws.onmessage = function (event) {

      console.log("WebSocket message received from server”, event);

    };

onerror 

 ws.onerror = function (event) {

      console.log(“WebSocket Error Occurred”, event);

    };

onclose 

 ws.onclose = function (event) {
      console.log(“WebSocket Connection Closed”, event);
    };

Events

open

ws.addEventListener('open', (event) => {
   console.log("WebSocket Connection open");
});

message

ws.addEventListener('message', (event) => {
    console.log(' WebSocket message received from server', event);
});

error

ws.addEventListener(‘error', (event) => {
   console.log(“WebSocket Error Occurred“, event);
});

close

ws.addEventListener(‘close', (event) => {
    console.log('WebSocket connections Closed ', event);
});


Methods
close() – The WebSocket.close() method closes the WebSocket connection or connection attempt, if any. If the connection is already CLOSED, this method does nothing.
Syntax:- ws.close(code, reason)
code - A numeric value indicating the status code explaining why the connection is being closed. If this parameter is not specified, a default value of 1005 is assumed.
reason – A human-readable string explaining why the connection is closing. This string must be no longer than 123 bytes of UTF-8 text (not characters).
Example:- ws.close()



send() – The WebSocket.send() method enqueues the specified data to be transmitted to the server over the WebSocket connection.
If the data can't be sent, the socket is closed automatically. 
The browser will throw an exception if you call send() when the connection is in the CONNECTING state. 
If you call send() when the connection is in the CLOSING or CLOSED states, the browser will silently discard the data.
Syntax:- ws.send(data)
Example:- ws.send(“Hello”)

consumers.py
# Topic - Web API WebSocket - JavaScript
from channels.consumer import SyncConsumer, AsyncConsumer
from channels.exceptions import StopConsumer
from time import sleep
import asyncio

class MySyncConsumer(SyncConsumer):
  def websocket_connect(self, event):
    print('Websocket Connected...', event)
    self.send({
      'type':'websocket.accept',
    })
 
  def websocket_receive(self, event):
    print('Message received from Client', event)
    print(event['text'])
    for i in range(10):
      self.send({
        'type':'websocket.send',
        'text': str(i)
      })
      sleep(1)

  def websocket_disconnect(self, event):
    print('Websocket Disconnected...', event)
    raise StopConsumer()

class MyAsyncConsumer(AsyncConsumer):
  async def websocket_connect(self, event):
    print('Websocket Connected...', event)
    await self.send({
      'type':'websocket.accept',
    })
 
  async def websocket_receive(self, event):
    print('Message received from Client', event)
    print(event['text'])
    for i in range(50):
      await self.send({
        'type':'websocket.send',
        'text': str(i)
      })
      await asyncio.sleep(1)

  async def websocket_disconnect(self, event):
    print('Websocket Disconnected...', event)
    raise StopConsumer()

templates\app\index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <h1>Count Page</h1>

  <script>
    var ws = new WebSocket('ws://127.0.0.1:8000/ws/sc/')

    ws.onopen = function () {
      console.log('Websocket connection open...')
      ws.send('Hi, Message from Client to server...')
    }
    ws.onmessage = function (event) {
      console.log('Message Received from Server...', event)
    }
    ws.onerror = function (event) {
      console.log('Websocket Error Occurred...', event)
    }
    ws.onclose = function (event) {
      console.log('Websocket Connection Closed...', event)
    }

    // ws.addEventListener('open', (event) => {
    //   console.log('Websocket connection open...', event)
    //   ws.send('Hi, Message from Client...')
    // })
    // ws.addEventListener('message', (event) => {
    //   console.log('Message Received from Server...', event)
    // })
    // ws.addEventListener('error', (event) => {
    //   console.log('Websocket Error Occurred...', event)
    // })
    // ws.addEventListener('close', (event) => {
    //   console.log('Websocket Connection Closed...', event)
    // })

  </script>
</body>

</html>


readyState


gs7

Server Side:-

When Sending Data to Client

    Python to String

When Receiving Data from Client

    String to Python

Client Side:-

When Sending Data to Server

    JavaScript Object to String

When Receiving Data from Server

    String to JavaScript Object


Python JSON Lib

In python file used

import json

json.dumps() – This method is used to convert Python dictionary into json string.

json.loads() – This method is used to convert json string into Python dictionary.


JSON
in JavaScript file used
JSON.parse() – This method is used to convert json string into JavaScript object.
JSON.stringify() – This method is used to convert JavaScript object into json string.


gs8 & gs9 - ppt7

Channel Layers

Channel layers allow you to talk between different instances of an application. 

It is for high-level application-to-application communication.

We can communicate with out storing data in database.

Most Important this three things- Channels, Groups, Message

Channels - Channels are a first-in, first out queue with at-most-once delivery semantics. Each channel has a name.

Chanal ar nume jana thakla amra message send korta parbo.

Groups - Multiple channel a data send karar janna Groups used kara hoy.

Multiple chanal a data send kara ka bala hoy broadcast system.

Sending to individual channels isn’t particularly useful - in most cases you’ll want to send to multiple channels/consumers there we use groups.

Multiple channels can be grouped into a group. Each group has a name. A channel can be added or removed from a group by anyone who knows the group name. Using the group name you can also send a message to all channels in the group. 

Groups are a broadcast system that:

  • Allows you to add and remove channel names from named groups, and send message to those named groups.
  • Provides group expiry for clean-up of connections.

Messages – Messages must be a dict. Because these messages are sometimes sent over a network, they need to be serializable.

Redis Channel Layer - It is basically use developing purpose and production(So it is recomended to implement and important)

In-Memory Channel Layer - It is basically use developing purpose not used in production

Redis Channel Layer

Redis works as the communication store for the channel layer. 

In order to use Redis as a channel layer you have to install channels_redis package.

channels_redis is the only official Django-maintained channel layer supported for production use. 


Config Redis Channel Layer

Download and Install Memurai – Redis for Windows alternative

Install channels_redis pip install channels_redis

Open settings.py file then write

CHANNEL_LAYERS = {

    "default": {

        "BACKEND": "channels_redis.core.RedisChannelLayer",

        "CONFIG": {

            "hosts": [("127.0.0.1", 6379)],

        },

    },

}

get_channel_layer() –  This function is used to get default channel layer from a project.

from channels.layers import get_channel_layer

channel_layer – This attribute is used to get default channel layer from a project. This contains a pointer to the channel layer instance, only if you are using consumers.

channel_name – This attribute contains the channel name that will reach the consumer.

Method

send() – It  that takes two arguments: the channel to send on, as a unicode string, and the message to send, as a serializable dict.

Syntax:- send(‘channel_name’, message)

group_send() – It takes two positional arguments; the group to send to, as a unicode string, and the message to send, as a serializable dict. It may raise MessageTooLarge but cannot raise ChannelFull.

Syntax:- group_send(‘group_name’, message)

group_add() – This is used to add a channel to a new or existing group. If the channel is already in the group, the function should return normally.

Syntax:- group_add(‘group_name’, ‘channel_name’)

Example:- group_add(‘friends’, self.channel_name)

group_discard() – This is used to remove channel from the group if it is in it, and does nothing otherwise.

Syntax:- group_discard(‘group_name’, ‘channel_name’)

Example:- group_discard(‘friends’, self.channel_name)

Exception

MessageTooLarge, the exception raised when a send operation fails because the encoded message is over the layer’s size limit.

ChannelFull, the exception raised when a send operation fails because the destination channel is over capacity.

gs10 - ppt8

Database

The Django ORM is a synchronous piece of code, and so if you want to access it from asynchronous code you need to do special handling to make sure its connections are closed properly.

If you are writing asynchronous code, however, you will need to call database methods in a safe, synchronous context, using database_sync_to_async.

database_sync_to_async
Write your ORM queries in a separate function or method, and then call it with database_sync_to_async.
Example:- 
from channels.db import database_sync_to_async
async def websocket_connect(self):
    self.username = await database_sync_to_async(self.get_name)()

def get_name(self):
    return User.objects.all()[0].name

gs11- ppt9

Authentication

asgi.py

from channels.auth import AuthMiddlewareStack

application = ProtocolTypeRouter({

  'http': get_asgi_application(),

  'websocket': AuthMiddlewareStack(

    URLRouter(

      app.routing.websocket_urlpatterns

    ) )})

To access the user, just use self.scope["user"] in your consumer 

gs12 to gs16 - ppt10


No comments:

Post a Comment

Server

 Python manage.py runserver ===> It is used for Development server, it has good feature auto restart when we are add or edit smoothing d...