#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Сервер для управления данными бизнес-объединений ДНР. Поддерживает: - GET /data.json - получение данных - POST /save - сохранение данных в файл - POST /reset - сброс к дефолтным данным (загружает из data.default.json) """ import http.server import socketserver import json import os import shutil from urllib.parse import urlparse PORT = 8092 DATA_FILE = 'data.json' DEFAULT_DATA_FILE = 'data.default.json' # Дефолтные данные вынесены в отдельный файл data.default.json # Если нужно создать файл с дефолтом - раскомментировать функцию ниже class CustomHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): def end_headers(self): self.send_header('Access-Control-Allow-Origin', '*') self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') self.send_header('Access-Control-Allow-Headers', 'Content-Type') super().end_headers() def do_OPTIONS(self): self.send_response(200) self.end_headers() def do_GET(self): parsed_path = urlparse(self.path) # Отдаём data.json if parsed_path.path == '/data.json': self.send_response(200) self.send_header('Content-Type', 'application/json; charset=utf-8') self.end_headers() try: with open(DATA_FILE, 'r', encoding='utf-8') as f: self.wfile.write(f.read().encode('utf-8')) except FileNotFoundError: self.send_error(404, 'data.json not found') return # Отдаём index.html if parsed_path.path == '/' or parsed_path.path == '/index.html': self.path = '/index.html' # Статические файлы if self.path.endswith('.html'): self.send_response(200) self.send_header('Content-Type', 'text/html; charset=utf-8') self.end_headers() try: with open(self.path[1:], 'rb') as f: self.wfile.write(f.read()) except FileNotFoundError: self.send_error(404, 'File not found') return super().do_GET() def do_POST(self): parsed_path = urlparse(self.path) # Сохранение данных if parsed_path.path == '/save': content_length = int(self.headers.get('Content-Length', 0)) post_data = self.rfile.read(content_length) try: data = json.loads(post_data.decode('utf-8')) with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) self.send_response(200) self.send_header('Content-Type', 'application/json') self.end_headers() response = json.dumps({'success': True, 'message': 'Данные сохранены'}) self.wfile.write(response.encode('utf-8')) except json.JSONDecodeError as e: self.send_response(400) self.send_header('Content-Type', 'application/json') self.end_headers() response = json.dumps({'success': False, 'message': f'Ошибка JSON: {str(e)}'}) self.wfile.write(response.encode('utf-8')) except Exception as e: self.send_response(500) self.send_header('Content-Type', 'application/json') self.end_headers() response = json.dumps({'success': False, 'message': f'Ошибка сервера: {str(e)}'}) self.wfile.write(response.encode('utf-8')) return # Сброс к дефолту (если есть файл data.default.json) if parsed_path.path == '/reset': try: if os.path.exists(DEFAULT_DATA_FILE): shutil.copy(DEFAULT_DATA_FILE, DATA_FILE) self.send_response(200) self.send_header('Content-Type', 'application/json') self.end_headers() response = json.dumps({'success': True, 'message': 'Данные сброшены к исходным'}) self.wfile.write(response.encode('utf-8')) else: self.send_response(404) self.send_header('Content-Type', 'application/json') self.end_headers() response = json.dumps({'success': False, 'message': 'Файл с дефолтными данными не найден'}) self.wfile.write(response.encode('utf-8')) except Exception as e: self.send_response(500) self.send_header('Content-Type', 'application/json') self.end_headers() response = json.dumps({'success': False, 'message': str(e)}) self.wfile.write(response.encode('utf-8')) return self.send_response(404) self.end_headers() def log_message(self, format, *args): print(f"[{self.address_string()}] {format % args}") def ensure_data_file(): """Проверяет наличие data.json, если нет - создаёт из дефолта или пустой""" if not os.path.exists(DATA_FILE): if os.path.exists(DEFAULT_DATA_FILE): shutil.copy(DEFAULT_DATA_FILE, DATA_FILE) print(f"📄 Создан файл данных из {DEFAULT_DATA_FILE}") else: # Создаём минимальный пустой файл empty_data = { "organizations": [], "additionalOrganizations": [], "metadata": {"lastUpdated": "2026-01-15", "totalOrganizations": 0} } with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(empty_data, f, ensure_ascii=False, indent=2) print(f"📄 Создан пустой файл данных: {DATA_FILE}") print(f"⚠️ Для работы с данными создайте файл {DEFAULT_DATA_FILE} с дефолтными данными") def run_server(): os.chdir(os.path.dirname(os.path.abspath(__file__))) ensure_data_file() with socketserver.TCPServer(("", PORT), CustomHTTPRequestHandler) as httpd: print("=" * 60) print(f"🚀 Сервер запущен!") print(f"📁 Директория: {os.getcwd()}") print(f"🌐 Локальный доступ: http://localhost:{PORT}") print(f"📄 Файл данных: {DATA_FILE}") print(f"📄 Дефолтный файл (если есть): {DEFAULT_DATA_FILE}") print(f"⏹️ Для остановки сервера нажмите Ctrl+C") print("=" * 60) try: httpd.serve_forever() except KeyboardInterrupt: print("\n🛑 Сервер остановлен.") httpd.shutdown() if __name__ == "__main__": run_server()