feat: docker-серверы - приложения в ~/apps под управлением бота
serverus: DockerHost - установка Docker и ingress Caddy, deploy приложения с проверкой compose и caddy.conf до изменений и пересозданием только изменившихся сервисов, status, control, logs, remove. nftables перезапускается только при изменении конфига, Docker следом восстанавливает свои правила; release восстанавливает конфиг Debian вместо остановки nftables. Telegram: прием документов и отправка файлов, раздача файлов своего Bot API сервера через nginx (telegram-files). App: общая модель Managed для Point и Platform, DockerApp и версии файлов AppVersion, разбор архивов (uploads), сценарии платформы (platforms), задачи и меню docker-серверов в боте. Проверено на стенде Debian 13 с local_certs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
65c19ea1cd
commit
a8d1f286d1
42 files changed
+3509
-232
No files matched your search
+45
-1
@@ -8,11 +8,32 @@ CHAT_ID = 42
|
||||
|
||||
|
||||
class FakeApi:
|
||||
"""Подменяет TeleBot: запоминает отправленные и удаленные сообщения."""
|
||||
"""Подменяет TeleBot: запоминает отправленные и удаленные сообщения, отдает присланные документы."""
|
||||
|
||||
def __init__(self):
|
||||
self.sent = []
|
||||
self.deleted = []
|
||||
self.documents = []
|
||||
self.files = {}
|
||||
"""file_id -> содержимое присланного документа."""
|
||||
|
||||
def get_file(self, file_id):
|
||||
from .api import WORK_DIR, uses_own_server
|
||||
|
||||
# свой сервер отдает путь на своем диске, облако - относительный
|
||||
path = f'{WORK_DIR}/1:token/documents/{file_id}' if uses_own_server() else f'documents/{file_id}'
|
||||
return SimpleNamespace(file_id=file_id, file_path=path, file_size=len(self.files[file_id]))
|
||||
|
||||
def download_file(self, file_path):
|
||||
return self.files[file_path.rsplit('/', 1)[-1]]
|
||||
|
||||
def send_document(self, chat_id, document, caption=None, reply_markup=None, parse_mode=None):
|
||||
content = document.file.read()
|
||||
self.documents.append(SimpleNamespace(
|
||||
chat_id=chat_id, file_name=document.file_name, content=content, caption=caption, reply_markup=reply_markup,
|
||||
))
|
||||
self.sent.append(SimpleNamespace(chat_id=chat_id, text=caption, reply_markup=reply_markup, parse_mode=parse_mode))
|
||||
return SimpleNamespace(message_id=len(self.sent))
|
||||
|
||||
def send_message(self, chat_id, text, reply_markup=None, parse_mode=None):
|
||||
self.sent.append(SimpleNamespace(chat_id=chat_id, text=text, reply_markup=reply_markup, parse_mode=parse_mode))
|
||||
@@ -51,6 +72,19 @@ def message_update_json(update_id: int, text: str, chat_type: str = 'private', u
|
||||
}
|
||||
|
||||
|
||||
def document_update_json(
|
||||
update_id: int, file_id: str, file_name: str, size: int, caption: str = '', user_id: int = USER_ID,
|
||||
) -> dict:
|
||||
"""Обновление с документом в том виде, в каком его присылает Bot API."""
|
||||
update = message_update_json(update_id, '', user_id=user_id)
|
||||
message = update['message']
|
||||
del message['text']
|
||||
message['document'] = {'file_id': file_id, 'file_unique_id': file_id, 'file_name': file_name, 'file_size': size}
|
||||
if caption:
|
||||
message['caption'] = caption
|
||||
return update
|
||||
|
||||
|
||||
class Conversation:
|
||||
"""Диалог пользователя с ботом: say() отправляет сообщение и возвращает ответ бота."""
|
||||
|
||||
@@ -68,3 +102,13 @@ class Conversation:
|
||||
sent_before = len(self.api.sent)
|
||||
self._handle_update(self.api, self.bot, message_update(self._update_id, text, user_id=self.user_id))
|
||||
return self.api.last_text if len(self.api.sent) > sent_before else None
|
||||
|
||||
def send_document(self, file_name: str, content: bytes, caption: str = '') -> str | None:
|
||||
"""Присылает боту документ и возвращает ответ бота."""
|
||||
self._update_id += 1
|
||||
file_id = f'file{self._update_id}'
|
||||
self.api.files[file_id] = content
|
||||
sent_before = len(self.api.sent)
|
||||
update = document_update_json(self._update_id, file_id, file_name, len(content), caption, self.user_id)
|
||||
self._handle_update(self.api, self.bot, types.Update.de_json(update))
|
||||
return self.api.last_text if len(self.api.sent) > sent_before else None
|
||||
Reference in new issue
Block a user