├── backend ├── __init__.py ├── chat │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── apps.py │ ├── routing.py │ ├── urls.py │ ├── views.py │ ├── consumers.py │ └── templates │ │ ├── index.html │ │ └── chatroom.html ├── urls.py ├── wsgi.py ├── asgi.py └── settings.py ├── requirements.txt ├── Makefile ├── manage.py ├── contrib └── env_gen.py ├── .gitignore ├── README.md └── passo-a-passo.md /backend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/chat/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/chat/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/chat/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ChatConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'backend.chat' 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | autopep8==2.0.2 2 | channels==4.0.0 3 | daphne==4.0.0 4 | Django==4.2 5 | djhtml==3.0.6 6 | isort==5.12.0 7 | websockets==11.0.1 8 | django-extensions==3.2.1 9 | python-decouple==3.8 10 | -------------------------------------------------------------------------------- /backend/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import include, path 3 | 4 | urlpatterns = [ 5 | path('', include('backend.chat.urls')), 6 | path('admin/', admin.site.urls), 7 | ] 8 | -------------------------------------------------------------------------------- /backend/chat/routing.py: -------------------------------------------------------------------------------- 1 | from django.urls import re_path 2 | 3 | from . import consumers 4 | 5 | websocket_urlpatterns = [ 6 | re_path(r'ws/chat/(?P\w+)/$', consumers.ChatRoomConsumer.as_asgi()), 7 | ] 8 | -------------------------------------------------------------------------------- /backend/chat/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | path('', views.index, name='index'), 7 | path('chat//', views.room, name='room'), 8 | ] 9 | -------------------------------------------------------------------------------- /backend/chat/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | 4 | def index(request): 5 | return render(request, 'index.html') 6 | 7 | 8 | def room(request, room_name): 9 | return render(request, 'chatroom.html', {'room_name': room_name}) 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | indenter: 2 | find backend -name "*.html" | xargs djhtml 3 | 4 | autopep8: 5 | find backend -name "*.py" | xargs autopep8 --max-line-length 120 --in-place 6 | 7 | isort: 8 | isort -m 3 * --skip migrations --skip .venv 9 | 10 | lint: autopep8 isort indenter -------------------------------------------------------------------------------- /backend/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for backend project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /backend/asgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import django 4 | from channels.auth import AuthMiddlewareStack 5 | from channels.routing import ProtocolTypeRouter, URLRouter 6 | from channels.security.websocket import AllowedHostsOriginValidator 7 | from django.core.asgi import get_asgi_application 8 | 9 | import backend.chat.routing 10 | 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") 12 | 13 | django.setup() 14 | 15 | application = ProtocolTypeRouter( 16 | { 17 | "http": get_asgi_application(), 18 | "websocket": AllowedHostsOriginValidator( 19 | AuthMiddlewareStack(URLRouter(backend.chat.routing.websocket_urlpatterns)) 20 | ), 21 | } 22 | ) 23 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /contrib/env_gen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Python SECRET_KEY generator. 3 | """ 4 | import random 5 | 6 | chars = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!?@#$%^&*()" 7 | size = 50 8 | secret_key = "".join(random.sample(chars, size)) 9 | 10 | chars = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!?@#$%_" 11 | size = 20 12 | password = "".join(random.sample(chars, size)) 13 | 14 | CONFIG_STRING = """ 15 | DEBUG=True 16 | SECRET_KEY=%s 17 | ALLOWED_HOSTS=127.0.0.1,.localhost,0.0.0.0 18 | 19 | #DATABASE_URL=postgres://USER:PASSWORD@HOST:PORT/NAME 20 | #POSTGRES_DB= 21 | #POSTGRES_USER= 22 | #POSTGRES_PASSWORD=%s 23 | #DB_HOST=localhost 24 | 25 | #DEFAULT_FROM_EMAIL= 26 | #EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend 27 | #EMAIL_HOST=localhost 28 | #EMAIL_PORT= 29 | #EMAIL_HOST_USER= 30 | #EMAIL_HOST_PASSWORD= 31 | #EMAIL_USE_TLS=True 32 | """.strip() % (secret_key, password) 33 | 34 | # Writing our configuration file to '.env' 35 | with open('.env', 'w') as configfile: 36 | configfile.write(CONFIG_STRING) 37 | 38 | print('Success!') 39 | print('Type: cat .env') 40 | -------------------------------------------------------------------------------- /backend/chat/consumers.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from channels.generic.websocket import AsyncWebsocketConsumer 4 | 5 | 6 | class ChatRoomConsumer(AsyncWebsocketConsumer): 7 | async def connect(self): 8 | # Pega o nome da sala (pode ser um slug também) 9 | self.room_name = self.scope['url_route']['kwargs']['room_name'] 10 | self.room_group_name = 'chat_%s' % self.room_name 11 | 12 | # Entra no grupo 13 | await self.channel_layer.group_add(self.room_group_name, self.channel_name) 14 | 15 | # Aceita a conexão 16 | await self.accept() 17 | 18 | async def disconnect(self, close_code): 19 | # Sai do group 20 | await self.channel_layer.group_discard(self.room_group_name, self.channel_name) 21 | 22 | async def receive(self, text_data): 23 | text_data_json = json.loads(text_data) 24 | message = text_data_json['message'] 25 | 26 | # Envia mensagem para o grupo 27 | await self.channel_layer.group_send( 28 | self.room_group_name, {'type': 'chat_message', 'message': message} 29 | ) 30 | 31 | async def chat_message(self, event): 32 | # É um evento. 33 | # Recebe mensagem do grupo 34 | message = event['message'] 35 | 36 | # Envia mensagem para o websocket 37 | await self.send(text_data=json.dumps({'message': message})) 38 | -------------------------------------------------------------------------------- /backend/chat/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Django Channels 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 |

