acolyte-py 2 years ago
parent
commit
9600baf90f
3 changed files with 174 additions and 1 deletions
  1. 32 1
      README.md
  2. 70 0
      chat.py
  3. 72 0
      example.py

+ 32 - 1
README.md

@@ -1,2 +1,33 @@
-# asynchronous_chat
+# Асинхронный Чат  ✉️
+
+Асинхронный час на базе raw-протоколов. Написан с помощью библиотеке ``asyncio`` и ``pywebio``
+
+Так же в файле ``example.py`` есть приблизительный пример работы чата, с точки зрения взаимодействия raw-протоколов.
+Неудобная система одновременного запуска python-файлов для общения. Уязвимость данного чата, возможность запустить - reverse-shell. 
+Привело к идее, усовершенствовать данный чат. Асинхронными потоками/Асинхронный ввод-вывод, и веб страницей для удобства общения нескольких людей одновременно.
+
+Чат имеет веб страницу. Окно чата. Возможность за логинится. Выполнен в стиле цитат известного стримера - ```Arthas```
+
+### Доступ 🔑
+#### Локальная сеть
+Для возможности воспользоваться чатом в локальной сети, Вы должны использовать следующие команды:
+```
+git http://gogs.tomtit.tomsk.ru:3000/gr703_mimal/asynchronous_chat.git
+cd asynchronous_chat && python3 chat.py
+```
+
+Далее у вас будет запущен чат по вашему локальному адресу и порту 8078, пример:
+```
+http://192.168.0.72:8078/
+```
+
+#### Открытая сеть
+Для этого Вам понадобиться следующее ПО: ``https://dashboard.ngrok.com/get-started/setup``
+
+Выполнить ряд команд для бесплатного хостинга:
+```
+unzip /path/to/ngrok.zip
+ngrok config add-authtoken <YOU_TOKEN>
+ngrok http 8078
+```
 

+ 70 - 0
chat.py

@@ -0,0 +1,70 @@
+import asyncio
+
+from pywebio import start_server
+from pywebio.input import *
+from pywebio.output import *
+from pywebio.session import run_async, run_js
+
+
+chat_msgs = []
+online_users = set()
+
+MAX_MSGS_COUNT = 100
+
+
+async def main():
+    global chat_msgs
+    put_markdown('## 😈 Всем доброго времени бытия!\nСегодня начнём за террористов, там посмотрим')
+    msg_box = output()
+    put_scrollable(msg_box, height=500, keep_bottom=True)
+    nickname = await input(
+        'Зайти в базу', required=True, placeholder='Твой ник',
+        validate=lambda n: 'Эй балбес, ник норм придумай' if n in online_users or n == '🗣' else None
+    )
+    online_users.add(nickname)
+    chat_msgs.append(('🗣', f' `{nickname}` прибыл на базу!'))
+    msg_box.append(put_markdown(f' `{nickname}` прибыл на базу!'))
+    refresh_task = run_async(refresh_msg(nickname, msg_box))
+
+    while True:
+        data = await input_group(
+            '💭 Новое сообщение', [
+                input(placeholder='Текст сообщения', name='msg'),
+                actions(name='cmd', buttons=['Отправить', {'label': 'Выйти с базы', 'type': 'cancel'}])
+            ],
+            validate=lambda m: ('msg', 'Введите текст сообщения') if m['cmd'] == 'Отправить' and not m['msg'] else None
+        )
+
+        if data is None:
+            break
+
+        msg_box.append(put_markdown(f"`{nickname}`: {data['msg']}"))
+        chat_msgs.append((nickname, data['msg']))
+
+    refresh_task.close()
+    online_users.remove(nickname)
+    toast("Вы вышли из чата!")
+    msg_box.append(put_markdown(f'📢 `{nickname}` покинул чат!'))
+    chat_msgs.append(('📢', f' `{nickname}` покинул чат!'))
+    put_buttons(['Перезайти'], onclick=lambda btn: run_js('window.location.reload()'))
+
+
+async def refresh_msg(nickname, msg_box):
+    global chat_msgs
+    last_idx = len(chat_msgs)
+
+    while True:
+        await asyncio.sleep(1)
+
+        for m in chat_msgs[last_idx:]:
+            if m[0] != nickname:
+                msg_box.append(put_markdown(f"`{m[0]}`: {m[1]}"))
+
+        if len(chat_msgs) > MAX_MSGS_COUNT:
+            chat_msgs = chat_msgs[len(chat_msgs) // 2:]
+
+        last_idx = len(chat_msgs)
+
+
+if __name__ == "__main__":
+    start_server(main, debug=True, port=8078, cdn=False)

+ 72 - 0
example.py

@@ -0,0 +1,72 @@
+"""Серверная часть UDP-чата."""
+# import socket
+#
+#
+# UDP_MAX_SIZE = 65535
+#
+#
+# def listen(host: str = '127.0.0.1', port: int = 3000):
+#     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+#
+#     s.bind((host, port))
+#     print(f'Listening at {host}:{port}')
+#
+#     members = []
+#     while True:
+#         msg, addr = s.recvfrom(UDP_MAX_SIZE)
+#
+#         if addr not in members:
+#             members.append(addr)
+#
+#         if not msg:
+#             continue
+#
+#         client_id = addr[1]
+#         if msg.decode('ascii') == '__join':
+#             print(f'Client {client_id} joined chat')
+#             continue
+#
+#         msg = f'client{client_id}: {msg.decode("ascii")}'
+#         for member in members:
+#             if member == addr:
+#                 continue
+#
+#             s.sendto(msg.encode('ascii'), member)
+#
+#
+# if __name__ == '__main__':
+#     listen()
+
+"""Клиенская часть UDP-чата."""
+# import socket
+# import threading
+# import os
+#
+#
+# UDP_MAX_SIZE = 65535
+#
+#
+# def listen(s: socket.socket):
+#     while True:
+#         msg = s.recv(UDP_MAX_SIZE)
+#         print('\r\r' + msg.decode('ascii') + '\n' + f'you: ', end='')
+#
+#
+# def connect(host: str = '127.0.0.1', port: int = 3000):
+#     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+#
+#     s.connect((host, port))
+#
+#     threading.Thread(target=listen, args=(s,), daemon=True).start()
+#
+#     s.send('__join'.encode('ascii'))
+#
+#     while True:
+#         msg = input(f'you: ')
+#         s.send(msg.encode('ascii'))
+#
+#
+# if __name__ == '__main__':
+#     os.system('clear')
+#     print('Welcome to chat!')
+#     connect()