Using channels outside consumers.py but function in consumers not firing - django-channels

I am trying to send a message to django consumers.py from one user to another after a user logs in. However, the chat_message function doesn't seem to be firing with the code I wrote in the log in function in views.py as "ccc" in not printing on the server side. New to Django Channels here. Would appreciate any input to this problem of mine.
consumers.py
class OnlineFriends(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope["user"]
print(self.room_name)
print(self.channel_layer)
self.room_group_name = 'chat_' + str(self.room_name)
print(self.room_group_name)
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
print("aa")
message = self.channel_name.split("-")
await self.send(text_data=json.dumps({
'message': message
}))
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
async def chat_message(self, event):
print("ccc")
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
users.views.py *Updated
class Login(View):
form_class = LoginForm
template = 'login.html'
def get(self, request):
form=self.form_class(None)
return render(request, self.template, {'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
user.onlinestatus = True
user.save()
for obj in user.friends.all():
print( user.friends.all())
if obj.onlinestatus == True:
print("obj: "+ str(obj.username))
channel_layer = get_channel_layer()
print("channel_layer: "+ str(channel_layer))
room_name = "chat_" + str(obj.username)
print("room_name: "+ str(room_name))
print(obj.channel_name)
async_to_sync(channel_layer.group_send(
room_name, {
"type": "chat.message",
"message": room_name,
}))
return redirect('home')
else:
return HttpResponse("No such user.")
else:
return render(request, 'login.html', {'form':form})
traceback updated
WebSocket HANDSHAKING /friendslist/ [127.0.0.1:49751] ****loading home page on browser****
foonghanyao ****output from consumers.OnlineFriends.connect****
RedisChannelLayer(hosts=[{'address': ('127.0.0.1', 6379)}])
chat_foonghanyao
WebSocket CONNECT /friendslist/ [127.0.0.1:49751]
HTTP GET /static/songs/images/favicon.png 200 [0.02, 127.0.0.1:61225]
<QuerySet [<User: foonghanyao>]> ****output from Login class in views.py****
obj: foonghanyao
channel_layer: RedisChannelLayer(hosts=[{'address': ('127.0.0.1', 6379)}])
room_name: chat_foonghanyao
specific.45d45ec67e0a4282b2066d67847e4bab!8ab6617c8be94d0dabefadf636ba886e
HTTP POST /accounts/login/ 302 [0.88, 127.0.0.1:60752]
<QuerySet [<Tag: apple>, <Tag: bee>]>
HTTP GET /home/ 200 [0.16, 127.0.0.1:60752]
WebSocket DISCONNECT /friendslist/ [127.0.0.1:55762] ****Disconnecting from websockets in login page****
aa
WebSocket HANDSHAKING /friendslist/ [127.0.0.1:58978] ****new page loading after being redirected following log in****
brandonfoong
RedisChannelLayer(hosts=[{'address': ('127.0.0.1', 6379)}])
chat_brandonfoong
WebSocket CONNECT /friendslist/ [127.0.0.1:58978]
sync.routing.py updated
websocket_urlpatterns = [
re_path(r"^friendslist/$", consumers.OnlineFriends.as_asgi(), name='friendslist'),
]
mainapp.asgi.py updated
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "music.settings")
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
sync.routing.websocket_urlpatterns,
)
),
})

Related

Token is not recognized after authentication in FastAPI

