From f2e7e37592f9d1a8461d4749380c9891aa578411 Mon Sep 17 00:00:00 2001 From: Alexey Polyakov Date: Sun, 22 Mar 2026 16:59:13 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B0=D0=BC=D0=A2=D0=B0=D0=BC:=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=2032=20?= =?UTF-8?q?=D0=BE=D0=BF=D0=BA=D0=BE=D0=B4=D0=B0.=20=D0=9D=D0=B0=D0=B4?= =?UTF-8?q?=D0=B5=D1=8E=D1=81=D1=8C,=20=D0=B1=D1=83=D0=B4=D0=B5=D1=82=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tamtam/models.py | 5 ++- src/tamtam/processors/__init__.py | 3 +- src/tamtam/processors/search.py | 63 +++++++++++++++++++++++++++++++ src/tamtam/socket.py | 6 +++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/tamtam/processors/search.py diff --git a/src/tamtam/models.py b/src/tamtam/models.py index 5e5ecc8..ffab737 100644 --- a/src/tamtam/models.py +++ b/src/tamtam/models.py @@ -31,4 +31,7 @@ class FinalAuthPayloadModel(pydantic.BaseModel): class LoginPayloadModel(pydantic.BaseModel): interactive: bool - token: str \ No newline at end of file + token: str + +class SearchUsersPayloadModel(pydantic.BaseModel): + contactIds: list \ No newline at end of file diff --git a/src/tamtam/processors/__init__.py b/src/tamtam/processors/__init__.py index 46f53f4..4c798db 100644 --- a/src/tamtam/processors/__init__.py +++ b/src/tamtam/processors/__init__.py @@ -1,5 +1,6 @@ from .main import MainProcessors from .auth import AuthProcessors +from .search import SearchProcessors -class Processors(MainProcessors, AuthProcessors): +class Processors(MainProcessors, AuthProcessors, SearchProcessors): pass \ No newline at end of file diff --git a/src/tamtam/processors/search.py b/src/tamtam/processors/search.py new file mode 100644 index 0000000..45b256b --- /dev/null +++ b/src/tamtam/processors/search.py @@ -0,0 +1,63 @@ +import json, pydantic +from classes.baseprocessor import BaseProcessor +from tamtam.models import SearchUsersPayloadModel + +class SearchProcessors(BaseProcessor): + async def contact_info(self, payload, seq, writer): + """Поиск пользователей по ID""" + # Валидируем данные пакета + try: + SearchUsersPayloadModel.model_validate(payload) + except pydantic.ValidationError as error: + self.logger.error(f"Возникли ошибки при валидации пакета: {error}") + await self._send_error(seq, self.opcodes.CONTACT_INFO, self.error_types.INVALID_PAYLOAD, writer) + return + + # Итоговый список пользователей + users = [] + + # ID пользователей, которые нам предстоит найти + contactIds = payload.get("contactIds") + + # Ищем пользователей в бд + async with self.db_pool.acquire() as conn: + async with conn.cursor() as cursor: + for contactId in contactIds: + await cursor.execute("SELECT * FROM users WHERE id = %s", (contactId,)) + user = await cursor.fetchone() + + # Если такой пользователь есть, добавляем его в список + if user: + # Аватарка с биографией + photo_id = None if not user.get("avatar_id") else int(user.get("avatar_id")) + avatar_url = None if not photo_id else self.config.avatar_base_url + photo_id + description = None if not user.get("description") else user.get("description") + + # Генерируем профиль + users.append( + self.tools.generate_profile_tt( + id=user.get("id"), + phone=int(user.get("phone")), + avatarUrl=avatar_url, + photoId=photo_id, + updateTime=int(user.get("updatetime")), + firstName=user.get("firstname"), + lastName=user.get("lastname"), + options=json.loads(user.get("options")), + description=description, + username=user.get("username") + ) + ) + + # Создаем данные пакета + payload = { + "contacts": users + } + + # Создаем пакет + response = self.proto.pack_packet( + seq=seq, opcode=self.opcodes.CONTACT_INFO, payload=payload + ) + + # Отправляем + await self._send(writer, response) \ No newline at end of file diff --git a/src/tamtam/socket.py b/src/tamtam/socket.py index ed1820c..6da1028 100644 --- a/src/tamtam/socket.py +++ b/src/tamtam/socket.py @@ -3,6 +3,7 @@ from common.proto_tcp import MobileProto from tamtam.processors import Processors from common.rate_limiter import RateLimiter from common.opcodes import Opcodes +from common.tools import Tools class TTMobileServer: def __init__(self, host="0.0.0.0", port=443, ssl_context=None, db_pool=None, clients={}, send_event=None): @@ -18,6 +19,7 @@ class TTMobileServer: self.proto = MobileProto() self.processors = Processors(db_pool=db_pool, clients=clients, send_event=send_event) + self.auth_required = Tools().auth_required # rate limiter self.auth_rate_limiter = RateLimiter(max_attempts=5, window_seconds=60) @@ -97,6 +99,10 @@ class TTMobileServer: if userPhone: await self._finish_auth(writer, address, userPhone, userId) + case self.opcodes.CONTACT_INFO: + await self.auth_required( + userPhone, self.processors.contact_info, payload, seq, writer + ) case _: self.logger.warning(f"Неизвестный опкод {opcode}") except Exception as e: