48 lines
2.9 KiB
Python
48 lines
2.9 KiB
Python
def _rest_request(self, method: str, endpoint: str, payload: Optional[dict] = None, timeout: Optional[int] = None) -> Optional[Any]:
|
||
method = method.upper()
|
||
if method not in ("POST", "PUT", "DELETE", "PATCH", "GET"):
|
||
self._last_error = f"_rest_request: неподдерживаемый метод {method}"
|
||
return None
|
||
url = f"{self._base}/api/v2.0/{endpoint}"
|
||
t = timeout if timeout is not None else self.valves.request_timeout
|
||
try:
|
||
r = requests.request(method, url, headers=self._headers, json=payload if payload is not None else {}, timeout=t, verify=self.valves.verify_ssl)
|
||
# v2.1.2: автоматический fallback POST → GET при 405 (Method Not Allowed).
|
||
# Это часто встречается в TrueNAS 25.10: некоторые эндпоинты каталога
|
||
# исторически были POST, но в новых версиях стали GET.
|
||
if r.status_code == 405 and method == "POST":
|
||
try:
|
||
r2 = requests.get(url, headers=self._headers, params=payload or {}, timeout=t, verify=self.valves.verify_ssl)
|
||
if r2.status_code in (200, 201, 202, 204):
|
||
if not r2.text:
|
||
return {"status": "ok", "http_code": r2.status_code, "via": "GET-fallback"}
|
||
try:
|
||
data = r2.json()
|
||
if isinstance(data, dict):
|
||
data["_via"] = "GET-fallback"
|
||
return data
|
||
except Exception:
|
||
return {"status": "ok", "text": r2.text, "http_code": r2.status_code, "_via": "GET-fallback"}
|
||
except Exception:
|
||
pass # вернёмся к исходной ошибке ниже
|
||
if r.status_code in (200, 201, 202, 204):
|
||
if not r.text:
|
||
return {"status": "ok", "http_code": r.status_code}
|
||
try:
|
||
return r.json()
|
||
except Exception:
|
||
return {"status": "ok", "text": r.text, "http_code": r.status_code}
|
||
self._last_error = f"{method} {endpoint} → HTTP {r.status_code}: {r.text[:400]}"
|
||
return None
|
||
except requests.exceptions.SSLError as e:
|
||
self._last_error = f"SSL-ошибка {method} {endpoint}: {e}"
|
||
return None
|
||
except requests.exceptions.ConnectionError as e:
|
||
self._last_error = f"Соединение {method} {endpoint}: {e}"
|
||
return None
|
||
except requests.exceptions.Timeout:
|
||
self._last_error = f"Таймаут {method} {endpoint} (> {t}с)"
|
||
return None
|
||
except Exception as e:
|
||
self._last_error = f"{method} {endpoint}: {type(e).__name__}: {e}"
|
||
return None |