I am creating a basic Authentication register/login with FastAPI. However, after the user has succesfully registered and logged in, the token does not get recognized. It works fine using the "/docs" through Swagger UI, but not from the main app.
Here is my code: main.py
import uvicorn
from fastapi import Depends, HTTPException
from auth import AuthHandler
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
auth_handler = AuthHandler()
users = []
#app.get('/', response_class=HTMLResponse)
def get_register_form(request: Request):
return templates.TemplateResponse("register.html", {"request": request})
#app.post('/', response_class=HTMLResponse)
def register(request: Request, username: str = Form(...), password: str = Form(...)):
if len(users) != 0:
for x in users:
if x['username'] == username:
print('Username is taken!')
raise HTTPException(status_code=400, detail='Username is taken!')
hashed_password = auth_handler.get_password_hash(password)
users.append({
'username': username,
'password': hashed_password
})
print('User:', username, 'registered!')
return templates.TemplateResponse("success.html", {"request": request})
#app.get('/login', response_class=HTMLResponse)
def get_login_form(request: Request):
return templates.TemplateResponse("login.html", {"request": request})
#app.post('/login')
def login(request: Request, username: str = Form(...), password: str = Form(...)):
user = None
for x in users:
if x['username'] == username:
user = x
break
if (user is None) or (not auth_handler.verify_password(password, user['password'])):
print('Invalid username and/or password!')
raise HTTPException(status_code=401, detail='Invalid username and/or password!')
token = auth_handler.encode_token(user['username'])
return {'token': token}
#app.get('/protected')
def protected(username=Depends(auth_handler.auth_wrapper)):
return {'name': username}
if __name__ == '__main__':
uvicorn.run(app)
Here is my code: auth.py
import jwt
from fastapi import HTTPException, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from passlib.context import CryptContext
from datetime import datetime, timedelta
class AuthHandler():
security = HTTPBearer()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
secret = 'SECRET'
def get_password_hash(self, password):
return self.pwd_context.hash(password)
def verify_password(self, plain_password, hashed_password):
return self.pwd_context.verify(plain_password, hashed_password)
def encode_token(self, user_id):
payload = {
'exp': datetime.utcnow() + timedelta(days=0, minutes=5),
'iat': datetime.utcnow(),
'sub': user_id
}
return jwt.encode(
payload,
self.secret,
algorithm='HS256'
)
def decode_token(self, token):
try:
payload = jwt.decode(token, self.secret, algorithms=['HS256'])
return payload['sub']
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail='Signature has expired')
except jwt.InvalidTokenError as e:
raise HTTPException(status_code=401, detail='Invalid token')
def auth_wrapper(self, auth: HTTPAuthorizationCredentials = Security(security)):
return self.decode_token(auth.credentials)
Here is my forms.html: register.html and login.html are the same.
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="../static/styles.css">
<title>Document</title>
</head>
<body>
<div id="form">
<form method="post">
<h3>Login</h3>
<label for="username">Username:</label><br>
<input type="text" name="username" id="username"><br>
<label for="password">Password:</label><br>
<input type="text" name="password" id="password"><br><br>
<input type="submit" value="Submit" id="sub">
</form>
</div>
</body>
</html>
The error I get when going to 127.0.0.1/protected is:
{"detail":"Not authenticated"}
How can I fix this, so that it recognizes the token from the user just like in docs?
I found a solution on the advise from #MatsLindh, I also simplified a lot the code, imports, etc.
You will obviously still need to have the html files with the form and fields you'll need. In my case I just added the email and password.
Please note that this is not "best practice" especially inserting in the same table of the database the password even it it's hashed.
import uvicorn
import sqlite3
import jwt
from datetime import datetime, timedelta
from fastapi import FastAPI, Form, HTTPException, Cookie, Request, Depends
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from passlib.context import CryptContext
connection = sqlite3.connect("users.db", check_same_thread=False)
cursor = connection.cursor()
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
class AuthHandler:
secret = 'SECRET' # I can put any key I want, it's going to be used to encrypt and decrypt
bcrypt_obj = CryptContext(schemes=["bcrypt"], deprecated="auto")
def get_password_hash(self, password):
return self.bcrypt_obj.hash(password)
def verify_password(self, plain_password, hashed_password):
return self.bcrypt_obj.verify(plain_password, hashed_password)
def encode_token(self, user_id):
payload = {
'exp': datetime.utcnow() + timedelta(days=0, minutes=5),
'iat': datetime.utcnow(),
'sub': user_id
}
return jwt.encode(
payload,
self.secret,
algorithm='HS256'
)
def decode_token(self, token):
try:
payload = jwt.decode(token, self.secret, algorithms=['HS256'])
return payload['sub']
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail='Signature has expired')
except jwt.InvalidTokenError as e:
raise HTTPException(status_code=401, detail='Invalid token')
def grant_access(self, token, users_db):
for x in users_db:
if x['email'] == self.decode_token(token):
return True
else:
return False
auth_handler = AuthHandler()
#app.get('/', response_class=HTMLResponse)
def get_register_form(request: Request):
return templates.TemplateResponse("register.html", {"request": request})
#app.post('/', response_class=HTMLResponse)
def register(email: str = Form(...), password: str = Form(...)):
cursor.execute("select * from users where email=:e", {"e": email})
user_with_same_email_list = cursor.fetchall()
if len(user_with_same_email_list) != 0:
print(user_with_same_email_list)
print('Email already registered!')
raise HTTPException(status_code=400, detail='Email already registered!')
else:
hashed_password = auth_handler.get_password_hash(password)
sqlite_insert_query = "INSERT INTO users (user_id, username, email, hashed_password, eoa) VALUES " \
"(1,'','" + email + "','" + hashed_password + "','')"
cursor.execute(sqlite_insert_query)
connection.commit()
print('User with email:', email, 'registered!')
response = RedirectResponse(url="/login")
response.status_code = 302
return response
#app.get('/login', response_class=HTMLResponse)
def get_login_form(request: Request):
return templates.TemplateResponse("login.html", {"request": request})
#app.post('/login')
def login(email: str = Form(...), password: str = Form(...)):
cursor.execute("select * from users where email=:e", {"e": email})
user_with_same_email_list = cursor.fetchall()
if len(user_with_same_email_list) == 0:
print('No user with this email!')
raise HTTPException(status_code=400, detail='No user with this email!')
elif (email is None) or (not auth_handler.verify_password(password, user_with_same_email_list[0][3])):
print('Invalid email and/or password!')
raise HTTPException(status_code=401, detail='Invalid email and/or password!')
else:
token = auth_handler.encode_token(email)
response = RedirectResponse(url="/check_cookie")
response.status_code = 302
response.set_cookie(key="Authorization", value=token, secure=True, httponly=True)
return response
#app.get("/check_cookie")
async def check_cookie(Authorization: str | None = Cookie(None)):
if Authorization:
email = auth_handler.decode_token(Authorization)
cursor.execute("select * from users where email=:e", {"e": email})
user_with_same_email_list = cursor.fetchall()
if len(user_with_same_email_list) == 0:
print('Invalid token')
raise HTTPException(status_code=401, detail='Invalid token')
else:
print('Access granted!')
response = RedirectResponse(url="/protected")
response.status_code = 302
return response
else:
print("No token found")
raise HTTPException(status_code=401, detail='No token found')
#app.get('/protected', response_class=HTMLResponse)
async def protected(request: Request, email=Depends(check_cookie)):
return templates.TemplateResponse("logged_in.html", {"request": request})
#app.get("/logged_out", response_class=HTMLResponse)
async def logged_out(request: Request):
return templates.TemplateResponse("logged_out.html", {"request": request})
#app.get("/logout")
async def route_logout_and_remove_cookie():
response = RedirectResponse(url="/logged_out")
response.delete_cookie("Authorization", domain="127.0.0.1")
return response
if __name__ == '__main__':
uvicorn.run(app)

