59 lines
2.0 KiB
Python
59 lines
2.0 KiB
Python
import threading
|
|
import time
|
|
import uuid
|
|
|
|
import requests
|
|
|
|
from app.modules.shared.gigachat.errors import GigaChatError
|
|
from app.modules.shared.gigachat.settings import GigaChatSettings
|
|
|
|
|
|
class GigaChatTokenProvider:
|
|
def __init__(self, settings: GigaChatSettings) -> None:
|
|
self._settings = settings
|
|
self._lock = threading.Lock()
|
|
self._token: str | None = None
|
|
self._expires_at_ms: float = 0
|
|
|
|
def get_access_token(self) -> str:
|
|
now_ms = time.time() * 1000
|
|
with self._lock:
|
|
if self._token and self._expires_at_ms - 300_000 > now_ms:
|
|
return self._token
|
|
|
|
token, expires_at = self._fetch_token()
|
|
with self._lock:
|
|
self._token = token
|
|
self._expires_at_ms = expires_at
|
|
return token
|
|
|
|
def _fetch_token(self) -> tuple[str, float]:
|
|
if not self._settings.credentials:
|
|
raise GigaChatError("GIGACHAT_TOKEN is not set")
|
|
headers = {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
"Accept": "application/json",
|
|
"Authorization": f"Basic {self._settings.credentials}",
|
|
"RqUID": str(uuid.uuid4()),
|
|
}
|
|
try:
|
|
response = requests.post(
|
|
self._settings.auth_url,
|
|
headers=headers,
|
|
data=f"scope={self._settings.scope}",
|
|
timeout=30,
|
|
verify=self._settings.ssl_verify,
|
|
)
|
|
except requests.RequestException as exc:
|
|
raise GigaChatError(f"GigaChat auth request failed: {exc}") from exc
|
|
|
|
if response.status_code >= 400:
|
|
raise GigaChatError(f"GigaChat auth error {response.status_code}: {response.text}")
|
|
|
|
payload = response.json()
|
|
token = payload.get("access_token")
|
|
expires_at = float(payload.get("expires_at", 0))
|
|
if not token:
|
|
raise GigaChatError("GigaChat auth: no access_token in response")
|
|
return token, expires_at
|