feat: update Python and Devenv deps

- Updated all dependencies to their latest versions
- Vendored fastapi-plugins[redis] as it looks unmaintained
This commit is contained in:
fusion44 2026-02-02 12:25:30 +01:00
parent 44385ca40c
commit 07d2bfbc76
No known key found for this signature in database
10 changed files with 1663 additions and 1037 deletions

View file

@ -8,13 +8,13 @@ import time
from typing import Any, Dict, Optional
from fastapi.encoders import jsonable_encoder
from fastapi_plugins import redis_plugin
from loguru import logger
from redis.asyncio import Redis, TimeoutError
from app.api.error_report.report import Report
from app.api.models import ProcessResult
from app.api.sse_manager import SSEManager
from app.external.fastapi_plugins_redis import redis_plugin
from app.external.result_type.src.result import Err, Ok, Result
from app.external.sse_starlette import ServerSentEvent

238
app/external/fastapi_plugins_redis.py vendored Normal file
View file

@ -0,0 +1,238 @@
# Based on the original fastapi-plugins implementation
# Re-implemented to remove the dependency on the unmaintained library
import asyncio
import enum
import typing
from typing import Any, Dict, List, Optional, Union
import redis.asyncio as aioredis
import redis.asyncio.sentinel as aioredis_sentinel
from fastapi import FastAPI
from pydantic_settings import BaseSettings
__all__ = [
"RedisError",
"RedisType",
"RedisSettings",
"RedisPlugin",
"redis_plugin",
"registered_configuration",
"get_config",
]
class RedisError(Exception):
pass
@enum.unique
class RedisType(str, enum.Enum):
redis = "redis"
sentinel = "sentinel"
fakeredis = "fakeredis"
class RedisSettings(BaseSettings):
redis_type: RedisType = RedisType.redis
redis_url: Optional[str] = None
redis_host: str = "localhost"
redis_port: int = 6379
redis_user: Optional[str] = None
redis_password: Optional[str] = None
redis_db: Optional[int] = None
redis_max_connections: Optional[int] = None
redis_decode_responses: bool = True
redis_ttl: int = 3600
redis_sentinels: Optional[str] = None
redis_sentinel_master: str = "mymaster"
redis_prestart_tries: int = 60 * 5 # 5 min
redis_prestart_wait: int = 1 # 1 second
def get_redis_address(self) -> str:
if self.redis_url:
return self.redis_url
elif self.redis_db:
return f"redis://{self.redis_host}:{self.redis_port}/{self.redis_db}"
else:
return f"redis://{self.redis_host}:{self.redis_port}"
def get_sentinels(self) -> List:
if self.redis_sentinels:
try:
return [
(_conn.split(":")[0].strip(), int(_conn.split(":")[1].strip()))
for _conn in self.redis_sentinels.split(",")
if _conn.strip()
]
except Exception as e:
raise RuntimeError(
"bad sentinels string :: "
f"{type(e)} :: {str(e)} :: {self.redis_sentinels}"
)
else:
return []
class RedisPlugin:
def __init__(self):
self.redis: Union[aioredis.Redis, aioredis_sentinel.Sentinel, None] = None
self.config: Optional[RedisSettings] = None
async def init_app(
self, app: FastAPI, config: Optional[RedisSettings] = None
) -> None:
self.config = config or RedisSettings()
if self.config is None:
raise RedisError("Redis configuration is not initialized")
elif not isinstance(self.config, RedisSettings):
raise RedisError("Redis configuration is not valid")
# Store the plugin instance in app.state for access if needed,
# mirroring the original behavior.
app.state.REDIS = self
async def init(self) -> None:
if self.redis is not None:
raise RedisError("Redis is already initialized")
if self.config is None:
raise RedisError("Redis configuration is not initialized")
opts = dict(
db=self.config.redis_db,
username=self.config.redis_user,
password=self.config.redis_password,
max_connections=self.config.redis_max_connections,
decode_responses=self.config.redis_decode_responses,
)
address: Any = None
method: Any = None
if self.config.redis_type == RedisType.redis:
address = self.config.get_redis_address()
method = aioredis.from_url
elif self.config.redis_type == RedisType.fakeredis:
try:
import fakeredis.aioredis # type: ignore
except ImportError:
raise RedisError(
f"{self.config.redis_type} requires fakeredis to be installed"
)
else:
address = self.config.get_redis_address()
method = fakeredis.aioredis.FakeRedis.from_url
elif self.config.redis_type == RedisType.sentinel:
address = self.config.get_sentinels()
method = aioredis_sentinel.Sentinel
else:
raise NotImplementedError(
f"Redis type {self.config.redis_type} is not implemented"
)
if not address:
raise ValueError("Redis address is empty")
tries = 0
while True:
try:
self.redis = method(address, **opts)
if self.redis:
await self.ping()
break
except Exception as e:
tries += 1
if tries >= self.config.redis_prestart_tries:
raise RedisError(
f"Could not connect to Redis after {tries} attempts: {e}"
) from e
await asyncio.sleep(self.config.redis_prestart_wait)
async def terminate(self) -> None:
self.config = None
if self.redis is not None:
if isinstance(self.redis, aioredis.Redis):
await self.redis.close()
self.redis = None
async def health(self) -> Dict:
if self.config is None:
return dict(status="down", reason="Configuration not initialized")
address = (
self.config.get_sentinels()
if self.config.redis_type == RedisType.sentinel
else self.config.get_redis_address()
)
return dict(
redis_type=self.config.redis_type,
redis_address=address,
redis_pong=(await self.ping()),
)
async def ping(self) -> bool:
if self.redis is None or self.config is None:
return False
if self.config.redis_type == RedisType.redis:
return await self.redis.ping() # type: ignore
elif self.config.redis_type == RedisType.fakeredis:
return await self.redis.ping() # type: ignore
elif self.config.redis_type == RedisType.sentinel:
sentinel: aioredis_sentinel.Sentinel = self.redis # type: ignore
master = sentinel.master_for(self.config.redis_sentinel_master)
return await master.ping()
else:
raise NotImplementedError(
f"Redis type {self.config.redis_type}.ping() is not implemented"
)
async def __call__(self) -> Any:
# Support dependency injection style usage: await redis_plugin()
if self.redis is None:
raise RedisError("Redis is not initialized")
if self.config is None:
raise RedisError("Redis configuration is not initialized")
if self.config.redis_type == RedisType.sentinel:
sentinel: aioredis_sentinel.Sentinel = self.redis # type: ignore
conn = sentinel.master_for(self.config.redis_sentinel_master)
elif self.config.redis_type == RedisType.redis:
conn = self.redis
elif self.config.redis_type == RedisType.fakeredis:
conn = self.redis
else:
raise NotImplementedError(
f"Redis type {self.config.redis_type} is not implemented"
)
# Note: aioredis connection objects don't have a simple TTL attribute like this
# in the newer versions usually, but we keep the logic from the original plugin
# if it was attaching it dynamically or if older versions had it.
# However, purely attaching it to the object might be harmless.
# conn.TTL = self.config.redis_ttl
return conn
# Singleton instance
redis_plugin = RedisPlugin()
# Configuration Registry Logic
# To support the @registered_configuration and get_config() pattern
_config_class: Optional[typing.Type[RedisSettings]] = None
def registered_configuration(cls):
global _config_class
_config_class = cls
return cls
def get_config() -> RedisSettings:
global _config_class
if _config_class:
return _config_class()
return RedisSettings()