Sign In with Apple, decoded Apple response

I've implemented 'Sign In with Apple' from this source (https://gist.github.com/aamishbaloch/2f0e5d94055e1c29c0585d2f79a8634e?permalink_comment_id=3328115) taking into account the comments of NipunShaji and aj3sh. But it doesn't works because Apple sends incomplete data: I recieve
decoded = {'iss': 'https://appleid.apple.com', 'aud': '...', 'exp': 1664463442, 'iat': 1664377042, 'sub': '.....', 'at_hash': '....', 'auth_time': 1664377030, 'nonce_supported': True}
without email data).
According to the Apple's documentation typical response contains email: https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple.
What I've missed?
Additional code:
view.py file:
class AppleSocialAuthView(GenericAPIView):
serializer_class = AppleSocialAuthSerializer
permission_classes = [AllowAny]
def post(self, request):
"""
POST with "auth_token"
Send an access token as from facebook to get user information
"""
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
data = (serializer.validated_data['auth_token'])
return Response(data, status=status.HTTP_200_OK)
serializer.py file:
class Apple(BaseOAuth2):
"""apple authentication backend"""
name = 'apple'
ACCESS_TOKEN_URL = 'https://appleid.apple.com/auth/token'
SCOPE_SEPARATOR = ','
ID_KEY = 'uid'
#handle_http_errors
def do_auth(self, access_token, *args, **kwargs):
"""
Finish the auth process once the access_token was retrieved
Get the email from ID token received from apple
"""
response_data = {}
client_id, client_secret = self.get_key_and_secret()
headers = {'content-type': "application/x-www-form-urlencoded"}
data = {
'client_id': client_id,
'client_secret': client_secret,
'code': access_token,
'grant_type': 'authorization_code',
'redirect_uri': settings.SOCIAL_AUTH_APPLE_REDIRECT_URL
}
res = requests.post(Apple.ACCESS_TOKEN_URL, data=data, headers=headers)
response_dict = res.json()
id_token = response_dict.get('id_token', None)
if id_token:
decoded = jwt.decode(id_token, '', options={"verify_signature": False}, verify=False)
print(decoded)
response_data.update({'email': decoded['email']}) if 'email' in decoded else None
response_data.update({'uid': decoded['sub']}) if 'sub' in decoded else None
response = kwargs.get('response') or {}
response.update(response_data)
response.update({'access_token': access_token}) if 'access_token' not in response else None
kwargs.update({'response': response, 'backend': self})
return self.strategy.authenticate(*args, **kwargs)
def get_user_details(self, response):
email = response.get('email', None)
details = {
'email': email,
}
return details
def get_key_and_secret(self):
headers = {
'kid': settings.SOCIAL_AUTH_APPLE_KEY_ID,
'alg': 'ES256',
}
payload = {
'iss': settings.SOCIAL_AUTH_APPLE_TEAM_ID,
'iat': int(time.time()),
'exp': int(time.time()) + 15552000,
'aud': 'https://appleid.apple.com',
'sub': settings.SOCIAL_AUTH_APPLE_CLIENT_ID,
}
client_secret = jwt.encode(
payload,
settings.SOCIAL_AUTH_APPLE_CLIENT_SECRET,
# algorithm='ES256',
headers=headers
)
return settings.SOCIAL_AUTH_APPLE_CLIENT_ID, client_secret
class AppleSocialAuthSerializer(serializers.Serializer):
auth_token = serializers.CharField()
def validate_auth_token(self, auth_token):
user_data = Apple()
user_data = user_data.do_auth(auth_token)
try:
email = user_data['email']
name = user_data['name']
provider = 'apple'
return register_social_user(
provider=provider, email=email, name=name)
except Exception as identifier:
raise serializers.ValidationError(
'The token is invalid or expired. Please login again.'
)
When I test this proces on my Mac (logging into web app), the end result is that I can see on my Mac, preferences -> Apple ID, that I'm using SSO for this application.
So it looks like Apple validated this Web App.
If they do send email, only first time the user is logging in to Web App, how Web App should know next time what user to log in?
There is no single parameter that would identify the user in decoded response (like some ID, which would also appear in their first response?
Best Regards, Marek

Why Twitter is not making a get request to my server while registering webhook using endpoint?

I'm using twitter account activity api for registering a webhook using autohook wrapper library.
As per the docs the post requests to endpoint (https://api.twitter.com/1.1/account_activity/all/:env_name/webhooks.json) should trigger a get request from my server. that will return a crc based on a crc token and my consumer key.
While im getting code 215 and unable to connect during crc request error message again and again.
Im not sure why get request is not exceuting. here is my server and client code.
server.py
#app.route("/webhook/twitter", methods=["GET", "POST"])
def callback() -> json:
if flask.request.method == "GET" or flask.request.method == "PUT":
print(flask.request.args.get("crc_token"))
hash_digest = hmac.digest(
key=os.environ["consumer_secret"].encode("utf-8"),
msg=flask.request.args.get("crc_token").encode("utf-8"),
digest=hashlib.sha256,
)
return {
"response_token": "sha256="
+ base64.b64encode(hash_digest).decode("ascii")
}
elif flask.request.method == "POST":
data = flask.request.get_json()
logging.info(data)
return {"code": 200}
# Once the code running on the server.
# You can register and subscribe to events from your local machine.
#app.route("/",methods=["GET"])
def callbackget():
return "in GEt"
if __name__ == "__main__":
app.run(debug=True, port=443,ssl_context=context)
client side autohook wrapper:
const { Autohook } = require('twitter-autohook');
(async ƛ => {
const webhook = new Autohook(
{
token:"1218220064610099203-8CnN6G3edmIRGdDpLcR7Bao88mMCUg",
token_secret:"JEavuf3PZmSsXWhmSdtNarFPNBp6BsZzMrLpkEMASkJX5",
consumer_key:"6n7U6KDXxouXDcsLMxdiSKwZ9",
consumer_secret:"o2aKE9TivbTwchJXXZ4XaTyAwtCgtoRO35a9PgdaqMLUBRfv49",
env:"enc"
}
);
// Removes existing webhooks
await webhook.removeWebhooks();
// Listens to incoming activity
webhook.on('event', event => console.log('Something happened:', event));
// Starts a server and adds a new webhook
await webhook.start("https://127.0.0.1:443/webhook/twitter");
// Subscribes to a user's activity
await webhook.subscribe({oauth_token, oauth_token_secret});
})();

call django consumer using signals

Is there a way to call a consumer by post_save signal?
that's my consumer and i don't know how to call it, what should i put in the parameters of it?
in models:
#receiver(post_save, sender=Message)
def SendMessage(sender, instance, **kwargs):
consumer = ChatConsumer(room_id=instance.receiver.pk)
ChatConsumer.receive(self=consumer, pk=instance.pk)
my consumer:
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_id = self.scope['url_route']['kwargs']['pk']
self.room_group_name = 'chat_%s' % self.room_id
# Join room
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from web socket
async def receive(self, pk):
pk = pk
print(pk)
self.room_id = pk
self.room_group_name = 'chat_%s' % self.room_id
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'pk': pk,
}
)
# Receive message from room group
async def chat_message(self, event):
pk = event['pk']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'pk': pk
}))
when i try this, i get this error:
object.init() takes exactly one argument (the instance to initialize)
if anyone still looking, I solved it here's my consumers full code
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async, async_to_sync
from django.db.models.signals import *
from django.dispatch import receiver
from .models import Message
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_id = self.scope['url_route']['kwargs']['pk']
self.room_group_name = 'chat_%s' % self.room_id
# Join room
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from room group
async def chat_message(self, event):
message_pk = event["message_pk"]
print("received" + str(message_pk))
# Send message to WebSocket
await self.send(text_data=json.dumps({'pk': message_pk}))
#receiver(post_save, sender=Message)
def SendMessage(sender, instance, **kwargs):
pk = instance.receiver.pk
message_pk = instance.pk
room_group_name = 'chat_%s' % pk
async_to_sync(channel_layer.group_send)(
room_group_name,
{'type': 'chat_message','message_pk': message_pk,})

