You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
2.6 KiB
Python

"""Реализация клиента для сервера метрик"""
import socket
from time import time
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Dict, List, Optional, Tuple
class ClientError(Exception):
"""Общий класс исключений клиента"""
...
class ClientSocketError(ClientError):
"""Исключение, выбрасываемое клиентом при сетевой ошибке"""
...
class ClientProtocolError(ClientError):
"""Исключение, выбрасываемое клиентом при ошибке протокола"""
...
class Client:
"""Класс клиент для сервера метрик"""
def __init__(
self, host: "str", port: "int", timeout: "Optional[int]" = None
):
"""Конструктор класса"""
self.connection: "Tuple[str,int]" = (host, port)
self.timeout: "Optional[int]" = timeout
def send(self, cmd: "str") -> "str":
"""Отправка команд серверу"""
data: "bytes" = b""
try:
with socket.create_connection(
self.connection, self.timeout
) as sock:
sock.sendall(cmd.encode("utf8"))
while not data.endswith(b"\n\n"):
data += sock.recv(1024)
except socket.error as err:
raise ClientSocketError("error create connection", err) from err
status, payload = data.decode("utf-8").split("\n", 1)
payload: "str" = payload.strip()
if status == "error":
raise ClientProtocolError(payload)
return payload
def put(
self, metric: "str", value: "float", timestamp: "Optional[int]" = None
) -> "None":
"""Метод отправки данных"""
self.send(
f"put {metric} {value} {timestamp if timestamp else int(time())}\n"
)
def get(self, metric: "str") -> "Dict[str,List[Tuple[int,float]]]":
"""Метод получения данных"""
result: "Dict[str,List[Tuple[int,float]]]" = {}
for line in self.send(f"get {metric}\n").splitlines():
try:
_metric, value, timestamp = line.split()
if not _metric in result:
result[_metric] = []
result[_metric].append((int(timestamp), float(value)))
except ValueError as error:
raise ClientProtocolError(line) from error
for item in result.items():
item[1].sort(key=lambda stamp: stamp[0])
return result