mirror of
https://github.com/Retropex/custom-ocean.xyz-dashboard.git
synced 2025-05-13 03:30:46 +02:00
Improve API connectivity and error handling
Updated `MiningDashboardService` in `data_service.py` to enhance API connectivity testing and error handling. Introduced `_api_request_with_retry` for retry logic on API requests, and modified `_test_api_connectivity` to log detailed connectivity test information. Refactored multiple API calls to utilize the new retry method, improving reliability when fetching user hashrate data, pool stats, and other metrics.
This commit is contained in:
parent
c9a2f927ff
commit
0a32b492b8
136
data_service.py
136
data_service.py
@ -46,53 +46,71 @@ class MiningDashboardService:
|
|||||||
def _test_api_connectivity(self):
|
def _test_api_connectivity(self):
|
||||||
"""Test if the new Ocean.xyz Beta API is available."""
|
"""Test if the new Ocean.xyz Beta API is available."""
|
||||||
try:
|
try:
|
||||||
# Add helpful headers
|
# Add helpful headers to increase chances of successful connection
|
||||||
headers = {
|
headers = {
|
||||||
'User-Agent': 'Mozilla/5.0 Mining Dashboard',
|
'User-Agent': 'Mozilla/5.0 Mining Dashboard',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json, text/plain, */*',
|
||||||
'Cache-Control': 'no-cache'
|
'Cache-Control': 'no-cache'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try wallet-specific ping endpoint first since you confirmed it works
|
# Try the wallet-specific ping endpoint first (this is what works)
|
||||||
wallet_ping_url = f"{self.ocean_api_base}/ping/{self.wallet}"
|
wallet_ping_url = f"{self.ocean_api_base}/ping/{self.wallet}"
|
||||||
logging.info(f"Testing Ocean API connectivity with wallet-specific ping: {wallet_ping_url}")
|
logging.info(f"Testing Ocean API connectivity: {wallet_ping_url}")
|
||||||
|
|
||||||
response = self.session.get(wallet_ping_url, headers=headers, timeout=5)
|
response = self.session.get(wallet_ping_url, headers=headers, timeout=5)
|
||||||
if response.ok:
|
if response.ok:
|
||||||
logging.info("Ocean.xyz Beta API is available with wallet-specific ping endpoint")
|
logging.info(f"Ocean.xyz Beta API is available through wallet-specific ping: {response.text[:30]}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# Log the failed attempt details
|
||||||
|
logging.warning(f"Wallet-specific ping failed with status: {response.status_code}, response: {response.text[:100]}")
|
||||||
|
|
||||||
# If wallet-specific ping fails, try standard ping
|
# Try a different endpoint as backup
|
||||||
standard_ping_url = f"{self.ocean_api_base}/ping"
|
|
||||||
logging.info(f"Testing Ocean API with standard ping: {standard_ping_url}")
|
|
||||||
|
|
||||||
response = self.session.get(standard_ping_url, headers=headers, timeout=5)
|
|
||||||
if response.ok and response.text.strip() == "PONG":
|
|
||||||
logging.info("Ocean.xyz Beta API is available with standard ping endpoint")
|
|
||||||
return True
|
|
||||||
|
|
||||||
# If both pings fail, try a wallet-specific endpoint that should return data
|
|
||||||
statsnap_url = f"{self.ocean_api_base}/statsnap/{self.wallet}"
|
statsnap_url = f"{self.ocean_api_base}/statsnap/{self.wallet}"
|
||||||
logging.info(f"Testing Ocean API with statsnap endpoint: {statsnap_url}")
|
logging.info(f"Trying alternate endpoint: {statsnap_url}")
|
||||||
|
|
||||||
response = self.session.get(statsnap_url, headers=headers, timeout=5)
|
response = self.session.get(statsnap_url, headers=headers, timeout=5)
|
||||||
if response.ok:
|
if response.ok:
|
||||||
logging.info("Ocean.xyz Beta API is available with statsnap endpoint")
|
logging.info("Ocean.xyz Beta API is available through statsnap endpoint")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# All attempts failed
|
# Log all failed attempts and return False
|
||||||
logging.error("All Ocean.xyz Beta API connectivity tests failed")
|
logging.error("All Ocean.xyz API connectivity tests failed")
|
||||||
|
logging.error(f"Last response status: {response.status_code}, text: {response.text[:200]}")
|
||||||
# Log the exact URL that you confirmed works for debugging
|
|
||||||
debug_url = f"https://api.ocean.xyz/v1/ping/{self.wallet}"
|
|
||||||
logging.info(f"Note: The URL {debug_url} should work according to user confirmation")
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error testing Ocean.xyz Beta API connectivity: {e}")
|
logging.error(f"Error testing Ocean.xyz Beta API connectivity: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _api_request_with_retry(self, endpoint, timeout=10, retries=3):
|
||||||
|
"""Make an API request with retry logic."""
|
||||||
|
url = f"{self.ocean_api_base}/{endpoint}"
|
||||||
|
logging.info(f"API request: {url}")
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 Mining Dashboard',
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Cache-Control': 'no-cache'
|
||||||
|
}
|
||||||
|
|
||||||
|
for attempt in range(retries):
|
||||||
|
try:
|
||||||
|
response = self.session.get(url, headers=headers, timeout=timeout)
|
||||||
|
if response.ok:
|
||||||
|
return response
|
||||||
|
|
||||||
|
logging.warning(f"API request failed (attempt {attempt+1}/{retries}): {url}, status: {response.status_code}")
|
||||||
|
if attempt < retries - 1:
|
||||||
|
time.sleep(1) # Wait before retry
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"API request exception (attempt {attempt+1}/{retries}): {e}")
|
||||||
|
if attempt < retries - 1:
|
||||||
|
time.sleep(1) # Wait before retry
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def fetch_metrics(self):
|
def fetch_metrics(self):
|
||||||
"""
|
"""
|
||||||
Fetch metrics from Ocean.xyz and other sources.
|
Fetch metrics from Ocean.xyz and other sources.
|
||||||
@ -227,13 +245,19 @@ class MiningDashboardService:
|
|||||||
data = OceanData()
|
data = OceanData()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Fetch user hashrate data
|
# First test if API connectivity is still valid
|
||||||
hashrate_resp = self.session.get(f"{self.ocean_api_base}/user_hashrate/{self.wallet}", timeout=10)
|
if not self._test_api_connectivity():
|
||||||
if not hashrate_resp.ok:
|
logging.warning("API connectivity test failed during data fetch, falling back to scraping")
|
||||||
logging.error(f"Error fetching hashrate data: status code {hashrate_resp.status_code}")
|
return self.get_ocean_data()
|
||||||
return None
|
|
||||||
|
# Fetch user hashrate data with retry logic
|
||||||
|
hashrate_resp = self._api_request_with_retry(f"user_hashrate/{self.wallet}")
|
||||||
|
if not hashrate_resp:
|
||||||
|
logging.error("Error fetching hashrate data from API, falling back to scraping")
|
||||||
|
return self.get_ocean_data()
|
||||||
|
|
||||||
hashrate_data = hashrate_resp.json()
|
hashrate_data = hashrate_resp.json()
|
||||||
|
logging.debug(f"Hashrate API response: {str(hashrate_data)[:200]}...")
|
||||||
|
|
||||||
# Convert and populate hashrates
|
# Convert and populate hashrates
|
||||||
if "hashrate_60s" in hashrate_data:
|
if "hashrate_60s" in hashrate_data:
|
||||||
@ -262,8 +286,8 @@ class MiningDashboardService:
|
|||||||
data.hashrate_24hr_unit = self._format_hashrate_value(hashrate_24hr)[1]
|
data.hashrate_24hr_unit = self._format_hashrate_value(hashrate_24hr)[1]
|
||||||
|
|
||||||
# Fetch pool stats for pool hashrate
|
# Fetch pool stats for pool hashrate
|
||||||
pool_resp = self.session.get(f"{self.ocean_api_base}/pool_hashrate", timeout=10)
|
pool_resp = self._api_request_with_retry("pool_hashrate")
|
||||||
if pool_resp.ok:
|
if pool_resp:
|
||||||
pool_data = pool_resp.json()
|
pool_data = pool_resp.json()
|
||||||
if "pool_300s" in pool_data:
|
if "pool_300s" in pool_data:
|
||||||
pool_hashrate = pool_data["pool_300s"]
|
pool_hashrate = pool_data["pool_300s"]
|
||||||
@ -271,9 +295,10 @@ class MiningDashboardService:
|
|||||||
data.pool_total_hashrate_unit = self._format_hashrate_value(pool_hashrate)[1]
|
data.pool_total_hashrate_unit = self._format_hashrate_value(pool_hashrate)[1]
|
||||||
|
|
||||||
# Fetch user's stats for earnings info
|
# Fetch user's stats for earnings info
|
||||||
stats_resp = self.session.get(f"{self.ocean_api_base}/statsnap/{self.wallet}", timeout=10)
|
stats_resp = self._api_request_with_retry(f"statsnap/{self.wallet}")
|
||||||
if stats_resp.ok:
|
if stats_resp:
|
||||||
stats_data = stats_resp.json()
|
stats_data = stats_resp.json()
|
||||||
|
logging.debug(f"Statsnap API response: {str(stats_data)[:200]}...")
|
||||||
|
|
||||||
# Get unpaid earnings
|
# Get unpaid earnings
|
||||||
if "unpaid" in stats_data:
|
if "unpaid" in stats_data:
|
||||||
@ -297,17 +322,19 @@ class MiningDashboardService:
|
|||||||
data.total_last_share = la_dt.strftime("%Y-%m-%d %I:%M %p")
|
data.total_last_share = la_dt.strftime("%Y-%m-%d %I:%M %p")
|
||||||
|
|
||||||
# Fetch user_hashrate_full to count active workers
|
# Fetch user_hashrate_full to count active workers
|
||||||
workers_resp = self.session.get(f"{self.ocean_api_base}/user_hashrate_full/{self.wallet}", timeout=10)
|
workers_resp = self._api_request_with_retry(f"user_hashrate_full/{self.wallet}")
|
||||||
if workers_resp.ok:
|
if workers_resp:
|
||||||
workers_data = workers_resp.json()
|
workers_data = workers_resp.json()
|
||||||
if "workers" in workers_data:
|
if "workers" in workers_data:
|
||||||
|
logging.info(f"Found {len(workers_data['workers'])} workers in API response")
|
||||||
# Count non-zero hashrate workers as active
|
# Count non-zero hashrate workers as active
|
||||||
data.workers_hashing = sum(1 for worker in workers_data["workers"]
|
data.workers_hashing = sum(1 for worker in workers_data["workers"]
|
||||||
if worker.get("hashrate_300s", 0) > 0)
|
if worker.get("hashrate_300s", 0) > 0)
|
||||||
|
logging.info(f"Workers currently hashing: {data.workers_hashing}")
|
||||||
|
|
||||||
# Fetch latest block info
|
# Fetch latest block info
|
||||||
latest_block_resp = self.session.get(f"{self.ocean_api_base}/latest_block", timeout=10)
|
latest_block_resp = self._api_request_with_retry("latest_block")
|
||||||
if latest_block_resp.ok:
|
if latest_block_resp:
|
||||||
latest_block_data = latest_block_resp.json()
|
latest_block_data = latest_block_resp.json()
|
||||||
if latest_block_data:
|
if latest_block_data:
|
||||||
# Get the first block in the response
|
# Get the first block in the response
|
||||||
@ -327,8 +354,8 @@ class MiningDashboardService:
|
|||||||
logging.error(f"Error converting block timestamp: {e}")
|
logging.error(f"Error converting block timestamp: {e}")
|
||||||
|
|
||||||
# Fetch blocks for blocks found count
|
# Fetch blocks for blocks found count
|
||||||
blocks_resp = self.session.get(f"{self.ocean_api_base}/blocks", timeout=10)
|
blocks_resp = self._api_request_with_retry("blocks")
|
||||||
if blocks_resp.ok:
|
if blocks_resp:
|
||||||
blocks_data = blocks_resp.json()
|
blocks_data = blocks_resp.json()
|
||||||
if isinstance(blocks_data, list):
|
if isinstance(blocks_data, list):
|
||||||
# Count blocks mined by this user
|
# Count blocks mined by this user
|
||||||
@ -338,8 +365,8 @@ class MiningDashboardService:
|
|||||||
data.blocks_found = str(len(user_blocks))
|
data.blocks_found = str(len(user_blocks))
|
||||||
|
|
||||||
# Fetch earnpay for last block earnings
|
# Fetch earnpay for last block earnings
|
||||||
earnpay_resp = self.session.get(f"{self.ocean_api_base}/earnpay/{self.wallet}", timeout=10)
|
earnpay_resp = self._api_request_with_retry(f"earnpay/{self.wallet}")
|
||||||
if earnpay_resp.ok:
|
if earnpay_resp:
|
||||||
earnpay_data = earnpay_resp.json()
|
earnpay_data = earnpay_resp.json()
|
||||||
if "earnings" in earnpay_data and earnpay_data["earnings"]:
|
if "earnings" in earnpay_data and earnpay_data["earnings"]:
|
||||||
# Get the latest earning entry
|
# Get the latest earning entry
|
||||||
@ -371,11 +398,15 @@ class MiningDashboardService:
|
|||||||
# Rough estimate based on 144 blocks per day average
|
# Rough estimate based on 144 blocks per day average
|
||||||
data.estimated_earnings_per_day = data.estimated_earnings_next_block * 144
|
data.estimated_earnings_per_day = data.estimated_earnings_next_block * 144
|
||||||
|
|
||||||
|
# Log successful API data retrieval
|
||||||
|
logging.info("Successfully retrieved Ocean data from API")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error fetching Ocean data from API: {e}")
|
logging.error(f"Error fetching Ocean data from API: {e}")
|
||||||
return None
|
# Fall back to scraping method
|
||||||
|
logging.info("Falling back to web scraping method")
|
||||||
|
return self.get_ocean_data()
|
||||||
|
|
||||||
def _format_hashrate_value(self, hashrate_h_per_sec):
|
def _format_hashrate_value(self, hashrate_h_per_sec):
|
||||||
"""
|
"""
|
||||||
@ -797,10 +828,10 @@ class MiningDashboardService:
|
|||||||
dict: Worker data dictionary with stats and list of workers
|
dict: Worker data dictionary with stats and list of workers
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Fetch full worker hashrate information
|
# Fetch full worker hashrate information with retry
|
||||||
response = self.session.get(f"{self.ocean_api_base}/user_hashrate_full/{self.wallet}", timeout=15)
|
response = self._api_request_with_retry(f"user_hashrate_full/{self.wallet}", timeout=15)
|
||||||
if not response.ok:
|
if not response:
|
||||||
logging.error(f"Error fetching worker data from API: status code {response.status_code}")
|
logging.error("Error fetching worker data from API")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
@ -808,6 +839,7 @@ class MiningDashboardService:
|
|||||||
logging.error("No worker data found in API response")
|
logging.error("No worker data found in API response")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
logging.debug(f"Worker API response: {str(data)[:200]}...")
|
||||||
workers = []
|
workers = []
|
||||||
total_hashrate = 0
|
total_hashrate = 0
|
||||||
workers_online = 0
|
workers_online = 0
|
||||||
@ -881,9 +913,9 @@ class MiningDashboardService:
|
|||||||
workers.append(worker)
|
workers.append(worker)
|
||||||
|
|
||||||
# Try to get earnings info from statsnap endpoint
|
# Try to get earnings info from statsnap endpoint
|
||||||
earnings_resp = self.session.get(f"{self.ocean_api_base}/statsnap/{self.wallet}", timeout=10)
|
earnings_resp = self._api_request_with_retry(f"statsnap/{self.wallet}", timeout=10)
|
||||||
daily_sats = 0
|
daily_sats = 0
|
||||||
if earnings_resp.ok:
|
if earnings_resp:
|
||||||
stats_data = earnings_resp.json()
|
stats_data = earnings_resp.json()
|
||||||
if "estimated_earn_next_block" in stats_data:
|
if "estimated_earn_next_block" in stats_data:
|
||||||
# Approximately 144 blocks per day
|
# Approximately 144 blocks per day
|
||||||
|
Loading…
Reference in New Issue
Block a user