Django channels: messages are duplicated in a one channel

I'm going through official Django Channels tutorial and get stacked with the same problem as this guy:
Django Channels group send only sends the message to last channel
So, I have a bunch of standard files:
# asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
# routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
print('def receive from websocket')
text_data_json = json.loads(text_data)
message = text_data_json['message']
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
async def chat_message(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
And a part of settings.py
ASGI_APPLICATION = 'mysite.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
This is a simple chat room. I open two tabs in the same browser, text "Hello" in the first one and get two "Hello" inside of the second tab with zero "Hello" in the first tab.
UPDATE!!!
I made some experiments and I think that consumers functions work correctly (I logged channel_name parameter during the messages sending and inside def receive() I can see exactly that channel_name, from which I sent a message, and at the same time inside def chat_message() I can see all channels). So, the problem should be in js?
<textarea id="chat-log" cols="100" rows="20"></textarea><br>
<input id="chat-message-input" type="text" size="100"><br>
<input id="chat-message-submit" type="button" value="Send">
{{ room_name|json_script:"room-name" }}
<script>
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/'
+ roomName
+ '/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.message + '\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
</script>
The problem is solved. In my case it was with django environment. I used the common one, which I also use for other projects. Maybe the reason of issue was in conflict between some installs. I've created a new environment, installed django and channels and everything is working now.
I faced this issue too. I think this is a bug in channels=3.0.0
I upgraded to channels=3.0.4 and it is working now!

Resources