View file

@ -6,9 +6,6 @@ from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import HTTPException, RequestValidationError
from fastapi_plugins import RedisSettings
from fastapi_plugins import get_config as get_redis_config
from fastapi_plugins import redis_plugin, registered_configuration
from loguru import logger
from pydantic import BaseModel
from redis.asyncio import Redis
@ -39,6 +36,12 @@ from app.bitcoind.service import (
register_bitcoin_status_gatherer,
register_bitcoin_zmq_sub,
)
from app.external.fastapi_plugins_redis import (
RedisSettings,
get_config as get_redis_config,
redis_plugin,
registered_configuration,
)
from app.external.result_type.src.result.result import Ok
from app.lightning.models import LnInitState
from app.lightning.router import router as ln_router

View file

@ -1,5 +1,4 @@
from abc import abstractmethod
from logging import error
from typing import Dict
from app.api.error_report.report import Report

View file

@ -3,10 +3,10 @@
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1762706931,
"lastModified": 1770030861,
"owner": "cachix",
"repo": "devenv",
"rev": "9a8147b9345ecbb1321890ce7603df1507b1125d",
"rev": "6c4bab62f66aa3a9f0f70cd9741d365a9c28b2bb",
"type": "github"
},
"original": {
@ -19,14 +19,14 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1761588595,
"owner": "edolstra",
"lastModified": 1767039857,
"owner": "NixOS",
"repo": "flake-compat",
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "edolstra",
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}
@ -40,10 +40,10 @@
]
},
"locked": {
"lastModified": 1762441963,
"lastModified": 1769939035,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "8e7576e79b88c16d7ee3bbd112c8d90070832885",
"rev": "a8ca480175326551d6c4121498316261cbb5b260",
"type": "github"
},
"original": {
@ -60,10 +60,10 @@
]
},
"locked": {
"lastModified": 1709087332,
"lastModified": 1762808025,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
"type": "github"
},
"original": {
@ -74,10 +74,10 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1761313199,
"lastModified": 1767052823,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "d1c30452ebecfc55185ae6d1c983c09da0c274ff",
"rev": "538a5124359f0b3d466e1160378c87887e3b51a4",
"type": "github"
},
"original": {
@ -89,10 +89,10 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1762482733,
"lastModified": 1769983348,
"owner": "nixos",
"repo": "nixpkgs",
"rev": "e1ebeec86b771e9d387dd02d82ffdc77ac753abc",
"rev": "eb8d947de7b05897b2b5f4117d184f9c9846cd06",
"type": "github"
},
"original": {

View file

@ -63,9 +63,10 @@ in {
python = {
enable = true;
# 3.11 is default on RaspiBlitz 1.12
package = pkgs-unstable.python311;
package = pkgs-unstable.python312;
uv = {
enable = true;
sync.enable = true;
package = pkgs-unstable.uv;
};
};
@ -112,6 +113,7 @@ in {
cln.exec = ''
sleep 3
lightningd \
--bind-addr=127.0.0.1:9736 \
--regtest \
--lightning-dir=${clnDataDir} \
--bitcoin-datadir=${bitcoinDataDir}

View file

@ -10,11 +10,37 @@
"tags": [
"Apps"
],
"summary": "Get the status available apps.",
"summary": "Get the status of all available apps.",
"operationId": "apps_status_apps_status_get",
"responses": {
"200": {
"description": "\nReturns a JSON list with the current status of all **installed** apps\n```\n[\n {\n id: 'specter',\n name: 'Specter Desktop',\n status: 'online'\n },\n {\n id: 'sphinx',\n name: 'Sphinx Chat',\n status: 'online'\n },\n ...\n]\n```\n",
"description": "\nReturns a JSON list with the current status of all available apps\n```\n{\n \"data\": [\n {\n \"id\": \"btcpayserver\",\n \"version\": \"v1.13.0\",\n \"installed\": false,\n \"configured\": false,\n \"status\": \"offline\",\n \"local_ip\": null,\n \"http_port\": null,\n \"https_port\": null,\n \"https_forced\": null,\n \"https_self_signed\": null,\n \"hidden_service\": null,\n \"address\": null,\n \"auth_method\": null,\n \"details\": null,\n \"error\": null\n },\n {\n \"id\": \"btc-rpc-explorer\",\n \"version\": \"v3.4.0\",\n \"installed\": false,\n \"configured\": false,\n \"status\": \"offline\",\n \"local_ip\": null,\n ...\n },\n ...\n ],\n \"errors\": [\n {\n \"id\": \"rtl\",\n \"error\": \"App status script execution failed.\n\u251c\u2574at /home/blitzapi/blitz_api/app/apps/impl/raspiblitz.py:92:10\n\u251c\u2574script_name: /home/admin/config.scripts/bonus.rtl.sh status\n\u2502\n\u2570\u2500\u25b6 500: Something went wrong!\n \u2570\u2574at /home/blitzapi/blitz_api/app/apps/impl/raspiblitz.py:92:10\"\n },\n ...\n ]\n}\n```\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AppStatusQueryResult"
}
}
}
}
},
"security": [
{
"JWTBearer": []
}
]
}
},
"/apps/update-cache": {
"post": {
"tags": [
"Apps"
],
"summary": "Update the app status cache. Results will be broadcasted to SSE clients.",
"operationId": "apps_update_cache_apps_update_cache_post",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
@ -56,10 +82,15 @@
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
"schema": {
"$ref": "#/components/schemas/AppStatus"
}
}
}
},
"404": {
"description": "If no or an invalid app id is given."
},
"422": {
"description": "Validation Error",
"content": {
@ -79,7 +110,7 @@
"Apps"
],
"summary": "Get the advanced status of a single app by id.",
"description": "Some apps might give status information that is computationally\n to expensive to include in the normal status endpoint.\n\n> \u2139\ufe0f _This endpoint is not implemented on all platforms_",
"description": "Some apps might give status information that is computationally\n to expensive to include in the normal status endpoint.\n\n Available app ids for this endpoint:\n - electrs\n\n> \u2139\ufe0f _This endpoint is not implemented on all platforms_",
"operationId": "apps_status_advanced_apps_status_advanced__id__get",
"security": [
{
@ -107,8 +138,8 @@
}
}
},
"400": {
"description": "If no or invalid app id is given."
"404": {
"description": "If no or an invalid app id is given."
},
"422": {
"description": "Validation Error",
@ -123,21 +154,102 @@
}
}
},
"/apps/status-sub": {
"get": {
"/apps/install/{app_id}": {
"post": {
"tags": [
"Apps"
],
"summary": "Subscribe to status changes of currently installed apps.",
"operationId": "apps_status_sub_apps_status_sub_get",
"summary": "Install an app",
"description": "Attempts to install an app. The installation process results are\n not returned on this endpoint. Instead, the results are communicated via the SSE\n channels. This call only verifies if the app is available for installation on the\n given platform.",
"operationId": "apps_install_apps_install__app_id__post",
"security": [
{
"JWTBearer": []
}
],
"parameters": [
{
"name": "app_id",
"in": "path",
"required": true,
"schema": {
"$ref": "#/components/schemas/AppId"
}
}
],
"responses": {
"200": {
"description": "\nSends a JSON object with the status of an app if it changes.\n```\n{\n id: 'specter',\n name: 'Specter Desktop',\n status: 'online'\n},\n```\n",
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"400": {
"description": "If the app is already installed or not available for the platform."
},
"404": {
"description": "If no or an invalid app id is given."
},
"423": {
"description": "If an app install task is already running."
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/apps/uninstall": {
"post": {
"tags": [
"Apps"
],
"summary": "Uninstall app",
"description": "Attempts to uninstall an app. The uninstallation process results are\n not returned on this endpoint. Instead, the results are communicated via the SSE\n channels. This call only verifies if the app is available for uninstallation on the\n given platform.",
"operationId": "apps_uninstall_apps_uninstall_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AppUninstallInput"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"400": {
"description": "If the app is already installed."
},
"404": {
"description": "If no or an invalid app id is given."
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
},
"security": [
@ -147,106 +259,6 @@
]
}
},
"/apps/install/{name}": {
"post": {
"tags": [
"Apps"
],
"summary": "Install app",
"operationId": "apps_install_apps_install__name__post",
"security": [
{
"JWTBearer": []
}
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/apps/uninstall/{name}": {
"post": {
"tags": [
"Apps"
],
"summary": "Uninstall app",
"operationId": "apps_install_apps_uninstall__name__post",
"security": [
{
"JWTBearer": []
}
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UninstallData"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/bitcoin/btc-info": {
"get": {
"tags": [
@ -1735,7 +1747,7 @@
"operationId": "system_hardware_info_sub_system_hardware_info_sub_get",
"responses": {
"200": {
"description": "Yields a JSON string with hardware information every 2.5 seconds\n\n```JSON\n{\n \"cpu_overall_percent\": 15.8,\n \"cpu_per_cpu_percent\": [\n 11.8,\n 6.1,\n 12.5\n ],\n \"vram_total_bytes\": 25134919680,\n \"vram_available_bytes\": 17240051712,\n \"vram_used_bytes\": 6044856320,\n \"vram_usage_percent\": 31.4,\n \"swap_ram_total_bytes\": 2147479552,\n \"swap_used_bytes\": 0,\n \"swap_usage_bytes\": 0,\n \"temperatures_celsius\": {\n \"coretemp\": [\n [\n \"Core 1\",\n 51,\n 84,\n 100\n ],\n [\n \"Core 2\",\n 53,\n 84,\n 100\n ],\n [\n \"Core 3\",\n 50,\n 84,\n 100\n ]\n ]\n },\n \"boot_time_timestamp\": 1623486468,\n \"disk_io_read_count\": 254574,\n \"disk_io_write_count\": 133353,\n \"disk_io_read_bytes\": 5306839040,\n \"disk_io_write_bytes\": 5593076736,\n \"disks\": [\n {\n \"device\": \"/dev/sda1\",\n \"mountpoint\": \"/boot/efi\",\n \"filesystem_type\": \"vfat\",\n \"partition_total_bytes\": 535805952,\n \"partition_used_bytes\": 8228864,\n \"partition_free_bytes\": 527577088,\n \"partition_percent\": 1.5\n },\n {\n \"device\": \"/dev/sda2\",\n \"mountpoint\": \"/\",\n \"filesystem_type\": \"ext4\",\n \"partition_total_bytes\": 250438021120,\n \"partition_used_bytes\": 177157742592,\n \"partition_free_bytes\": 60487389184,\n \"partition_percent\": 74.5\n }\n ],\n \"networks\": [\n {\n \"interface_name\": \"lo\",\n \"address\": \"127.0.0.1\",\n \"mac_address\": \"00:00:00:00:00:00\"\n },\n {\n \"interface_name\": \"enp4s0\",\n \"address\": \"192.168.1.23\",\n \"mac_address\": \"35:a3:5c:6a:4a:f0\"\n }\n ],\n \"networks_bytes_sent\": 137088249,\n \"networks_bytes_received\": 1603400654\n}\n```\n",
"description": "Yields a JSON string with hardware information every 2 seconds\n\n```JSON\n{\n \"cpu_overall_percent\": 15.8,\n \"cpu_per_cpu_percent\": [\n 11.8,\n 6.1,\n 12.5\n ],\n \"vram_total_bytes\": 25134919680,\n \"vram_available_bytes\": 17240051712,\n \"vram_used_bytes\": 6044856320,\n \"vram_usage_percent\": 31.4,\n \"swap_ram_total_bytes\": 2147479552,\n \"swap_used_bytes\": 0,\n \"swap_usage_bytes\": 0,\n \"temperatures_celsius\": {\n \"coretemp\": [\n [\n \"Core 1\",\n 51,\n 84,\n 100\n ],\n [\n \"Core 2\",\n 53,\n 84,\n 100\n ],\n [\n \"Core 3\",\n 50,\n 84,\n 100\n ]\n ]\n },\n \"boot_time_timestamp\": 1623486468,\n \"disk_io_read_count\": 254574,\n \"disk_io_write_count\": 133353,\n \"disk_io_read_bytes\": 5306839040,\n \"disk_io_write_bytes\": 5593076736,\n \"disks\": [\n {\n \"device\": \"/dev/sda1\",\n \"mountpoint\": \"/boot/efi\",\n \"filesystem_type\": \"vfat\",\n \"partition_total_bytes\": 535805952,\n \"partition_used_bytes\": 8228864,\n \"partition_free_bytes\": 527577088,\n \"partition_percent\": 1.5\n },\n {\n \"device\": \"/dev/sda2\",\n \"mountpoint\": \"/\",\n \"filesystem_type\": \"ext4\",\n \"partition_total_bytes\": 250438021120,\n \"partition_used_bytes\": 177157742592,\n \"partition_free_bytes\": 60487389184,\n \"partition_percent\": 74.5\n }\n ],\n \"networks\": [\n {\n \"interface_name\": \"lo\",\n \"address\": \"127.0.0.1\",\n \"mac_address\": \"00:00:00:00:00:00\"\n },\n {\n \"interface_name\": \"enp4s0\",\n \"address\": \"192.168.1.23\",\n \"mac_address\": \"35:a3:5c:6a:4a:f0\"\n }\n ],\n \"networks_bytes_sent\": 137088249,\n \"networks_bytes_received\": 1603400654\n}\n```\n",
"content": {
"application/json": {
"schema": {}
@ -1856,6 +1868,174 @@
]
}
},
"/setup/status": {
"get": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Get Status",
"operationId": "get_status_setup_status_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
},
"/setup/setup-start-info": {
"get": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Setup Start Info",
"operationId": "setup_start_info_setup_setup_start_info_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
},
"/setup/setup-start-done": {
"post": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Setup Start Done",
"operationId": "setup_start_done_setup_setup_start_done_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StartDoneData"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/setup/setup-final-info": {
"get": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Setup Final Info",
"operationId": "setup_final_info_setup_setup_final_info_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"security": [
{
"JWTBearer": []
}
]
}
},
"/setup/setup-final-done": {
"post": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Setup Final Done",
"operationId": "setup_final_done_setup_setup_final_done_post",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"security": [
{
"JWTBearer": []
}
]
}
},
"/setup/shutdown": {
"get": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Get Shutdown",
"operationId": "get_shutdown_setup_shutdown_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
},
"/setup/setup-sync-info": {
"post": {
"tags": [
"RaspiBlitz Setup"
],
"summary": "Setup Sync Info",
"operationId": "setup_sync_info_setup_setup_sync_info_post",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"security": [
{
"JWTBearer": []
}
]
}
},
"/": {
"get": {
"summary": "Index",
@ -1956,6 +2136,259 @@
],
"title": "Amp"
},
"AppId": {
"type": "string",
"enum": [
"albyhub",
"btcpayserver",
"btc-rpc-explorer",
"electrs",
"jam",
"lnbits",
"mempool",
"rtl",
"thunderhub"
],
"title": "AppId"
},
"AppOnlineStatus": {
"type": "string",
"enum": [
"online",
"offline"
],
"title": "AppOnlineStatus"
},
"AppStatus": {
"properties": {
"id": {
"$ref": "#/components/schemas/AppId",
"description": "Id of the applications"
},
"version": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Version",
"description": "Version of the application"
},
"installed": {
"type": "boolean",
"title": "Installed",
"description": "Whether the application is installed",
"default": false
},
"configured": {
"type": "boolean",
"title": "Configured",
"description": "Whether the application is configured",
"default": false
},
"status": {
"$ref": "#/components/schemas/AppOnlineStatus",
"description": "Whether the application is online",
"default": "offline"
},
"local_ip": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Local Ip",
"description": "The local network IP of the application"
},
"http_port": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Http Port",
"description": "The http port of the application"
},
"https_port": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Https Port",
"description": "The https port of the application"
},
"https_forced": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Https Forced",
"description": "Whether https is forced for this application"
},
"https_self_signed": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Https Self Signed",
"description": "Whether the https certificate is self signed"
},
"hidden_service": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Hidden Service",
"description": "Whether the application is reachable via a tor hidden service"
},
"address": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Address",
"description": "The full address where this application is reachable"
},
"auth_method": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Auth Method",
"description": "The authentication method this application uses"
},
"details": {
"anyOf": [
{
"type": "object"
},
{
"type": "null"
}
],
"title": "Details",
"description": "Additional application specific details\n\n This field can contain values for the following app ids:\n - `mempool`: `is_indexed`, `index_info`\n - `btc-rpc-explorer`: `is_indexed`, `index_info`\n - `electrs`: `initial_sync_done`, `block_height`,\n `blockheightPercent`, `info_sync`,\n `electrum_responding`,\n "
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error",
"description": "Last known encountered error for this app."
}
},
"type": "object",
"required": [
"id"
],
"title": "AppStatus"
},
"AppStatusQueryError": {
"properties": {
"id": {
"$ref": "#/components/schemas/AppId",
"description": "The app id"
},
"error": {
"type": "string",
"title": "Error",
"description": "The error description"
}
},
"type": "object",
"required": [
"id",
"error"
],
"title": "AppStatusQueryError"
},
"AppStatusQueryResult": {
"properties": {
"data": {
"items": {
"$ref": "#/components/schemas/AppStatus"
},
"type": "array",
"title": "Data",
"description": "Contains the successfully queried app statuses",
"default": []
},
"errors": {
"items": {
"$ref": "#/components/schemas/AppStatusQueryError"
},
"type": "array",
"title": "Errors",
"description": "Contains the error messages for unsuccessful queries",
"default": []
},
"timestamp": {
"type": "integer",
"title": "Timestamp",
"description": "The UTC timestamp of when the data was fetched",
"default": 0
}
},
"type": "object",
"title": "AppStatusQueryResult"
},
"AppUninstallInput": {
"properties": {
"app_id": {
"$ref": "#/components/schemas/AppId",
"description": "Id of the applications"
},
"keep_data": {
"type": "boolean",
"title": "Keep Data",
"description": "Whether to keep the app data",
"default": true
}
},
"type": "object",
"required": [
"app_id"
],
"title": "AppUninstallInput"
},
"Bip9Data": {
"properties": {
"status": {
@ -2175,7 +2608,8 @@
"warnings": {
"type": "string",
"title": "Warnings",
"description": "Any network and blockchain warnings"
"description": "Any network and blockchain warnings",
"default": ""
},
"softforks": {
"items": {
@ -2199,7 +2633,6 @@
"chainwork",
"size_on_disk",
"pruned",
"warnings",
"softforks"
],
"title": "BlockchainInfo"
@ -3632,7 +4065,8 @@
"warnings": {
"type": "string",
"title": "Warnings",
"description": "Any network and blockchain warnings"
"description": "Any network and blockchain warnings",
"default": ""
}
},
"type": "object",
@ -4297,6 +4731,47 @@
],
"title": "SoftFork"
},
"StartDoneData": {
"properties": {
"hostname": {
"type": "string",
"title": "Hostname",
"default": ""
},
"forceFreshSetup": {
"type": "boolean",
"title": "Forcefreshsetup",
"default": false
},
"keepBlockchain": {
"type": "boolean",
"title": "Keepblockchain",
"default": true
},
"lightning": {
"type": "string",
"title": "Lightning",
"default": ""
},
"passwordA": {
"type": "string",
"title": "Passworda",
"default": ""
},
"passwordB": {
"type": "string",
"title": "Passwordb",
"default": ""
},
"passwordC": {
"type": "string",
"title": "Passwordc",
"default": ""
}
},
"type": "object",
"title": "StartDoneData"
},
"SubSystemHealthInfo": {
"properties": {
"name": {
@ -4458,17 +4933,6 @@
],
"title": "TxType"
},
"UninstallData": {
"properties": {
"keepData": {
"type": "boolean",
"title": "Keepdata",
"default": true
}
},
"type": "object",
"title": "UninstallData"
},
"UnlockWalletInput": {
"properties": {
"password": {

View file

@ -6,29 +6,23 @@ authors = [{ name = "fusion44", email = "some.fusion@gmail.com" }]
requires-python = ">=3.11,<3.13"
license = "MIT"
dependencies = [
"fastapi[standard-no-fastapi-cloud-cli]==0.120.4",
"fastapi-plugins[redis]==0.14.0",
"fastapi[standard-no-fastapi-cloud-cli]==0.128.0",
"starlette==0.49.1",
"anyio==4.9.0",
"uvicorn[standard]==0.34.2",
"pydantic==2.10.6",
"pydantic-core==2.27.2",
"typing-extensions==4.12.2",
"uvicorn[standard]==0.40.0",
"pydantic==2.12.5",
"typing-extensions==4.15.0",
"pyjwt==2.10.1",
"python-decouple==3.8",
"psutil==7.0.0",
"requests==2.32.4",
"pyzmq==26.4.0",
"aiohttp==3.12.14",
"grpcio==1.71.0",
"grpcio-tools==1.71.0",
"protobuf==5.29.5",
"psutil==7.2.2",
"requests==2.32.5",
"pyzmq==27.1.0",
"aiohttp==3.13.3",
"grpcio==1.76.0",
"grpcio-tools==1.76.0",
"deepdiff==8.6.1",
"loguru==0.7.3",
"celery[redis]==5.5.2",
# Required for the fastapi-plugins[redis]
# Maybe remove and use redis-py directly instead as this is deprecated
"async_timeout==5.0.1",
"celery[redis]==5.6.2",
]
[project.scripts]
@ -36,13 +30,13 @@ api = "app.server:main"
[dependency-groups]
dev = [
"pytest==8.3.5",
"pytest-asyncio==0.25.3",
"coverage==7.8.0",
"ruff==0.9.6",
"debugpy==1.8.14",
"click==8.1.8",
"watchfiles==0.24.0",
"pytest==9.0.2",
"pytest-asyncio==1.3.0",
"coverage==7.13.2",
"ruff==0.14.14",
"debugpy==1.8.20",
"click==8.3.1",
"watchfiles==1.1.1",
]
[tool.hatch.build.targets.sdist]
@ -99,8 +93,15 @@ line-length = 88
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
target-version = "py311"
target_version = "py311"
[tool.ruff.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10
[tool.pytest.ini_options]
pythonpath = [
"app/external/result_type/src"
]
asyncio_mode = "auto"
norecursedirs = [".venv", ".devenv"]

View file

@ -2,12 +2,8 @@
# uv pip compile --all-extras --output-file requirements.txt pyproject.toml
aiohappyeyeballs==2.6.1
# via aiohttp
aiohttp==3.12.14
aiohttp==3.13.3
# via blitz-api (pyproject.toml)
aiojobs==1.4.0
# via fastapi-plugins
aiomcache==0.8.2
# via fastapi-plugins
aiosignal==1.4.0
# via aiohttp
amqp==5.3.1
@ -22,13 +18,11 @@ anyio==4.9.0
# httpx
# starlette
# watchfiles
async-timeout==5.0.1
# via blitz-api (pyproject.toml)
attrs==25.3.0
# via aiohttp
billiard==4.2.1
# via celery
celery==5.5.2
celery==5.6.2
# via blitz-api (pyproject.toml)
certifi==2025.4.26
# via
@ -37,7 +31,7 @@ certifi==2025.4.26
# requests
charset-normalizer==3.4.2
# via requests
click==8.1.8
click==8.3.1
# via
# celery
# click-didyoumean
@ -58,30 +52,24 @@ dnspython==2.7.0
# via email-validator
email-validator==2.2.0
# via fastapi
fastapi==0.120.4
# via
# blitz-api (pyproject.toml)
# fastapi-plugins
fastapi==0.128.0
# via blitz-api (pyproject.toml)
fastapi-cli==0.0.14
# via fastapi
fastapi-plugins==0.14.0
# via blitz-api (pyproject.toml)
frozenlist==1.6.0
# via
# aiohttp
# aiosignal
grpcio==1.71.0
grpcio==1.76.0
# via
# blitz-api (pyproject.toml)
# grpcio-tools
grpcio-tools==1.71.0
grpcio-tools==1.76.0
# via blitz-api (pyproject.toml)
h11==0.16.0
# via
# httpcore
# uvicorn
hiredis==3.1.1
# via redis
httpcore==1.0.9
# via httpx
httptools==0.6.4
@ -97,7 +85,7 @@ idna==3.10
# yarl
jinja2==3.1.6
# via fastapi
kombu==5.5.3
kombu==5.6.2
# via celery
loguru==0.7.3
# via blitz-api (pyproject.toml)
@ -113,32 +101,30 @@ multidict==6.4.3
# yarl
orderly-set==5.4.1
# via deepdiff
orjson==3.11.4
# via fastapi-plugins
packaging==25.0
# via kombu
prompt-toolkit==3.0.51
# via click-repl
propcache==0.3.1
# via
# aiohttp
# yarl
protobuf==5.29.5
# via
# blitz-api (pyproject.toml)
# grpcio-tools
psutil==7.0.0
protobuf==6.33.5
# via grpcio-tools
psutil==7.2.2
# via blitz-api (pyproject.toml)
pydantic==2.10.6
pydantic==2.12.5
# via
# blitz-api (pyproject.toml)
# fastapi
# fastapi-plugins
# pydantic-extra-types
# pydantic-settings
pydantic-core==2.27.2
# via
# blitz-api (pyproject.toml)
# pydantic
pydantic-core==2.41.5
# via pydantic
pydantic-extra-types==2.11.0
# via fastapi
pydantic-settings==2.9.1
# via fastapi-plugins
# via fastapi
pygments==2.19.1
# via rich
pyjwt==2.10.1
@ -151,19 +137,15 @@ python-dotenv==1.1.0
# via
# pydantic-settings
# uvicorn
python-json-logger==3.3.0
# via fastapi-plugins
python-multipart==0.0.20
# via fastapi
pyyaml==6.0.2
# via uvicorn
pyzmq==26.4.0
pyzmq==27.1.0
# via blitz-api (pyproject.toml)
redis==4.6.0
# via
# celery
# fastapi-plugins
requests==2.32.4
# via kombu
requests==2.32.5
# via blitz-api (pyproject.toml)
rich==14.0.0
# via
@ -183,26 +165,33 @@ starlette==0.49.1
# via
# blitz-api (pyproject.toml)
# fastapi
tenacity==9.1.2
# via fastapi-plugins
typer==0.15.3
# via fastapi-cli
typing-extensions==4.12.2
typing-extensions==4.15.0
# via
# blitz-api (pyproject.toml)
# aiosignal
# anyio
# fastapi
# grpcio
# pydantic
# pydantic-core
# pydantic-extra-types
# rich-toolkit
# starlette
# typer
# typing-inspection
typing-inspection==0.4.0
# via pydantic-settings
typing-inspection==0.4.2
# via
# pydantic
# pydantic-settings
tzdata==2025.2
# via kombu
urllib3==2.5.0
tzlocal==5.3.1
# via celery
urllib3==2.4.0
# via requests
uvicorn==0.34.2
uvicorn==0.40.0
# via
# blitz-api (pyproject.toml)
# fastapi
@ -214,7 +203,7 @@ vine==5.1.0
# amqp
# celery
# kombu
watchfiles==0.24.0
watchfiles==1.1.1
# via uvicorn
wcwidth==0.2.13
# via prompt-toolkit

1564
uv.lock generated

File diff suppressed because it is too large Load diff