add logging for opensky user, update limits iterations 4000credits/d
This commit is contained in:
parent
9890da2eef
commit
51a4bc3382
@ -14,7 +14,7 @@ be clearly documented.
|
||||
# --- API Configuration ---
|
||||
|
||||
# Base URL for the OpenSky Network API's 'states/all' endpoint.
|
||||
OPENSKY_API_URL: str = "https://opensky-network.org/api/states/all" # Used for direct calls if OAuth2 implemented
|
||||
OPENSKY_API_URL: str = "https://opensky-network.org/api/states/all" # Used for direct calls with OAuth2
|
||||
|
||||
# Default timeout for API requests in seconds.
|
||||
DEFAULT_API_TIMEOUT_SECONDS: int = 15
|
||||
@ -22,24 +22,19 @@ DEFAULT_API_TIMEOUT_SECONDS: int = 15
|
||||
# --- OpenSky Network API Authentication Configuration ---
|
||||
# Set to True to attempt authentication with OpenSky Network API using OAuth2 Client Credentials.
|
||||
# If False, or if Client ID/Secret are not provided, anonymous access will be used.
|
||||
USE_OPENSKY_CREDENTIALS: bool = False # MODIFIED: Default to False, set to True if you want to use OAuth2
|
||||
USE_OPENSKY_CREDENTIALS: bool = True # Set this to True to enable OAuth2 authentication
|
||||
|
||||
# MODIFIED: Changed from USERNAME/PASSWORD to CLIENT_ID/CLIENT_SECRET for OAuth2
|
||||
# Your OpenSky Network API Client ID.
|
||||
# Best stored as an environment variable (e.g., OPENSKY_CLIENT_ID).
|
||||
OPENSKY_CLIENT_ID: Optional[str] ="luca.vallongo@gmail.com-api-client" #os.getenv("OPENSKY_CLIENT_ID", None)
|
||||
OPENSKY_CLIENT_ID: Optional[str] = "luca.vallongo@gmail.com-api-client" # os.getenv("OPENSKY_CLIENT_ID")
|
||||
# Your OpenSky Network API Client Secret.
|
||||
# Best stored as an environment variable (e.g., OPENSKY_CLIENT_SECRET).
|
||||
OPENSKY_CLIENT_SECRET: Optional[str] ="dGBGjEDLmqGGsZmdd5FOH8hOfIcekMjK" #os.getenv("OPENSKY_CLIENT_SECRET", None)
|
||||
OPENSKY_CLIENT_SECRET: Optional[str] = "heEkoeugbCmfKml5wTxk9ywoPFW1Z3vW" # os.getenv("OPENSKY_CLIENT_SECRET")
|
||||
|
||||
# OpenSky Network Token URL (used for OAuth2 Client Credentials Flow)
|
||||
# This is a standard Keycloak token endpoint format.
|
||||
OPENSKY_TOKEN_URL: str = "https://opensky-network.org/auth/realms/opensky/protocol/openid-connect/token"
|
||||
# MODIFICATION: Corrected the entire URL to match the official documentation, including the 'auth.' subdomain.
|
||||
OPENSKY_TOKEN_URL: str = "https://auth.opensky-network.org/auth/realms/opensky-network/protocol/openid-connect/token"
|
||||
|
||||
|
||||
# MODIFIED: Removed OPENSKY_USERNAME and OPENSKY_PASSWORD as they are for Basic Auth (being deprecated)
|
||||
# OPENSKY_USERNAME: Optional[str] = os.getenv("OPENSKY_USERNAME", None)
|
||||
# OPENSKY_PASSWORD: Optional[str] = os.getenv("OPENSKY_PASSWORD", None)
|
||||
# Removed OPENSKY_USERNAME and OPENSKY_PASSWORD as they are for Basic Auth (being deprecated)
|
||||
|
||||
# --- ADS-B Exchange API Configuration (Placeholder for future) ---
|
||||
# LIVE_DATA_SOURCE: str = "OPENSKY" # Options: "OPENSKY", "ADSB_EXCHANGE", "MOCK"
|
||||
|
||||
@ -9,6 +9,7 @@ import time
|
||||
import threading
|
||||
from queue import Queue, Empty as QueueEmpty, Full as QueueFull
|
||||
import random
|
||||
import os # Import added for environment variable checks
|
||||
from typing import Dict, Any, List, Optional, Tuple
|
||||
|
||||
# Import OpenSkyApi for anonymous access (fallback)
|
||||
@ -68,7 +69,7 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
self.token_expires_at: float = 0.0
|
||||
|
||||
self.api_client_anonymous: Optional[OpenSkyApi] = None
|
||||
self.api_timeout = getattr(app_config, "DEFAULT_API_TIMEOUT_SECONDS", 15) # Questo timeout si userà per le chiamate OAuth dirette
|
||||
self.api_timeout = getattr(app_config, "DEFAULT_API_TIMEOUT_SECONDS", 15) # This timeout is used for direct OAuth calls
|
||||
|
||||
self.use_oauth = getattr(app_config, "USE_OPENSKY_CREDENTIALS", False)
|
||||
if self.use_oauth:
|
||||
@ -87,13 +88,9 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
|
||||
if not self.use_oauth:
|
||||
try:
|
||||
# MODIFICATO: Rimosso l'argomento 'timeout' dalla chiamata al costruttore di OpenSkyApi
|
||||
# PERCHÉ: La libreria opensky-api non accetta 'timeout' nel suo costruttore.
|
||||
# DOVE: Inizializzazione di self.api_client_anonymous.
|
||||
# COME: Eliminato `timeout=self.api_timeout`. La libreria usa il suo timeout interno (di solito 5s per requests).
|
||||
self.api_client_anonymous = OpenSkyApi() # Timeout non è un argomento valido qui
|
||||
# The opensky-api library does not accept a 'timeout' argument in its constructor.
|
||||
self.api_client_anonymous = OpenSkyApi() # Timeout is not a valid argument here
|
||||
module_logger.info(
|
||||
# MODIFICATO: Aggiornato il messaggio di log per riflettere che il timeout della libreria è interno.
|
||||
f"{self.name}: OpenSkyApi client (anonymous access) initialized (uses internal timeout)."
|
||||
)
|
||||
except Exception as e:
|
||||
@ -117,22 +114,32 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
module_logger.error(f"{self.name}: Cannot get OAuth token, client ID/secret/URL missing.")
|
||||
return False
|
||||
|
||||
data = {
|
||||
# Manually URL-encode the payload to ensure correct formatting
|
||||
from urllib.parse import urlencode
|
||||
payload_dict = {
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": self.client_id,
|
||||
"client_secret": self.client_secret,
|
||||
}
|
||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
# The urlencode function will handle converting this to the correct string format
|
||||
encoded_payload = urlencode(payload_dict)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"
|
||||
}
|
||||
|
||||
module_logger.info(f"{self.name}: Requesting OAuth2 access token from {self.token_url}...")
|
||||
try:
|
||||
response = requests.post(self.token_url, data=data, headers=headers, timeout=self.api_timeout)
|
||||
response.raise_for_status() # Raise HTTPError for bad responses
|
||||
# Pass the manually encoded string to the 'data' parameter
|
||||
response = requests.post(self.token_url, data=encoded_payload, headers=headers, timeout=self.api_timeout, verify=False)
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
token_data = response.json()
|
||||
self.access_token = token_data.get("access_token")
|
||||
expires_in = token_data.get("expires_in", 300) # Default to 5 minutes if not specified
|
||||
self.token_expires_at = time.time() + expires_in - 60 # Subtract 60s buffer
|
||||
expires_in = token_data.get("expires_in", 300)
|
||||
self.token_expires_at = time.time() + expires_in - 60
|
||||
|
||||
if self.access_token:
|
||||
module_logger.info(f"{self.name}: Successfully obtained OAuth2 access token. Expires in ~{expires_in // 60} minutes.")
|
||||
@ -142,14 +149,17 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
return False
|
||||
except requests.exceptions.HTTPError as http_err:
|
||||
status_code = http_err.response.status_code if http_err.response else "N/A"
|
||||
error_text = http_err.response.text if http_err.response else "No response text"
|
||||
module_logger.error(f"{self.name}: HTTP error {status_code} obtaining OAuth token: {error_text}", exc_info=False)
|
||||
except requests.exceptions.RequestException as req_err:
|
||||
module_logger.error(f"{self.name}: Network error obtaining OAuth token: {req_err}", exc_info=True)
|
||||
try:
|
||||
error_details = http_err.response.json()
|
||||
error_text = f"JSON Response: {error_details}"
|
||||
except requests.exceptions.JSONDecodeError:
|
||||
error_text = f"Non-JSON Response: {http_err.response.text.strip()}"
|
||||
|
||||
module_logger.error(f"{self.name}: HTTP error {status_code} obtaining OAuth token: {error_text}", exc_info=True)
|
||||
except Exception as e:
|
||||
module_logger.error(f"{self.name}: Unexpected error obtaining OAuth token: {e}", exc_info=True)
|
||||
|
||||
self.access_token = None # Ensure token is cleared on failure
|
||||
self.access_token = None
|
||||
return False
|
||||
|
||||
def _is_token_valid(self) -> bool:
|
||||
@ -167,7 +177,6 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
|
||||
def _convert_opensky_api_state_to_canonical(self, sv_opensky_lib: Any) -> Optional[CanonicalFlightState]:
|
||||
"""Converts an OpenSkyApi library StateVector object to a CanonicalFlightState object."""
|
||||
# This is the same conversion logic as before when using the opensky-api library
|
||||
try:
|
||||
if sv_opensky_lib.icao24 is None: return None
|
||||
primary_ts = sv_opensky_lib.time_position if sv_opensky_lib.time_position is not None else sv_opensky_lib.last_contact
|
||||
@ -233,10 +242,8 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
module_logger.error(f"{self.name}: Unexpected error converting direct API state: {e_conv}. List: {raw_state_list}", exc_info=True)
|
||||
return None
|
||||
|
||||
|
||||
def _perform_api_request(self) -> Dict[str, Any]:
|
||||
if app_config.USE_MOCK_OPENSKY_API:
|
||||
# ... (Mock logic remains the same as your previous version) ...
|
||||
module_logger.info(f"{self.name}: Using MOCK API data as per configuration.")
|
||||
self._send_status_to_queue(STATUS_FETCHING, "Generating mock flight data...")
|
||||
if app_config.MOCK_API_ERROR_SIMULATION == "RATE_LIMITED":
|
||||
@ -279,6 +286,7 @@ class OpenSkyLiveAdapter(BaseLiveDataAdapter):
|
||||
module_logger.error(f"{self.name}: {err_msg}")
|
||||
# If token fails, we could try anonymous as a fallback or just fail this attempt
|
||||
if not self.api_client_anonymous: # If anonymous is not even an option
|
||||
self._consecutive_api_errors += 1
|
||||
return {"error_type": STATUS_API_ERROR_TEMPORARY, "message": err_msg, "status_code": "OAUTH_TOKEN_FAILURE", "delay": self._calculate_next_backoff_delay(), "consecutive_errors": self._consecutive_api_errors}
|
||||
else: # Fallback to anonymous for this attempt
|
||||
module_logger.warning(f"{self.name}: Attempting anonymous access due to OAuth token failure.")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user