diff --git a/solution.py b/solution.py index 0e8a391..285ed47 100644 --- a/solution.py +++ b/solution.py @@ -1,18 +1,31 @@ -import asyncio -import requests -import json +from dataclasses import dataclass +from asyncio import Task from typing import List + +import asyncio import os import configparser import aiohttp import aiofiles -async def write_config_files( - hosts: list, path_to_template_file: str, path_to_config_dir: str, template: str -) -> None: +@dataclass(frozen=True) +class Config: + """Класс для хранения конфига сервиса.""" + + template: str + path_for_config: str + frequency_sec: int + central_host_url: str + requests_count: int + request_portion: int + + +async def write_config_files(hosts: list, cfg: Config, template: str) -> None: """Записываем конфиги для списка hosts.""" - full_path_to_config_dir: str = os.path.abspath(path_to_config_dir) + + full_path_to_config_dir: str = os.path.abspath(cfg.path_for_config) + if not os.path.isdir(full_path_to_config_dir): os.mkdir(full_path_to_config_dir) @@ -32,7 +45,7 @@ def _get_template(templ_file: str) -> str: """Возвращает шаблон конфига для хоста из файла `templ_file`.""" template: str = "" - with open(templ_file, "r") as file: + with open(templ_file, mode="r", encoding="utf8") as file: template = file.read() return template @@ -41,61 +54,54 @@ def _get_template(templ_file: str) -> str: async def get_records_count(session, server) -> int: """Возвращает количество записей в базе.""" async with session.get(f"{server}/count") as resp: - r = await resp.json() - count: int = int(r["result"]) + resp = await resp.json() + count: int = int(resp["result"]) return count -async def get_tasks(session, server, count, body, request_portion) -> list: +async def get_tasks(cfg: Config, session: aiohttp.ClientSession, count, body) -> list: """Вернет список запросов к API. Функция не ограничивает кол-во запросов, это нужно сделать до вызова, чтобы передать корректный `session`. """ - tasks = [] + tasks: List[Task] = [] offset = 0 - for r in range(count // request_portion + 1): + url = f"{cfg.central_host_url}/get" + + for _ in range(count // cfg.request_portion + 1): if offset < count: print(f"{offset=}") - tasks.append(asyncio.create_task(session.get(f"{server}/get", json=body))) - offset += request_portion + tasks.append(asyncio.create_task(session.get(url, json=body))) + offset += cfg.request_portion body["offset"] = offset print(f"{count=}") return tasks -# изменить сигнатуру на (cfg: Conifg, json_body: dict) -async def send_async_request(cfg: dict, columns: list, limit: int = 1) -> None: - request_portion = 10 - requests_count = 10 - server = cfg["central_host_url"] - path_to_template_file = cfg["template"] - path_for_config = cfg["path_for_config"] - - template: str = _get_template(path_to_template_file) +async def send_async_request(cfg: Config, json_body: dict) -> None: + """Начать серию запросов.""" + template: str = _get_template(cfg.template) # ограничим одновременное число запросов - conn = aiohttp.TCPConnector(limit=requests_count) + conn = aiohttp.TCPConnector(limit=cfg.requests_count) async with aiohttp.ClientSession(connector=conn) as session: # всего записей в базе - count = await get_records_count(session, server) + count = await get_records_count(session, cfg.central_host_url) - body = body = {"columns": columns, "limit": request_portion, "offset": 0} - tasks = await get_tasks(session, server, count, body, request_portion) + tasks = await get_tasks(cfg, session, count, json_body) responses = await asyncio.gather(*tasks) for response in responses: - r = await response.json() - hosts = [i["hostname"] for i in r.get("result")] - await write_config_files( - hosts, path_to_template_file, path_for_config, template - ) + resp = await response.json() + hosts = [i["hostname"] for i in resp.get("result")] + await write_config_files(hosts, cfg, template) -def read_config(path_to_conf_file: str, section: str = "Main") -> dict: +def read_config(path_to_conf_file: str, section: str = "Main") -> Config: """ Считать конфиг с помощью `configparser`. @@ -123,18 +129,26 @@ def read_config(path_to_conf_file: str, section: str = "Main") -> dict: if section not in config.sections(): raise KeyError(f"Section {section} not found in config file!") - return dict(config.items(section)) + conf = dict(config.items(section)) + return Config( + template=conf["template"], + path_for_config=conf["path_for_config"], + frequency_sec=int(conf["frequency_sec"]), + central_host_url=conf["central_host_url"], + requests_count=int(conf["requests_count"]), + request_portion=int(conf["request_portion"]), + ) -async def main() -> None: - - cnf = read_config("service.conf") - wait_sec: int = int(cnf["frequency_sec"]) +async def main() -> None: + """Точка входа.""" + cfg: Config = read_config("service.conf") while True: - await send_async_request(cnf, columns=["hostname"], limit=10) - await asyncio.sleep(wait_sec) + body = {"columns": "['hostname']", "limit": cfg.request_portion, "offset": 0} + await send_async_request(cfg, json_body=body) + await asyncio.sleep(cfg.frequency_sec) if __name__ == "__main__":