refactor: improve startup procedure
During startup the API will try to connect to Bitcoin Core and the
Lightning Node. If it can't connect it will check every "n" seconds
(currently 2s) and connect when available. A new SSE event
called "system_startup_info" is introduced. This event contains
all startup status information during the startup procedure.
The old wallet_locked event is obsolete.
Sample:
--------------------------
event: system_startup_info
data: {"bitcoin": "offline", "bitcoin_msg": "", "lightning": "offline", "lightning_msg": "Unable to connect to LND daemon, waiting..."}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "offline", "lightning_msg": "Unable to connect to LND daemon, waiting..."}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "locked", "lightning_msg": "Wallet locked, unlock it to enable full RPC access"}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "done", "lightning_msg": ""}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "bootstraping", "lightning_msg": "RPC not yet available"}
--------------------------
refs #97
2022-06-06 19:29:21 +02:00
|
|
|
from enum import Enum
|
2025-03-25 09:48:40 +01:00
|
|
|
from typing import Any, Dict, List, Optional, Sequence, Union
|
2025-03-18 17:14:35 +01:00
|
|
|
|
|
|
|
|
from fastapi import Query
|
2025-03-26 20:22:19 +01:00
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProcessResult:
|
|
|
|
|
return_code: int | None
|
|
|
|
|
stdout: str
|
|
|
|
|
stderr: str
|
|
|
|
|
|
|
|
|
|
def __init__(self, return_code: int | None, stdout: str, stderr: str) -> None:
|
|
|
|
|
self.return_code = return_code
|
|
|
|
|
self.stdout = stdout
|
|
|
|
|
self.stderr = stderr
|
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return (
|
|
|
|
|
f"ProcessResult: \nreturn_code: {self.return_code}\n"
|
|
|
|
|
f"stdout: {self.stdout}\n"
|
|
|
|
|
f"stderr: {self.stderr}"
|
|
|
|
|
)
|
2025-03-18 17:14:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class ApiErrors(str, Enum):
|
|
|
|
|
INVALID_REQUEST_INPUT = "invalid_request_input"
|
|
|
|
|
UNABLE_TO_PROCESS_ERROR = "unable_to_process_error"
|
2025-04-01 20:42:55 +02:00
|
|
|
APP_STATUS_UPDATE_FAILED = "app_status_update_failed"
|
2025-04-13 21:16:17 +02:00
|
|
|
APP_INVALID_FOR_PLATFORM = "app_invalid_for_platform"
|
|
|
|
|
APP_MANAGE_ON_IS_ALREADY_INSTALLED = "app_manage_on_is_already_installed"
|
|
|
|
|
APP_MANAGE_OFF_IS_NOT_INSTALLED = "app_manage_off_is_not_installed"
|
|
|
|
|
APP_MANAGE_LOCK_HELD = "app_manage_lock_held"
|
2025-04-01 20:42:55 +02:00
|
|
|
BACKGROUND_TASK_FAILED = "background_task_failed"
|
2025-04-13 21:16:17 +02:00
|
|
|
UNKNOWN = "unknown"
|
2025-03-18 17:14:35 +01:00
|
|
|
|
|
|
|
|
|
2025-04-14 14:31:07 +02:00
|
|
|
class RedisChannelMessageData(BaseModel):
|
|
|
|
|
timestamp: str = Query(..., description="The timestamp of the message")
|
|
|
|
|
key: str = Query(..., description="The key of the message")
|
|
|
|
|
json_contents: str | None = Query(None, description="The contents of the message")
|
|
|
|
|
|
|
|
|
|
|
2025-03-18 17:14:35 +01:00
|
|
|
class ErrorMessage(BaseModel):
|
|
|
|
|
detail: str = Query(..., description="short text representation of the error")
|
|
|
|
|
error_code: str = Query("", description="a unique identifier for the error")
|
|
|
|
|
report: Optional[Union[str, Dict, List, Sequence[Any]]] = Query(
|
|
|
|
|
None,
|
|
|
|
|
description="optional more detailed message",
|
|
|
|
|
)
|
|
|
|
|
trace: Optional[Sequence[str]] = Query(
|
|
|
|
|
None,
|
|
|
|
|
description="optional stack trace of the error "
|
|
|
|
|
"(only when configured with BAPI_SEND_TRACE=true)",
|
|
|
|
|
)
|
refactor: improve startup procedure
During startup the API will try to connect to Bitcoin Core and the
Lightning Node. If it can't connect it will check every "n" seconds
(currently 2s) and connect when available. A new SSE event
called "system_startup_info" is introduced. This event contains
all startup status information during the startup procedure.
The old wallet_locked event is obsolete.
Sample:
--------------------------
event: system_startup_info
data: {"bitcoin": "offline", "bitcoin_msg": "", "lightning": "offline", "lightning_msg": "Unable to connect to LND daemon, waiting..."}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "offline", "lightning_msg": "Unable to connect to LND daemon, waiting..."}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "locked", "lightning_msg": "Wallet locked, unlock it to enable full RPC access"}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "done", "lightning_msg": ""}
--------------------------
event: system_startup_info
data: {"bitcoin": "done", "bitcoin_msg": "", "lightning": "bootstraping", "lightning_msg": "RPC not yet available"}
--------------------------
refs #97
2022-06-06 19:29:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class StartupState(str, Enum):
|
|
|
|
|
OFFLINE = "offline"
|
|
|
|
|
BOOTSTRAPPING = "bootstrapping"
|
|
|
|
|
LOCKED = "locked"
|
|
|
|
|
DONE = "done"
|
|
|
|
|
DISABLED = "disabled"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ApiStartupStatus(BaseModel):
|
|
|
|
|
def __init__(
|
|
|
|
|
__pydantic_self__,
|
|
|
|
|
bitcoin: StartupState = StartupState.OFFLINE,
|
|
|
|
|
bitcoin_msg: Optional[str] = "",
|
|
|
|
|
lightning: StartupState = StartupState.OFFLINE,
|
|
|
|
|
lightning_msg: Optional[str] = "",
|
|
|
|
|
) -> "ApiStartupStatus":
|
|
|
|
|
super().__init__(
|
|
|
|
|
bitcoin=bitcoin,
|
|
|
|
|
bitcoin_msg=bitcoin_msg,
|
|
|
|
|
lightning=lightning,
|
|
|
|
|
lightning_msg=lightning_msg,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
bitcoin: StartupState
|
|
|
|
|
bitcoin_msg: Optional[str]
|
|
|
|
|
lightning: StartupState
|
|
|
|
|
lightning_msg: Optional[str]
|
2022-06-10 19:45:55 +02:00
|
|
|
|
|
|
|
|
def is_fully_initialized(self):
|
|
|
|
|
return self.bitcoin == StartupState.DONE and (
|
|
|
|
|
self.lightning == StartupState.DONE
|
|
|
|
|
or self.lightning == StartupState.DISABLED
|
|
|
|
|
)
|