2021-10-05 19:36:09 +02:00
|
|
|
import asyncio
|
2025-04-01 20:42:55 +02:00
|
|
|
from typing import List, Optional
|
2021-10-05 19:36:09 +02:00
|
|
|
|
2023-04-02 11:09:43 +02:00
|
|
|
from fastapi import HTTPException, status
|
|
|
|
|
from loguru import logger
|
|
|
|
|
|
2025-04-01 20:42:55 +02:00
|
|
|
from app.api.error_report.report import Report
|
2025-04-02 20:10:19 +02:00
|
|
|
from app.api.task_utils import get_lock_status
|
2025-04-05 20:45:12 +02:00
|
|
|
from app.apps.cache import cache as app_cache
|
2025-04-14 14:31:07 +02:00
|
|
|
from app.apps.constants import AppManagementProcessState, AppsServiceKeys
|
|
|
|
|
from app.apps.models import AppStatusUpdateTaskMessage
|
2025-04-01 20:42:55 +02:00
|
|
|
from app.apps.tasks import update_app_state_task
|
2022-10-03 20:22:00 +02:00
|
|
|
from app.bitcoind.service import get_btc_info
|
2025-04-01 20:42:55 +02:00
|
|
|
from app.external.result_type.src.result.result import Err, Ok, Result
|
2024-08-16 21:11:21 +00:00
|
|
|
from app.lightning.service import get_fee_revenue, get_ln_info, get_wallet_balance
|
2022-10-03 20:22:00 +02:00
|
|
|
from app.system.service import get_hardware_info, get_system_info
|
2021-10-05 19:36:09 +02:00
|
|
|
|
|
|
|
|
|
2023-04-02 11:09:43 +02:00
|
|
|
@logger.catch(exclude=(HTTPException,))
|
2022-06-12 07:59:40 +02:00
|
|
|
async def get_bitcoin_client_warmup_data() -> List:
|
|
|
|
|
"""Get the reduced data set needed when the lightning client is not yet ready."""
|
|
|
|
|
res = await asyncio.gather(
|
|
|
|
|
*[
|
|
|
|
|
get_btc_info(),
|
|
|
|
|
get_hardware_info(),
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
return [*res]
|
|
|
|
|
|
|
|
|
|
|
2025-04-14 14:31:07 +02:00
|
|
|
async def _get_app_status_data() -> Result[
|
|
|
|
|
Optional[AppStatusUpdateTaskMessage], Report
|
|
|
|
|
]:
|
2025-03-26 20:22:19 +01:00
|
|
|
"""Transform the result of get_app_status."""
|
2025-04-01 20:42:55 +02:00
|
|
|
try:
|
2025-04-05 20:45:12 +02:00
|
|
|
result = await app_cache.get_cached_app_status()
|
2025-04-01 20:42:55 +02:00
|
|
|
match result:
|
|
|
|
|
case Ok(cached_status_data) if cached_status_data:
|
2025-04-14 14:31:07 +02:00
|
|
|
return Ok(
|
|
|
|
|
AppStatusUpdateTaskMessage(
|
|
|
|
|
state=AppManagementProcessState.SUCCESS,
|
|
|
|
|
message=cached_status_data,
|
|
|
|
|
)
|
|
|
|
|
)
|
2025-04-01 20:42:55 +02:00
|
|
|
case Ok(_):
|
|
|
|
|
# Query executed, but no data was returned
|
|
|
|
|
# This means the cache is empty or stale => trigger update
|
|
|
|
|
update_app_state_task.delay() # type: ignore
|
|
|
|
|
return Ok(None)
|
|
|
|
|
case Err(report):
|
|
|
|
|
# TODO: return error message
|
|
|
|
|
logger.error(f"Failed to fetch app status: {report.format_verbose()}")
|
|
|
|
|
|
2026-07-03 15:28:57 +02:00
|
|
|
# The cache read failed; check whether an update is already running
|
|
|
|
|
# before triggering a new one
|
2025-04-02 20:10:19 +02:00
|
|
|
result = await get_lock_status(AppsServiceKeys.APP_STATUS_LOCK_KEY)
|
2025-04-01 20:42:55 +02:00
|
|
|
match result:
|
|
|
|
|
case Ok(True):
|
|
|
|
|
logger.info(
|
|
|
|
|
"App status update lock exists. Assuming update is in progress."
|
|
|
|
|
)
|
2026-07-03 15:28:57 +02:00
|
|
|
case Ok(False):
|
2025-04-01 20:42:55 +02:00
|
|
|
logger.info(
|
|
|
|
|
"App status cache is missing and no update lock exists. "
|
|
|
|
|
"Triggering update task."
|
|
|
|
|
)
|
|
|
|
|
update_app_state_task.delay() # type: ignore
|
|
|
|
|
case Err(report):
|
|
|
|
|
return Err(report)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return Err(
|
2026-07-03 15:28:57 +02:00
|
|
|
Report(f"Error during app status cache handling for new client: {e}")
|
2025-04-01 20:42:55 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return Ok(None)
|
2025-03-26 20:22:19 +01:00
|
|
|
|
|
|
|
|
|
2026-07-03 15:28:57 +02:00
|
|
|
def _convert_warmup_exceptions(res: List) -> List:
|
|
|
|
|
"""Convert exceptions from a gather(..., return_exceptions=True) call so
|
|
|
|
|
that a single failing data source doesn't wipe out the whole data set."""
|
|
|
|
|
for i, r in enumerate(res):
|
|
|
|
|
if isinstance(r, HTTPException):
|
|
|
|
|
if r.status_code == status.HTTP_501_NOT_IMPLEMENTED:
|
|
|
|
|
logger.trace(f"Not implemented Error in warmup data {i}: {r.detail}")
|
|
|
|
|
# TODO: find a better way to handle this, client receives an error but
|
|
|
|
|
# disguised as a valid response. For example:
|
|
|
|
|
# event: app_state_update_message
|
|
|
|
|
# data: {
|
|
|
|
|
# "status_code": 501,
|
|
|
|
|
# "detail": "Not available in native python mode.",
|
|
|
|
|
# "headers": null
|
|
|
|
|
# }
|
|
|
|
|
res[i] = r
|
|
|
|
|
elif isinstance(r, Exception):
|
|
|
|
|
logger.error(f"Error in warmup data {i}: {r}")
|
|
|
|
|
res[i] = HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
2023-04-02 11:09:43 +02:00
|
|
|
@logger.catch(exclude=(HTTPException,))
|
2022-06-12 07:59:40 +02:00
|
|
|
async def get_full_client_warmup_data() -> List:
|
|
|
|
|
"""Get the full data set needed when the lightning client is not yet ready."""
|
|
|
|
|
|
2021-10-05 19:36:09 +02:00
|
|
|
res = await asyncio.gather(
|
|
|
|
|
*[
|
|
|
|
|
get_system_info(),
|
|
|
|
|
get_btc_info(),
|
2021-11-18 19:50:04 +01:00
|
|
|
get_ln_info(),
|
2022-01-15 14:27:08 +01:00
|
|
|
get_fee_revenue(),
|
2021-10-05 19:36:09 +02:00
|
|
|
get_wallet_balance(),
|
2025-03-26 20:22:19 +01:00
|
|
|
_get_app_status_data(),
|
2022-06-12 07:59:40 +02:00
|
|
|
get_hardware_info(),
|
2023-04-02 11:09:43 +02:00
|
|
|
],
|
|
|
|
|
return_exceptions=True,
|
2021-10-05 19:36:09 +02:00
|
|
|
)
|
2023-04-02 11:09:43 +02:00
|
|
|
|
2026-07-03 15:28:57 +02:00
|
|
|
return [*_convert_warmup_exceptions(res)]
|
2022-06-16 15:30:14 +02:00
|
|
|
|
2022-06-17 21:35:35 +02:00
|
|
|
|
2023-04-02 11:09:43 +02:00
|
|
|
@logger.catch(exclude=(HTTPException,))
|
2022-06-16 15:30:14 +02:00
|
|
|
async def get_full_client_warmup_data_bitcoinonly() -> List:
|
|
|
|
|
"""Get the full data set needed without Lightning available"""
|
|
|
|
|
|
|
|
|
|
res = await asyncio.gather(
|
|
|
|
|
*[
|
|
|
|
|
get_system_info(),
|
|
|
|
|
get_btc_info(),
|
2025-03-26 20:22:19 +01:00
|
|
|
_get_app_status_data(),
|
2022-06-16 15:30:14 +02:00
|
|
|
get_hardware_info(),
|
2026-07-03 15:28:57 +02:00
|
|
|
],
|
|
|
|
|
return_exceptions=True,
|
2022-06-16 15:30:14 +02:00
|
|
|
)
|
2026-07-03 15:28:57 +02:00
|
|
|
return [*_convert_warmup_exceptions(res)]
|