Этот репозиторий больше не поддерживается из-за неправильно выбранного языка программирования. Сложно запустить приложение с графическим интерфейсом, написанное на Python без всяких фреймворков на мобильных устройствах. Новый репозиторий: MessengerJava.
Разделы:
Messenger - бесплатный мессенджер с открытым исходным кодом для обмена мгновенными сообщениями
Messenger написан на языке програмирования Python
Установите Python
Работают ли определённые версии Python:
- 3.10 - Все основные тесты происходят на этой версии
- 3.9 - Версия поддерживается Messenger и тестируется в Github
- 3.8 - Версия поддерживается Messenger и тестируется в Github
- 3.7 - Версия не поддерживается, но пока что есть возможность запустить Messenger на ней
- 3.6 - Версия не поддерживается, но пока что есть возможность запустить Messenger на ней
- 2.7 - Версия не поддерживается
Остальные версии не тестировались
Если у вас установлен git
, то выполните команду:
git clone https://github.com/werryxgames/Messenger.git
В таком случае Messenger скачается в текущую директорию
Также вы можете скачать Messenger при помощи интерфейса Github
Нажмите на кнопку Code
, а затем на Download ZIP
Необходимо распаковать скачанный архив в нужную директорию
Теперь вы можете удалить скачанный архив
Теперь вы можете создать ярлыки со следующими командами на рабочий стол:
python "путь_к_файлу_server.py"
python "путь_к_файлу_main.py"
Рекомендуется обновлять версию только из релизов
Прочитайте, написано ли в релизе про изменение формата хранения данных. Если да, то необходимо будет удалить все данные, затем проделайте шаги, как в Скачивание репозитория
Если написано, что формат хранения данных не изменён, или ничего не написано, проделайте шаги, как в Скачивание из Github, но распакуйте только файлы server.py
и main.py
Messenger состоит из двух частей: сервера и клиента
Сервер хранит все данные и обрабатывает запросы от клиентов
Клиент показывает информацию от сервера в графическом виде
Чтобы запустить сервер, напишите
python "путь_к_файлу_server.py"
Вы должны увидеть надпись Сервер запущен
, иначе создайте проблему на вкладке Issues
Перед надписью Сервер запущен
может появиться дополнительная информация (True
, False
(несколько раз) и список с сообщениями). Это значит, что база данных сброшена до первоначального состояния. После этого рекомендуется выключить сервер и сделать то, что написано в Отключение сброса базы данных
Чтобы отключить сброс базы данных, необходимо зайти в файл server.py
(пролистать в конец) и убрать все строки между этими (оставьте сами строки, удалите все строки, на месте которых "..."):
if __name__ == "__main__":
...
main()
Вам понадобиться включить сервер
Чтобы зайти в Messenger в первый раз, надо создать аккаунт. Для этого введите логин и пароль в соответствующие поля. Если всё правильно, то вы должны увидеть, как появится основной интерфейс Messenger`а
Если интерфейс не появился, посмотрите в консоли, там должно была появиться ошибка на подобии следующей:
----------------------------
| ОШИБКА: Заголовок ошибки |
----------------------------
| Описание ошибки |
----------------------------
Чтобы отправить сообщения, выберите получателя в списке слева, напишите текст сообщения справа внизу и нажмите 'Enter', или кнопку 'Отправить'
Внизу вашего сообщения написан его статус
Статусы сообщений:
- Отправлено - Сообщение отправлено, но ещё не получено сервером
- Доставлено - Сообщение доставлено на сервер, но ещё не получено получателем
- Получено - Сообщение получено получателем, но он ещё не ответил
- Прочитано - Сообщение получено получателем, который написал что-то после вашего сообщения
Код проверяется при помощи flake8
и pytest
(тесты в папке tests):
flake8 . --exclude venv,__pycache__,.git,.github
python -m pytest tests
def absolute(path_: str) -> str:
"""Возвращает абсолютный путь из относительного."""
def encrypt_password(user_id: int, password: str) -> str:
"""Шифрует пароль.
Аргументы:
user_id: ID пользователя.
password: Пароль пользователя.
Возвращаемое значение: Зашифрованный пароль.
"""
class Database:
"""Класс базы данных."""
def __init__(self, filepath: str) -> None:
"""Инициализация базы данных.
Аргументы:
filepath: Путь к базе данных.
"""
def sql(
self,
sql_text: str,
format_=None,
noresult: bool = False
):
"""Выполняет SQL код.
Аргументы:
sql_text: SQL код.
format_: Заменители '?' в SQL коде.
noresult: Если включено, то результатом будет булевое значение.
Возвращаемое значение:
bool: Если включено noresult, возвращает True, если результат
выполнения SQL кода пустой, иначе False.
list: Массив с результатами.
tuple: Единственный результат.
"""
def reset_database(self) -> bool:
"""Сбрасывает базу данных к начальному состоянию.
Возвращаемое значение: True, если удалось сбросить, иначе False.
"""
def create_account(self, name: str, password: str):
"""Создаёт аккаунт.
Аргументы:
name: Логин аккаунта.
password: Пароль от аккаунта.
Возвращаемое значение: Статус выполнения, id в случае успеха.
"""
def login_account(self, name: str, password: str):
"""Входит в аккаунт.
Аргументы:
name: Логин аккаунта.
password: Пароль от аккаунта.
Возвращаемое значение: Статус выполнения, id в случае успеха.
"""
def get_account_data(self, name: str) -> (tuple, list):
"""Получает данные аккаунта.
Аргументы:
name: Логин аккаунта.
Возвращаемое значение:
[
Отправленные и полученные сообщения,
ID пользователей, чей статус сообщений был изменён.
].
"""
def send_message(self, login: str, receiver: int, message: str) -> bool:
"""Создаёт запись в базе данных о сообщении."""
def find_user(self, username: str):
"""Ищет пользователя по username.
Аргументы:
username: Имя пользователя.
Возвращаемое значение:
False: Пользователь не найден.
list[int, str]: ID пользователя и его имя.
"""
def close(self) -> None:
"""Закрывает базу данных."""
class NetworkedClient:
"""Класс клиента."""
_instances = []
def __init__(self, sock: socket, addr) -> None:
pass
@staticmethod
def encode_message(message) -> bytes:
"""Превращает объекты, преобразоваемые в JSON в байты."""
@staticmethod
def decode_message(message: bytes):
"""Превращает байты в объекты, преобразоваемые в JSON."""
def send(self, message: list) -> None:
"""Отправляет сообщение клиенту.
Аргументы:
message: Сообщение.
"""
def send_account_data(self) -> None:
"""Отправляет данные об аккаунте."""
def receive(self, jdata: bytes) -> bool:
"""Получает сообщение от клиента.
Аргументы:
jdata: Данные от клиента.
Возвращаемое значаени: Надо ли обновлять таймер сообщений?
"""
def close(self) -> None:
"""Закрывает соединение с клиентом."""
def check_idle() -> None:
"""Отключает неактивных клиентов.
Аргументы:
clients: Словарь всех клиентов.
"""
def main() -> None:
"""Основная функция."""
class Window:
"""Класс окна."""
def __init__(self, tk_window: tk.Tk) -> None:
"""Инициализация окна.
Аргументы:
tk_window: Окно Tkinter.
"""
def place(self, id_: str, element, *args, **kwargs) -> None:
"""Размещает объект element.
Аргументы:
id_: Уникальный идентификатор элемента.
element: Элемент, который необходимо разместить.
*args: Аргументы element.place().
**kwargs: Позиционные аргументы element.place().
"""
def pack(self, id_: str, element, *args, **kwargs) -> None:
"""Размещает объект element.
Аргументы:
id_: Уникальный идентификатор элемента.
element: Элемент, который необходимо разместить.
*args: Аргументы element.pack().
**kwargs: Позиционные аргументы element.pack().
"""
def clear(self) -> None:
"""Очищает все элементы."""
def __getattribute__(self, id_: str):
"""Получает элемент по его ID.
Аргументы:
id_: Уникальный идентификатор элемента.
Возвращаемое значение: Элемент.
"""
class MessengerClient:
"""Основной класс."""
def __init__(self) -> None:
"""Инициализация класса."""
@staticmethod
def show_error(title: str, message: str) -> None:
"""Показывает ошибку.
Аргументы:
title: Заголовок ошибки.
message: Описание ошибки.
"""
@staticmethod
def encode_message(message) -> bytes:
"""Превращает объекты, преобразоваемые в JSON в байты."""
@staticmethod
def decode_message(message: bytes):
"""Превращает байты в объекты, преобразоваемые в JSON."""
def send(self, message) -> None:
"""Отправляет сообщение message на сервер.
Аргументы:
message: Сообщение.
"""
@staticmethod
def create_round_rectangle(
cnv,
px1,
py1,
px2,
py2,
radius,
ign1=False,
ign2=False,
**kwargs
) -> int:
"""Создаёт скруглённый прямоугольник.
Аргументы:
cnv: Холст Tkinter.
px1: Левая точка прямоугольника.
py1: Верхняя точка прямоугольника.
px2: Правая точка прямоугольника.
py2: Нижняя точка прямоугольника.
radius: Радиус скругления.
kwargs: Дополнительные аргументы cnv.create_polygon().
Возвращаемое значение: ID Скруглённого прямоугольника на холсте.
"""
def user_selected(self) -> None:
"""Обработчик события выбора пользователя.
Аргументы:
wid: Виджет Listbox Tkinter.
"""
def resize(self, event) -> None:
"""Обработчик изменения размера окна."""
def send_message(self, message: str) -> None:
"""Отправляет сообщение на сервер.
Аргументы:
message: Сообщение.
"""
def add_user(self, username: str) -> None:
"""Добавляет пользователя по имени.
Аргументы:
username: Имя пользователя.
"""
def receive(self) -> None:
"""Получает сообщения от сервера."""
def send_idle(self) -> None:
"""Отправляет сообщение серверу о том, что клиент до сих пор открыт."""
def login_tab(self, clear=True) -> None:
"""Перемещает на начальную вкладку."""
def on_destroy(self):
"""Обработчик выхода из приложения."""
def main(self):
"""Основная функция клиента."""