Skip to content
This repository has been archived by the owner on Aug 17, 2023. It is now read-only.

werryxgames/Messenger

Repository files navigation

Messenger

Этот репозиторий больше не поддерживается из-за неправильно выбранного языка программирования. Сложно запустить приложение с графическим интерфейсом, написанное на Python без всяких фреймворков на мобильных устройствах. Новый репозиторий: MessengerJava.

Разделы:

Главное

Обучение

Код

Главное

Что такое Messenger?

Messenger - бесплатный мессенджер с открытым исходным кодом для обмена мгновенными сообщениями

Messenger написан на языке програмирования Python

Установка

Установка 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 скачается в текущую директорию

Скачивание из Github

Также вы можете скачать Messenger при помощи интерфейса Github

Нажмите на кнопку Code, а затем на Download ZIP

Необходимо распаковать скачанный архив в нужную директорию

Теперь вы можете удалить скачанный архив

Завершение установки

Теперь вы можете создать ярлыки со следующими командами на рабочий стол:

python "путь_к_файлу_server.py"
python "путь_к_файлу_main.py"

Обновление Messenger

Рекомендуется обновлять версию только из релизов

Прочитайте, написано ли в релизе про изменение формата хранения данных. Если да, то необходимо будет удалить все данные, затем проделайте шаги, как в Скачивание репозитория

Если написано, что формат хранения данных не изменён, или ничего не написано, проделайте шаги, как в Скачивание из Github, но распакуйте только файлы server.py и main.py

Обучение

Основы

Messenger состоит из двух частей: сервера и клиента

Сервер хранит все данные и обрабатывает запросы от клиентов

Клиент показывает информацию от сервера в графическом виде

Чтобы запустить сервер, напишите

python "путь_к_файлу_server.py"

Вы должны увидеть надпись Сервер запущен, иначе создайте проблему на вкладке Issues

Перед надписью Сервер запущен может появиться дополнительная информация (True, False (несколько раз) и список с сообщениями). Это значит, что база данных сброшена до первоначального состояния. После этого рекомендуется выключить сервер и сделать то, что написано в Отключение сброса базы данных

Отключение сброса базы данных

Чтобы отключить сброс базы данных, необходимо зайти в файл server.py (пролистать в конец) и убрать все строки между этими (оставьте сами строки, удалите все строки, на месте которых "..."):

if __name__ == "__main__":
    ...
    main()

Примеры

Аккаунты

Вам понадобиться включить сервер

Чтобы зайти в Messenger в первый раз, надо создать аккаунт. Для этого введите логин и пароль в соответствующие поля. Если всё правильно, то вы должны увидеть, как появится основной интерфейс Messenger

Если интерфейс не появился, посмотрите в консоли, там должно была появиться ошибка на подобии следующей:

----------------------------
| ОШИБКА: Заголовок ошибки |
----------------------------
|     Описание ошибки      |
----------------------------

Сообщения

Чтобы отправить сообщения, выберите получателя в списке слева, напишите текст сообщения справа внизу и нажмите 'Enter', или кнопку 'Отправить'

Внизу вашего сообщения написан его статус

Статусы сообщений:

  1. Отправлено - Сообщение отправлено, но ещё не получено сервером
  2. Доставлено - Сообщение доставлено на сервер, но ещё не получено получателем
  3. Получено - Сообщение получено получателем, но он ещё не ответил
  4. Прочитано - Сообщение получено получателем, который написал что-то после вашего сообщения

Код

Код проверяется при помощи flake8 и pytest (тесты в папке tests):

flake8 . --exclude venv,__pycache__,.git,.github
python -m pytest tests

Функции и классы

server.py - Модуль сервера.

Зависимости: bcrypt

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:
    """Основная функция."""

main.py - Мессенджер на Python (клиент).

Нет зависимостей

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):
        """Основная функция клиента."""