import requests import logging import time from concurrent.futures import ThreadPoolExecutor, as_completed from rest_framework.response import Response from rest_framework.views import APIView from collections import defaultdict from .models import ScannedCode from .serializers import ScannedCodeSerializer # Константы API URL и креденшелы LOGIN_URL_ASPU = "http://192.168.254.10:3428/api/login" API_URL_ASPU_MANAGEMENT = "http://192.168.254.10:3428/api/Management/" API_URL_MANAGEMENT_DEVIN = "http://192.168.254.20:3428/api/Management/" API_URL_MANAGEMENT_JR = "http://192.168.254.30:3428/api/Management/" API_URL_MANAGEMENT_5L = "http://192.168.254.40:3428/api/Management/" API_URL_MANAGEMENT_19L = "http://192.168.254.50:3428/api/Management/" API_URL_ASPU_MASSAGE_LIST_SIPA = "http://192.168.254.10:3428/api/Messages/" API_URL_ASPU_MASSAGE_LIST_DEVIN = "http://192.168.254.20:3428/api/Messages/" API_URL_ASPU_MASSAGE_LIST_JR = "http://192.168.254.30:3428/api/Messages/" API_URL_ASPU_MASSAGE_LIST_5L = "http://192.168.254.40:3428/api/Messages/" API_URL_ASPU_MASSAGE_LIST_19L = "http://192.168.254.50:3428/api/Messages/" USERNAME = "superuser" PASSWORD = "Superuser1105" # Глобальные переменные для хранения токена token_cache = {"token": None, "timestamp": 0} TOKEN_LIFETIME = 1440 * 60 # 24 часа в секундах def get_new_token(url): """Получение нового токена с кешированием.""" global token_cache current_time = time.time() if token_cache["token"] and (current_time - token_cache["timestamp"] < TOKEN_LIFETIME): return token_cache["token"] payload = {"UserName": USERNAME, "Password": PASSWORD} try: response = requests.post(url, json=payload, timeout=5) response_data = response.json() if response.status_code == 200 and response_data.get("IsSuccess"): token_cache["token"] = response_data["Value"]["Token"] token_cache["timestamp"] = current_time return token_cache["token"] logging.error(f"Ошибка получения токена: {response_data}") return None except requests.RequestException as e: logging.error(f"Ошибка сети при получении токена: {str(e)}") return None def request_to_api(url, token, payload=None, timeout=10): """Отправка запроса к API.""" headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} try: response = requests.post(url, json=payload or {}, headers=headers, timeout=timeout) response.raise_for_status() return response.json() except requests.Timeout: logging.error(f"Тайм-аут при запросе {url}") except requests.RequestException as e: logging.error(f"Ошибка запроса {url}: {str(e)}") return None def extract_product_id(text): """Функция извлечения идентификатора продукта из текста.""" import re match = re.search(r'Product\s*ID:\s*(\d+)', text) return match.group(1) if match else None def create_response(status, message=None, data=None, status_code=200): """Создание стандартного ответа API.""" return Response({ "status": status, "message": message, "data": data }, status=status_code) class GetManagementAPIView(APIView): """Получение данных управления и сообщений с различных источников.""" def get(self, request): token = get_new_token(LOGIN_URL_ASPU) if not token: return create_response("Error", message="Failed to get token", status_code=500) management_urls = { "Sipa": API_URL_ASPU_MANAGEMENT, "Devin": API_URL_MANAGEMENT_DEVIN, "JR": API_URL_MANAGEMENT_JR, "5L": API_URL_MANAGEMENT_5L, "19L": API_URL_MANAGEMENT_19L } message_urls = { "Sipa": API_URL_ASPU_MASSAGE_LIST_SIPA, "Devin": API_URL_ASPU_MASSAGE_LIST_DEVIN, "JR": API_URL_ASPU_MASSAGE_LIST_JR, "5L": API_URL_ASPU_MASSAGE_LIST_5L, "19L": API_URL_ASPU_MASSAGE_LIST_19L } message_payload = { "skip": 1, "take": 50, "includes": [], "sort": [{"field": "Time", "dir": "desc"}], "filter": {"filters": [], "logic": "and"} } # Используем defaultdict, чтобы избежать KeyError all_data = defaultdict(lambda: { "Name": "", "ShortName": "", "BatchName": "", "Stats": [], "Sources": [], "Gtin": "", "GroupType": "", "Quantity": 0, "Messages": [] }) def process_management_response(key, response_data): """Обработка данных управления.""" if not response_data or "Value" not in response_data: logging.error(f"Некорректный ответ от {key}: {response_data}") return value_data = response_data["Value"] batch_name = value_data.get("BatchName", "") for product in value_data.get("ProductTypes", []): product_id = product.get("Id") if not product_id: continue all_data[product_id].update({ "Name": product.get("Name", ""), "ShortName": product.get("ShortName", ""), "BatchName": batch_name, "Gtin": product.get("Gtin", ""), "GroupType": product.get("GroupType", ""), }) all_data[product_id]["Stats"].extend(product.get("Stats", [])) all_data[product_id]["Sources"].append(key) if product.get("GroupType") == "Pallet": all_data[product_id]["Quantity"] = sum( stat["Value"] for stat in product.get("Stats", []) if stat.get("Type") == "Validated" ) def process_message_response(key, response_data): """Обработка сообщений.""" if not response_data or "Value" not in response_data: logging.error(f"Некорректный ответ от {key}: {response_data}") return for msg in response_data["Value"]: if "Text" not in msg: continue message = { "Id": msg["Id"], "Time": msg["Time"], "Type": msg["Type"], "Text": msg["Text"] } # Добавляем в общий список сообщений for product_id in all_data: all_data[product_id]["Messages"].append(message) with ThreadPoolExecutor(max_workers=10) as executor: futures = { executor.submit(request_to_api, url, token, timeout=2): (key, "management") for key, url in management_urls.items() } futures.update({ executor.submit(request_to_api, url, token, payload=message_payload, timeout=2): (key, "messages") for key, url in message_urls.items() }) for future in as_completed(futures): key, request_type = futures[future] try: response_data = future.result() if request_type == "management": process_management_response(key, response_data) elif request_type == "messages": process_message_response(key, response_data) except Exception as e: logging.error(f"Ошибка обработки {key}: {str(e)}") logging.info(f"Отправляем ответ с {len(all_data)} объектами управления") return create_response("OK", data=dict(all_data)) if all_data else create_response( "Error", message="No data found", status_code=404 )