|
|
import os
|
|
|
import asyncio
|
|
|
import importlib
|
|
|
from typing import Dict, Optional
|
|
|
|
|
|
from logging.config import dictConfig
|
|
|
from logging import getLogger, Logger
|
|
|
|
|
|
from ..variables.loader import Datavars
|
|
|
from ..commands.commands import Command, CommandRunner
|
|
|
from .utils.workers import Worker
|
|
|
|
|
|
from .schemas.config import ConfigSchema
|
|
|
|
|
|
|
|
|
# Получаем конфигурацию сервера.
|
|
|
TESTING = bool(os.environ.get("TESTING", False))
|
|
|
if not TESTING:
|
|
|
from .config import config
|
|
|
server_config = ConfigSchema(**config)
|
|
|
else:
|
|
|
from tests.server.config import config
|
|
|
server_config = ConfigSchema(**config)
|
|
|
|
|
|
|
|
|
class ServerData:
|
|
|
def __init__(self, config: ConfigSchema = server_config):
|
|
|
self.event_loop = asyncio.get_event_loop()
|
|
|
|
|
|
self._variables_path = config.variables_path
|
|
|
|
|
|
# Конфигурируем логгирование.
|
|
|
dictConfig(config.logger_config)
|
|
|
self.logger: Logger = getLogger("main")
|
|
|
self.log_message = {'DEBUG': self.logger.debug,
|
|
|
'INFO': self.logger.info,
|
|
|
'WARNING': self.logger.warning,
|
|
|
'ERROR': self.logger.error,
|
|
|
'CRITICAL': self.logger.critical}
|
|
|
|
|
|
self._datavars: Optional[Datavars] = None
|
|
|
|
|
|
# Словарь описаний команд.
|
|
|
self.commands: Dict[str, Command] = self._get_commands_descriptions(
|
|
|
config.commands_path)
|
|
|
|
|
|
# Словарь CID и экземпляров команд, передаваемых воркерам.
|
|
|
self.commands_runners: Dict[str, CommandRunner] = {}
|
|
|
|
|
|
# Словарь WID и экземпляров процессов-воркеров, передаваемых воркерам.
|
|
|
self.workers: Dict[int, Worker] = {}
|
|
|
|
|
|
@property
|
|
|
def datavars(self):
|
|
|
if self._datavars is not None:
|
|
|
return self._datavars
|
|
|
else:
|
|
|
self._datavars = self._load_datavars(self._variables_path,
|
|
|
self.logger)
|
|
|
return self._datavars
|
|
|
|
|
|
def _load_datavars(vars_path: str, logger: Logger) -> Datavars:
|
|
|
return Datavars(variables_path=vars_path,
|
|
|
logger=logger)
|
|
|
|
|
|
def _get_commands_descriptions(self, commands_path: str
|
|
|
) -> Dict[str, Command]:
|
|
|
'''Метод для получения совокупности описаний команд.'''
|
|
|
output = {}
|
|
|
package = ".".join(commands_path.split("/"))
|
|
|
|
|
|
for entry in os.scandir(commands_path):
|
|
|
if (not entry.name.endswith('.py')
|
|
|
or entry.name in {"commands.py", "__init__.py"}):
|
|
|
continue
|
|
|
module_name = entry.name[:-3]
|
|
|
try:
|
|
|
module = importlib.import_module("{}.{}".format(package,
|
|
|
module_name))
|
|
|
for obj_name in dir(module):
|
|
|
obj = module.__getattribute__(obj_name)
|
|
|
if isinstance(obj, Command):
|
|
|
output[obj.id] = obj
|
|
|
except Exception:
|
|
|
continue
|
|
|
return output
|
|
|
|
|
|
def make_command(self, command_id: str, ) -> int:
|
|
|
'''Метод для создания команды по ее описанию.'''
|
|
|
command_description = self.commands[command_id]
|
|
|
|
|
|
def _get_worker_object(self, wid: Optional[int] = None) -> Worker:
|
|
|
'''Метод для получения воркера для команды.'''
|
|
|
if wid is not None:
|
|
|
worker = Worker(wid, self._event_loop, self._datavars)
|
|
|
self._workers[wid] = worker
|
|
|
elif not self._workers:
|
|
|
worker = Worker(0, self._event_loop, self._datavars)
|
|
|
self._workers[0] = worker
|
|
|
else:
|
|
|
wid = max(self._workers.keys()) + 1
|
|
|
worker = Worker(wid, self._event_loop, self._datavars)
|
|
|
self._workers[wid] = worker
|
|
|
return worker
|