feat(api-client): implement session management for AdvowareAPI and EspoCRMAPI

This commit is contained in:
bsiggel
2026-03-03 17:24:35 +00:00
parent 69a48f5f9a
commit a53051ea8e
2 changed files with 201 additions and 176 deletions

View File

@@ -73,6 +73,17 @@ class AdvowareAPI:
self.logger.info("AdvowareAPI initialized")
self._session: Optional[aiohttp.ClientSession] = None
async def _get_session(self) -> aiohttp.ClientSession:
if self._session is None or self._session.closed:
self._session = aiohttp.ClientSession()
return self._session
async def close(self) -> None:
if self._session and not self._session.closed:
await self._session.close()
def _generate_hmac(self, request_time_stamp: str, nonce: Optional[str] = None) -> str:
"""Generate HMAC-SHA512 signature for authentication"""
if not nonce:
@@ -260,7 +271,7 @@ class AdvowareAPI:
# Use 'data' parameter if provided, otherwise 'json_data'
json_payload = data if data is not None else json_data
async with aiohttp.ClientSession(timeout=effective_timeout) as session:
session = await self._get_session()
try:
with self.logger.api_call(endpoint, method):
async with session.request(
@@ -268,7 +279,8 @@ class AdvowareAPI:
url,
headers=effective_headers,
params=params,
json=json_payload
json=json_payload,
timeout=effective_timeout
) as response:
# Handle 401 - retry with fresh token
if response.status == 401:
@@ -281,7 +293,8 @@ class AdvowareAPI:
url,
headers=effective_headers,
params=params,
json=json_payload
json=json_payload,
timeout=effective_timeout
) as retry_response:
if retry_response.status == 401:
raise AdvowareAuthError(

View File

@@ -55,6 +55,8 @@ class EspoCRMAPI:
self.logger.info(f"EspoCRM API initialized with base URL: {self.api_base_url}")
self._session: Optional[aiohttp.ClientSession] = None
# Optional Redis for caching/rate limiting (centralized)
self.redis_client = get_redis_client(strict=False)
if self.redis_client:
@@ -70,6 +72,15 @@ class EspoCRMAPI:
'Accept': 'application/json'
}
async def _get_session(self) -> aiohttp.ClientSession:
if self._session is None or self._session.closed:
self._session = aiohttp.ClientSession()
return self._session
async def close(self) -> None:
if self._session and not self._session.closed:
await self._session.close()
async def api_call(
self,
endpoint: str,
@@ -106,7 +117,7 @@ class EspoCRMAPI:
total=timeout_seconds or self.api_timeout_seconds
)
async with aiohttp.ClientSession(timeout=effective_timeout) as session:
session = await self._get_session()
try:
with self.logger.api_call(endpoint, method):
async with session.request(
@@ -114,7 +125,8 @@ class EspoCRMAPI:
url,
headers=headers,
params=params,
json=json_data
json=json_data,
timeout=effective_timeout
) as response:
# Handle errors
if response.status == 401:
@@ -340,9 +352,9 @@ class EspoCRMAPI:
effective_timeout = aiohttp.ClientTimeout(total=self.api_timeout_seconds)
async with aiohttp.ClientSession(timeout=effective_timeout) as session:
session = await self._get_session()
try:
async with session.post(url, headers=headers, data=form_data) as response:
async with session.post(url, headers=headers, data=form_data, timeout=effective_timeout) as response:
self._log(f"Upload response status: {response.status}")
if response.status == 401:
@@ -390,9 +402,9 @@ class EspoCRMAPI:
effective_timeout = aiohttp.ClientTimeout(total=self.api_timeout_seconds)
async with aiohttp.ClientSession(timeout=effective_timeout) as session:
session = await self._get_session()
try:
async with session.get(url, headers=headers) as response:
async with session.get(url, headers=headers, timeout=effective_timeout) as response:
if response.status == 401:
raise EspoCRMAuthError("Authentication failed - check API key")
elif response.status == 403: