Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 171 additions & 1 deletion hw1/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,107 @@
from typing import Any, Awaitable, Callable
import json
import urllib.parse


async def handle_factorial(query_string: str) -> tuple[int, dict[str, Any]]:
"""Обрабатывает запрос /factorial?n=<number>."""
status = 200
response_body = {"result": None}

if not query_string:
status = 422
response_body = {"error": "Missing parameter 'n'"}
else:
params = urllib.parse.parse_qs(query_string)
if "n" not in params or len(params["n"]) != 1:
status = 422
response_body = {"error": "Invalid parameter 'n'"}
else:
try:
n = int(params["n"][0])
if n < 0:
status = 400
response_body = {"error": "Parameter 'n' must be non-negative"}
else:
# Вычисляем факториал
result = 1
for i in range(1, n + 1):
result *= i
response_body = {"result": result}
except ValueError:
status = 422
response_body = {"error": "Parameter 'n' must be an integer"}

return status, response_body


async def handle_fibonacci(path: str) -> tuple[int, dict[str, Any]]:
"""Обрабатывает запрос /fibonacci/<n>."""
status = 200
response_body = {"result": None}

try:
n = int(path.split("/")[-1])
if n < 0:
status = 400
response_body = {"error": "Parameter must be non-negative"}
else:
# Вычисляем число Фибоначчи
if n == 0:
result = 0
elif n == 1:
result = 1
else:
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
result = b
response_body = {"result": result}
except ValueError:
status = 422
response_body = {"error": "Parameter must be an integer"}

return status, response_body


async def handle_mean(
receive: Callable[[], Awaitable[dict[str, Any]]],
) -> tuple[int, dict[str, Any]]:
"""Обрабатывает запрос /mean с JSON в теле запроса."""
status = 200
response_body = {"result": None}

message = await receive()
if message["type"] != "http.request":
status = 422
response_body = {"error": "Invalid request format"}
else:
body = message.get("body", b"")
if not body:
status = 422
response_body = {"error": "Missing numbers"}
else:
try:
numbers = json.loads(body)
if not isinstance(numbers, list):
status = 422
response_body = {"error": "Input must be a list of numbers"}
elif not numbers:
status = 400
response_body = {"error": "List of numbers cannot be empty"}
else:
try:
numbers = [float(x) for x in numbers]
result = sum(numbers) / len(numbers)
response_body = {"result": result}
except (ValueError, TypeError):
status = 422
response_body = {"error": "All elements must be numbers"}
except json.JSONDecodeError:
status = 422
response_body = {"error": "Invalid JSON format"}

return status, response_body


async def application(
Expand All @@ -12,8 +115,75 @@ async def application(
receive: Корутина для получения сообщений от клиента
send: Корутина для отправки сообщений клиенту
"""
# TODO: Ваша реализация здесь
# Обработка lifespan-сообщений
if scope["type"] == "lifespan":
while True:
message = await receive()
if message["type"] == "lifespan.startup":
await send({"type": "lifespan.startup.complete"})
elif message["type"] == "lifespan.shutdown":
await send({"type": "lifespan.shutdown.complete"})
return

# Проверяем, что это HTTP-запрос
if scope["type"] != "http":
return

# Получаем метод, путь и параметры запроса
method = scope["method"]
path = scope["path"]
query_string = scope["query_string"].decode("utf-8")

# Инициализация ответа
status = 200
response_body = {"result": None}

try:
# Обработка несуществующих эндпоинтов и неподдерживаемых методов
if method != "GET" or (
not path.startswith("/factorial")
and not path.startswith("/fibonacci")
and not path.startswith("/mean")
):
status = 404
response_body = {"error": "Not found"}
else:
if path.startswith("/factorial"):
status, response_body = await handle_factorial(query_string)
elif path.startswith("/fibonacci"):
status, response_body = await handle_fibonacci(path)
elif path.startswith("/mean"):
status, response_body = await handle_mean(receive)

except Exception:
status = 422
response_body = {"error": "Invalid request format"}

# Подготовка ответа
response_bytes = json.dumps(response_body).encode("utf-8")

# Отправка заголовков
await send(
{
"type": "http.response.start",
"status": status,
"headers": [
[b"content-type", b"application/json"],
[b"content-length", str(len(response_bytes)).encode("utf-8")],
],
}
)

# Отправка тела ответа
await send(
{
"type": "http.response.body",
"body": response_bytes,
}
)


if __name__ == "__main__":
import uvicorn

uvicorn.run("app:application", host="0.0.0.0", port=8000, reload=True)
3 changes: 3 additions & 0 deletions hw2/hw/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ pytest>=7.4.0
pytest-asyncio>=0.21.0
httpx>=0.27.2
Faker>=37.8.0

websocket-client==1.8.0
websockets==15.0.1
49 changes: 49 additions & 0 deletions hw2/hw/shop_api/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import sys
import threading
import time

from websocket import create_connection

# Проверяем, что пользователь указал имя комнаты
if len(sys.argv) < 2:
print("Usage: python client.py <chat_name>")
sys.exit(1)

chat_name = sys.argv[1]

# Подключаемся к серверу по WebSocket
ws = create_connection(f"ws://localhost:8000/chat/{chat_name}")
print(f"Connected to chat room: {chat_name}")


def receive_messages():
"""Слушаем сообщения от сервера в отдельном потоке"""
while True:
try:
response = ws.recv() # Получаю сообщение
print(response)
except Exception as e:
print(f"Connection closed: {e}")
break


# Запуск потока для получения сообщений
thread = threading.Thread(target=receive_messages)
thread.daemon = True # Поток завершится, когда программа закончится
thread.start()

# цикл для ввода сообщений
while True:
try:
message = input("Enter message: ")
if message.strip(): # Отправка только непустые сообщения
ws.send(message)
time.sleep(0.1)
except KeyboardInterrupt:
ws.close() # закрытие соединение при Ctrl+C
print("Disconnected from chat")
break
except Exception as e:
print(f"Error: {e}")
ws.close()
break
Loading