mirror of
http://github.com/openmax-server/server.git
synced 2026-07-03 14:05:40 +02:00
203 lines
5.7 KiB
Python
203 lines
5.7 KiB
Python
# Импортирование библиотек
|
|
import asyncio
|
|
import logging
|
|
import signal
|
|
import ssl
|
|
import sys
|
|
|
|
from common.config import ServerConfig
|
|
from common.push import PushService
|
|
from oneme.controller import OnemeController
|
|
from tamtam.controller import TTController
|
|
from telegrambot.controller import TelegramBotController
|
|
|
|
# Конфиг сервера
|
|
server_config = ServerConfig()
|
|
|
|
|
|
class SQLiteCursorCompat:
|
|
def __init__(self, connection):
|
|
self.connection = connection
|
|
self.cursor = None
|
|
|
|
async def __aenter__(self):
|
|
self.cursor = await self.connection.cursor()
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc, tb):
|
|
if self.cursor is not None:
|
|
await self.cursor.close()
|
|
self.cursor = None
|
|
|
|
@property
|
|
def lastrowid(self):
|
|
return None if self.cursor is None else self.cursor.lastrowid
|
|
|
|
def _normalize_query(self, query):
|
|
return query.replace("%s", "?").replace(
|
|
"UNIX_TIMESTAMP()", "CAST(strftime('%s','now') AS INTEGER)"
|
|
)
|
|
|
|
async def execute(self, query, params=()):
|
|
normalized_query = self._normalize_query(query)
|
|
if params is None:
|
|
params = ()
|
|
elif not isinstance(params, (tuple, list, dict)):
|
|
params = (params,)
|
|
await self.cursor.execute(normalized_query, params)
|
|
|
|
async def fetchone(self):
|
|
row = await self.cursor.fetchone()
|
|
if row is None:
|
|
return None
|
|
return dict(row)
|
|
|
|
async def fetchall(self):
|
|
rows = await self.cursor.fetchall()
|
|
return [dict(row) for row in rows]
|
|
|
|
|
|
class SQLiteConnectionCompat:
|
|
def __init__(self, connection):
|
|
self.connection = connection
|
|
|
|
async def __aenter__(self):
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc, tb):
|
|
return False
|
|
|
|
def cursor(self):
|
|
return SQLiteCursorCompat(self.connection)
|
|
|
|
|
|
class SQLitePoolCompat:
|
|
def __init__(self, connection):
|
|
self.connection = connection
|
|
|
|
def acquire(self):
|
|
return SQLiteConnectionCompat(self.connection)
|
|
|
|
|
|
async def init_db():
|
|
"""Инициализация базы данных"""
|
|
|
|
db = {}
|
|
|
|
if server_config.db_type == "mysql":
|
|
import aiomysql
|
|
|
|
db = await aiomysql.create_pool(
|
|
host=server_config.db_host,
|
|
port=server_config.db_port,
|
|
user=server_config.db_user,
|
|
password=server_config.db_password,
|
|
db=server_config.db_name,
|
|
cursorclass=aiomysql.DictCursor,
|
|
autocommit=True,
|
|
)
|
|
elif server_config.db_type == "sqlite":
|
|
import aiosqlite
|
|
|
|
raw_db = await aiosqlite.connect(server_config.db_file, isolation_level=None)
|
|
raw_db.row_factory = aiosqlite.Row
|
|
db = SQLitePoolCompat(raw_db)
|
|
|
|
# Возвращаем
|
|
return db
|
|
|
|
|
|
def init_ssl():
|
|
"""Создание контекста SSL"""
|
|
# Создаем контекст SSL
|
|
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
ssl_context.load_cert_chain(server_config.certfile, server_config.keyfile)
|
|
|
|
# Возвращаем
|
|
return ssl_context
|
|
|
|
|
|
def set_logging():
|
|
"""Настройка уровня логирования"""
|
|
# Настройка уровня логирования
|
|
log_level = server_config.log_level
|
|
|
|
if log_level == "debug":
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
elif log_level == "info":
|
|
logging.basicConfig(level=logging.INFO)
|
|
else:
|
|
logging.basicConfig(level=None)
|
|
|
|
|
|
async def main():
|
|
"""Запуск сервера"""
|
|
|
|
set_logging()
|
|
db = await init_db()
|
|
ssl_context = init_ssl()
|
|
clients = {}
|
|
push_service = PushService(server_config.firebase_credentials_path)
|
|
|
|
async def api_event(target, eventData):
|
|
target_clients = api.get("clients", {}).get(target, {}).get("clients", [])
|
|
|
|
for client in target_clients:
|
|
await controllers[client["protocol"]].event(target, client, eventData)
|
|
|
|
# Если у пользователя нет активных подключений
|
|
# и это новое сообщение - отсылаем пуш
|
|
if not target_clients and eventData.get("eventType") == "new_msg":
|
|
message = eventData.get("message", {})
|
|
sender_id = message.get("sender")
|
|
text = message.get("text", "")
|
|
chat_id = eventData.get("chatId", "")
|
|
msg_id = message.get("id", 0)
|
|
await push_service.send_to_user(
|
|
db, target,
|
|
sender_id=sender_id,
|
|
msg_id=msg_id,
|
|
chat_id=chat_id,
|
|
text=text,
|
|
)
|
|
|
|
api = {
|
|
"db": db,
|
|
"ssl": ssl_context,
|
|
"clients": clients,
|
|
"event": api_event,
|
|
"origins": server_config.origins,
|
|
}
|
|
|
|
controllers = {
|
|
"oneme": OnemeController(),
|
|
"tamtam": TTController(),
|
|
"telegrambot": TelegramBotController(),
|
|
}
|
|
|
|
api["telegram_bot"] = controllers["telegrambot"]
|
|
|
|
coros = [controller.launch(api) for controller in controllers.values()]
|
|
running_tasks = [asyncio.create_task(coro) for coro in coros]
|
|
|
|
# Обработчик sigterm
|
|
loop = asyncio.get_running_loop()
|
|
|
|
def _shutdown(sig):
|
|
for task in running_tasks:
|
|
task.cancel()
|
|
|
|
if sys.platform != "win32":
|
|
for sig in (signal.SIGTERM, signal.SIGINT):
|
|
loop.add_signal_handler(sig, _shutdown, sig)
|
|
|
|
# Запускаем контроллеры
|
|
try:
|
|
await asyncio.gather(*running_tasks)
|
|
except asyncio.CancelledError:
|
|
logging.info("Все задачи завершены, выходим")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|