Boas-vindas ao Django Channels

29 |

Escolha uma sala.

30 |
31 |
32 | 33 |
34 | 35 | 36 |
37 |
38 |
39 | Sala Green 40 |
41 |
42 |
43 | 44 | 45 |
46 |
47 |
48 | Sala Blue 49 |
50 |
51 |
52 | 53 |
54 | 55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .DS_Store 132 | 133 | media/ 134 | staticfiles/ 135 | .idea 136 | .ipynb_checkpoints/ 137 | .vscode 138 | *.cast 139 | -------------------------------------------------------------------------------- /backend/chat/templates/chatroom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | Django Channels | Sala 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 | 22 |
23 | 27 |
32 |
33 |
34 |
39 |
40 | 46 |
47 |
48 |
49 |
50 | 51 | {{ request.user.username|json_script:"user_username" }} 52 | {{ room_name|json_script:"room-name" }} 53 | 54 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /backend/settings.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Django settings for backend project. 3 | 4 | Generated by 'django-admin startproject' using Django 4.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/4.2/ref/settings/ 11 | ''' 12 | from pathlib import Path 13 | 14 | from decouple import Csv, config 15 | 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | # SECURITY WARNING: keep the secret key used in production secret! 19 | SECRET_KEY = config('SECRET_KEY') 20 | 21 | # SECURITY WARNING: don't run with debug turned on in production! 22 | DEBUG = config('DEBUG', default=False, cast=bool) 23 | 24 | ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv()) 25 | 26 | 27 | INSTALLED_APPS = [ 28 | 'django.contrib.admin', 29 | 'django.contrib.auth', 30 | 'django.contrib.contenttypes', 31 | 'django.contrib.sessions', 32 | 'django.contrib.messages', 33 | 'daphne', 34 | 'django.contrib.staticfiles', 35 | 'channels', 36 | 'backend.chat', 37 | ] 38 | 39 | MIDDLEWARE = [ 40 | 'django.middleware.security.SecurityMiddleware', 41 | 'django.contrib.sessions.middleware.SessionMiddleware', 42 | 'django.middleware.common.CommonMiddleware', 43 | 'django.middleware.csrf.CsrfViewMiddleware', 44 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 45 | 'django.contrib.messages.middleware.MessageMiddleware', 46 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 47 | ] 48 | 49 | ROOT_URLCONF = 'backend.urls' 50 | 51 | TEMPLATES = [ 52 | { 53 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 54 | 'DIRS': [], 55 | 'APP_DIRS': True, 56 | 'OPTIONS': { 57 | 'context_processors': [ 58 | 'django.template.context_processors.debug', 59 | 'django.template.context_processors.request', 60 | 'django.contrib.auth.context_processors.auth', 61 | 'django.contrib.messages.context_processors.messages', 62 | ], 63 | }, 64 | }, 65 | ] 66 | 67 | ASGI_APPLICATION = 'backend.asgi.application' 68 | WSGI_APPLICATION = 'backend.wsgi.application' 69 | 70 | 71 | # Database 72 | # https://docs.djangoproject.com/en/4.2/ref/settings/#databases 73 | 74 | DATABASES = { 75 | 'default': { 76 | 'ENGINE': 'django.db.backends.sqlite3', 77 | 'NAME': BASE_DIR / 'db.sqlite3', 78 | } 79 | } 80 | 81 | 82 | # Password validation 83 | # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators 84 | 85 | AUTH_PASSWORD_VALIDATORS = [ 86 | { 87 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 88 | }, 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 97 | }, 98 | ] 99 | 100 | 101 | # Internationalization 102 | # https://docs.djangoproject.com/en/4.2/topics/i18n/ 103 | 104 | LANGUAGE_CODE = 'en-us' 105 | 106 | TIME_ZONE = 'UTC' 107 | 108 | USE_I18N = True 109 | 110 | USE_TZ = True 111 | 112 | 113 | # Static files (CSS, JavaScript, Images) 114 | # https://docs.djangoproject.com/en/4.2/howto/static-files/ 115 | 116 | STATIC_URL = 'static/' 117 | STATIC_ROOT = BASE_DIR.joinpath('staticfiles') 118 | 119 | # Default primary key field type 120 | # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field 121 | 122 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 123 | 124 | CHANNEL_LAYERS = {'default': {'BACKEND': 'channels.layers.InMemoryChannelLayer'}} 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # channels 2 | 3 | Sistema de chat feito com django-channels. 4 | 5 | ## Instalação 6 | 7 | ### Este projeto foi feito com: 8 | 9 | * [Python 3.10.6](https://www.python.org/) 10 | * [Django 4.2](https://www.djangoproject.com/) 11 | * [Django channels](https://channels.readthedocs.io/en/stable/) 12 | 13 | ### Como rodar o projeto? 14 | 15 | * Clone esse repositório. 16 | * Crie um virtualenv com Python 3. 17 | * Ative o virtualenv. 18 | * Instale as dependências. 19 | * Rode as migrações. 20 | 21 | ``` 22 | git clone https://github.com/rg3915/django-channels-tutorial.git 23 | cd django-channels-tutorial 24 | 25 | python -m venv .venv 26 | source .venv/bin/activate 27 | 28 | pip install -r requirements.txt 29 | 30 | python contrib/env_gen.py 31 | 32 | python manage.py migrate 33 | python manage.py createsuperuser --username="admin" --email="" 34 | ``` 35 | 36 | Rodando aplicação 37 | 38 | ``` 39 | uvicorn backend.asgi:application --reload 40 | ``` 41 | 42 | As salas são criadas dinamicamente na url. 43 | 44 | Navegue em http://localhost:8000/chat/sala1 45 | 46 | 47 | ## Tutoriais 48 | 49 | https://www.youtube.com/watch?v=cw8-KFVXpTE 50 | 51 | https://www.youtube.com/watch?v=jsxFEONN_yo 52 | 53 | https://www.youtube.com/watch?v=DqCqFRYO4W8 54 | 55 | https://www.youtube.com/watch?v=SF1k_Twr9cg 56 | 57 | https://stackoverflow.com/questions/73755881/djangorestframework-does-not-work-when-django-channel-is-applied 58 | 59 | 60 | ```python 61 | # settings.py 62 | WSGI_APPLICATION = "core.wsgi.application" 63 | ASGI_APPLICATION = "core.asgi.application" 64 | 65 | CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}} 66 | ``` 67 | 68 | Configurando [CHANNEL_LAYERS](https://channels.readthedocs.io/en/stable/topics/channel_layers.html) 69 | 70 | ```python 71 | # asgi.py 72 | import os 73 | 74 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") 75 | import django 76 | 77 | django.setup() 78 | import chat.routing 79 | from channels.auth import AuthMiddlewareStack 80 | from channels.routing import ProtocolTypeRouter, URLRouter 81 | from channels.security.websocket import AllowedHostsOriginValidator 82 | from django.core.asgi import get_asgi_application 83 | 84 | application = ProtocolTypeRouter( 85 | { 86 | "http": get_asgi_application(), 87 | "websocket": AllowedHostsOriginValidator( 88 | AuthMiddlewareStack(URLRouter(chat.routing.websocket_urlpatterns)) 89 | ), 90 | } 91 | ) 92 | ``` 93 | 94 | `chat/routing.py` 95 | 96 | É o `url.py` do channels, vai dar match no endereço do websocket e fazer o dispatch para a classe. 97 | 98 | ```python 99 | # chat/routing.py 100 | from django.urls import re_path 101 | 102 | from . import consumers 103 | 104 | websocket_urlpatterns = [ 105 | re_path(r"ws/chat/(?P\w+)/$", consumers.ChatRoomConsumer.as_asgi()), 106 | ] 107 | ``` 108 | 109 | `chat/consumers.py` 110 | 111 | É o `views.py` do channels. 112 | 113 | ```python 114 | # chat/consumers.py 115 | import json 116 | 117 | from channels.generic.websocket import AsyncWebsocketConsumer 118 | 119 | 120 | class ChatRoomConsumer(AsyncWebsocketConsumer): 121 | async def connect(self): 122 | ... 123 | 124 | async def disconnect(self, close_code): 125 | ... 126 | 127 | async def receive(self, text_data): 128 | ... 129 | 130 | async def chat_message(self, event): 131 | ... 132 | ``` 133 | 134 | ```html 135 | 136 | 137 | {{ request.user.username|json_script:"user_username" }} {{ 138 | room_name|json_script:"room-name" }} 139 | 170 | ``` 171 | -------------------------------------------------------------------------------- /passo-a-passo.md: -------------------------------------------------------------------------------- 1 | daphne 2 | 3 | https://www.bootdey.com/snippets/view/white-chat#preview 4 | 5 | asgi.py 6 | 7 | routing.py 8 | 9 | consumers.py 10 | connect 11 | Pega o nome da sala 12 | # Entra no grupo 13 | group_add 14 | Aceita a conexão 15 | 16 | 17 | disconnect 18 | Sai do canal 19 | group_discard 20 | 21 | 22 | receive 23 | Quando receber alguma coisa, faz alguma coisa 24 | Envia mensagem para o grupo 25 | group_send 26 | 27 | chat_message 28 | Recebe mensagem do grupo 29 | Envia mensagem para o websocket 30 | 31 | --- 32 | 33 | Em Django Channels me explique o que é, e o que faz? 34 | 35 | consumers.py 36 | connect 37 | group_add 38 | 39 | 40 | disconnect 41 | group_discard 42 | 43 | 44 | receive 45 | group_send 46 | 47 | chat_message 48 | 49 | 50 | ```python 51 | # consumers.py 52 | 53 | from channels.generic.websocket import AsyncWebsocketConsumer 54 | import json 55 | 56 | class ChatConsumer(AsyncWebsocketConsumer): 57 | 58 | async def connect(self): 59 | # Chamado quando o canal WebSocket é inicializado. 60 | 61 | # Adiciona o cliente ao grupo do canal, permitindo comunicação em grupo. 62 | await self.channel_layer.group_add( 63 | 'chat_group', # Nome do grupo 64 | self.channel_name # Nome do canal do cliente 65 | ) 66 | 67 | # Aceita a conexão 68 | await self.accept() 69 | 70 | async def disconnect(self, close_code): 71 | # Chamado quando o canal WebSocket é fechado. 72 | 73 | # Remove o cliente do grupo do canal. 74 | await self.channel_layer.group_discard( 75 | 'chat_group', # Nome do grupo 76 | self.channel_name # Nome do canal do cliente 77 | ) 78 | 79 | async def receive(self, text_data): 80 | # Chamado quando uma mensagem WebSocket é recebida do cliente. 81 | 82 | # Envia a mensagem para o grupo do canal. 83 | await self.channel_layer.group_send( 84 | 'chat_group', # Nome do grupo 85 | { 86 | 'type': 'chat_message', # Tipo de mensagem a ser processada 87 | 'message': text_data # Dados da mensagem 88 | } 89 | ) 90 | 91 | async def chat_message(self, event): 92 | # Chamado quando uma mensagem é enviada para o grupo do canal. 93 | 94 | # Envia a mensagem de volta para o cliente. 95 | await self.send(text_data=json.dumps({ 96 | 'message': event['message'] 97 | })) 98 | 99 | ``` 100 | 101 | connect: Este método é chamado quando um cliente WebSocket se conecta ao servidor. No exemplo, ele adiciona o cliente a um grupo específico (chat_group), permitindo que eles participem de comunicações em grupo. 102 | 103 | disconnect: Este método é chamado quando um cliente WebSocket se desconecta. No exemplo, ele remove o cliente do grupo do canal. 104 | 105 | receive: Este método é chamado quando o servidor recebe uma mensagem WebSocket do cliente. No exemplo, ele envia a mensagem para o grupo do canal. 106 | 107 | chat_message: Este é um método personalizado definido no consumidor. Ele é chamado quando uma mensagem é enviada para o grupo do canal. No exemplo, ele envia a mensagem de volta para todos os clientes no grupo. 108 | 109 | 110 | --- 111 | 112 | chat.js 113 | chatSocket.onmessage 114 | Quando recebe a mensagem 115 | 116 | chatSocket.send 117 | Envia a mensagem 118 | 119 | chatSocket.onclose 120 | 121 | --- 122 | 123 | Parece que há um pequeno equívoco na sua pergunta. Em JavaScript, não existe um método específico chamado "chatSocket". No entanto, eu posso explicar como você pode implementar um sistema de chat usando WebSockets em JavaScript. WebSockets são uma tecnologia que permite a comunicação bidirecional em tempo real entre o cliente e o servidor. 124 | 125 | Aqui está um exemplo básico de como você pode implementar um chat usando WebSockets em JavaScript: 126 | 127 | 1. **Configuração do Servidor:** 128 | Primeiro, você precisa configurar um servidor WebSocket. Isso pode ser feito usando várias bibliotecas, como o `ws` para Node.js. 129 | 130 | ```javascript 131 | const WebSocket = require('ws'); 132 | const server = new WebSocket.Server({ port: 3000 }); 133 | 134 | server.on('connection', (socket) => { 135 | console.log('Cliente conectado'); 136 | 137 | // Evento quando o servidor recebe uma mensagem do cliente 138 | socket.on('message', (message) => { 139 | console.log(`Mensagem recebida: ${message}`); 140 | 141 | // Envie a mensagem de volta para todos os clientes conectados 142 | server.clients.forEach((client) => { 143 | if (client !== socket && client.readyState === WebSocket.OPEN) { 144 | client.send(message); 145 | } 146 | }); 147 | }); 148 | 149 | // Evento quando a conexão com o cliente é fechada 150 | socket.on('close', () => { 151 | console.log('Cliente desconectado'); 152 | }); 153 | }); 154 | ``` 155 | 156 | 2. **Configuração do Cliente:** 157 | No lado do cliente, você precisa usar a API WebSocket para estabelecer uma conexão com o servidor. 158 | 159 | ```javascript 160 | const socket = new WebSocket('ws://localhost:3000'); 161 | 162 | // Evento quando a conexão com o servidor é estabelecida 163 | socket.addEventListener('open', (event) => { 164 | console.log('Conexão estabelecida com o servidor'); 165 | }); 166 | 167 | // Evento quando o cliente recebe uma mensagem do servidor 168 | socket.addEventListener('message', (event) => { 169 | const message = event.data; 170 | console.log(`Mensagem recebida do servidor: ${message}`); 171 | }); 172 | 173 | // Evento quando a conexão com o servidor é fechada 174 | socket.addEventListener('close', (event) => { 175 | console.log('Conexão com o servidor fechada'); 176 | }); 177 | ``` 178 | 179 | 3. **Enviar Mensagens:** 180 | Agora, você pode enviar mensagens do cliente para o servidor e vice-versa. 181 | 182 | ```javascript 183 | // Enviar uma mensagem do cliente para o servidor 184 | const messageToSend = 'Olá, servidor!'; 185 | socket.send(messageToSend); 186 | ``` 187 | 188 | Lembre-se de que este é apenas um exemplo básico, e em um ambiente de produção, você precisará considerar questões de segurança, manipulação de erros e outros detalhes importantes. Além disso, certifique-se de entender as implicações de segurança ao lidar com comunicações em tempo real. 189 | 190 | --------------------------------------------------------------------------------