-
Notifications
You must be signed in to change notification settings - Fork 388
Expand file tree
/
Copy pathmain.py
More file actions
187 lines (157 loc) · 6.87 KB
/
main.py
File metadata and controls
187 lines (157 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
from datetime import datetime
import os
from contextlib import contextmanager, asynccontextmanager
import mysql.connector
from fastapi import FastAPI, Request, Depends, Header, HTTPException
from typing import Optional
# --- 1. Конфигурация ---
# Считываем конфигурацию БД из переменных окружения
db_host = os.environ.get('DB_HOST', '127.0.0.1')
db_user = os.environ.get('DB_USER', 'app')
db_password = os.environ.get('DB_PASSWORD', 'very_strong')
db_name = os.environ.get('DB_NAME', 'example')
@asynccontextmanager
async def lifespan(app: FastAPI):
# Код, который выполнится перед запуском приложения
print("Приложение запускается...")
if ensure_table_exists():
print("Соединение с БД установлено и таблица 'requests' готова к работе.")
else:
print("БД недоступна при старте. Таблица будет создана при первом запросе.")
yield
# Код, который выполнится при остановке приложения
print("Приложение останавливается.")
# Создаем экземпляр FastAPI с использованием lifespan
app = FastAPI(
title="Shvirtd Example FastAPI",
description="Учебный проект, FastAPI+Docker.",
version="1.0.0",
lifespan=lifespan
)
# --- 2. Управление соединением с БД ---
@contextmanager
def get_db_connection():
db = None
try:
db = mysql.connector.connect(
host=db_host,
user=db_user,
password=db_password,
database=db_name
)
yield db
finally:
if db is not None and db.is_connected():
db.close()
# --- 2.1. Функция создания таблицы ---
def ensure_table_exists():
"""Создает таблицу requests если она не существует"""
try:
with get_db_connection() as db:
cursor = db.cursor()
create_table_query = f"""
CREATE TABLE IF NOT EXISTS {db_name}.requests (
id INT AUTO_INCREMENT PRIMARY KEY,
request_date DATETIME,
request_ip VARCHAR(255)
)
"""
cursor.execute(create_table_query)
db.commit()
cursor.close()
return True
except mysql.connector.Error as err:
print(f"Ошибка при создании таблицы: {err}")
return False
# --- 3. Зависимость для получения IP ---
def get_client_ip(x_real_ip: Optional[str] = Header(None)):
return x_real_ip
# --- 5. Основной эндпоинт ---
@app.get("/")
def index(request: Request, ip_address: Optional[str] = Depends(get_client_ip)):
final_ip = ip_address # Только из X-Forwarded-For, без fallback
now = datetime.now()
current_time = now.strftime("%Y-%m-%d %H:%M:%S")
try:
with get_db_connection() as db:
cursor = db.cursor()
query = "INSERT INTO requests (request_date, request_ip) VALUES (%s, %s)"
values = (current_time, final_ip)
cursor.execute(query, values)
db.commit()
cursor.close()
except mysql.connector.Error as err:
ensure_table_exists()
with get_db_connection() as db:
cursor = db.cursor()
query = "INSERT INTO requests (request_date, request_ip) VALUES (%s, %s)"
values = (current_time, final_ip)
cursor.execute(query, values)
db.commit()
cursor.close()
# Подсказка для студентов при неправильном обращении
if final_ip is None:
ip_display = "похоже, что вы направляете запрос в неверный порт(например curl http://127.0.0.1:5000). Правильное выполнение задания - отправить запрос в порт 8090."
else:
ip_display = final_ip
return f'TIME: {current_time}, IP: {ip_display}'
# --- 5. Отладочный эндпоинт ---
@app.get("/debug")
def debug_headers(request: Request):
"""Показывает все заголовки для отладки откуда берется IP"""
return {
"headers": dict(request.headers),
"client_host": request.client.host if request.client else None,
"x_forwarded_for": request.headers.get('x-forwarded-for'),
"real_ip": request.headers.get('x-real-ip'),
"forwarded": request.headers.get('forwarded')
}
# --- 6. Эндпоинт для просмотра записей в БД ---
@app.get("/requests")
def get_requests():
"""Возвращает все записи из таблицы requests для проверки"""
try:
with get_db_connection() as db:
cursor = db.cursor()
query = "SELECT id, request_date, request_ip FROM requests ORDER BY id DESC LIMIT 50"
cursor.execute(query)
records = cursor.fetchall()
cursor.close()
# Преобразуем записи в читабельный формат
result = []
for record in records:
result.append({
"id": record[0],
"request_date": record[1].strftime("%Y-%m-%d %H:%M:%S") if record[1] else None,
"request_ip": record[2]
})
return {
"total_records": len(result),
"records": result
}
except mysql.connector.Error as err:
ensure_table_exists()
with get_db_connection() as db:
cursor = db.cursor()
query = "SELECT id, request_date, request_ip FROM requests ORDER BY id DESC LIMIT 50"
cursor.execute(query)
records = cursor.fetchall()
cursor.close()
# Преобразуем записи в читабельный формат
result = []
for record in records:
result.append({
"id": record[0],
"request_date": record[1].strftime("%Y-%m-%d %H:%M:%S") if record[1] else None,
"request_ip": record[2]
})
return {
"total_records": len(result),
"records": result
}
# --- 7. Запуск приложения ---
# Для запуска этого файла используется ASGI-сервер, например, uvicorn.
# Команда: uvicorn main:app --reload
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host='0.0.0.0', port=5000)