refactor: switch to domain driven directory layout

This commit is contained in:
fusion44 2022-10-03 20:22:00 +02:00
parent e1d5e23db7
commit ba453e7bdb
No known key found for this signature in database
68 changed files with 340 additions and 357 deletions

View file

@ -12,8 +12,8 @@ from typing import Dict, Optional
from fastapi.encoders import jsonable_encoder
from fastapi_plugins import redis_plugin
from app.api.sse_manager import SSEManager
from app.external.sse_starlette import ServerSentEvent
from app.sse_manager import SSEManager
sse_mgr = SSEManager()
sse_mgr.setup()

View file

@ -1,14 +1,14 @@
import asyncio
from typing import List
from app.repositories.bitcoin import get_btc_info
from app.repositories.lightning import (
from app.bitcoind.service import get_btc_info
from app.lightning.service import (
get_fee_revenue,
get_ln_info,
get_ln_info_lite,
get_wallet_balance,
)
from app.repositories.system import get_hardware_info, get_system_info
from app.system.service import get_hardware_info, get_system_info
async def get_bitcoin_client_warmup_data() -> List:

View file

@ -1,4 +1,4 @@
from app.repositories.apps_impl.apps_base import AppsBase
from app.apps.impl.apps_base import AppsBase
class NativePythonApps(AppsBase):

View file

@ -9,14 +9,20 @@ from decouple import config
from fastapi import HTTPException, status
from fastapi.encoders import jsonable_encoder
from app.core_utils import (
SSE,
broadcast_sse_msg,
call_sudo_script,
parse_key_value_text,
)
from app.repositories.apps_impl.apps_base import AppsBase
from app.repositories.utils.raspiblitz import available_app_ids
from app.api.utils import SSE, broadcast_sse_msg, call_sudo_script, parse_key_value_text
from app.apps.impl import AppsBase
available_app_ids = {
"btc-rpc-explorer",
"rtl",
# Specter is deactivated for now because it uses its own self signed HTTPS cert that makes trouble in Chrome on last test
# "specter",
"btcpayserver",
"lnbits",
"mempool",
"thunderhub",
}
SHELL_SCRIPT_PATH = config("shell_script_path")

View file

@ -2,8 +2,8 @@ from fastapi import APIRouter, HTTPException, status
from fastapi.params import Depends
from pydantic import BaseModel
import app.repositories.apps as repo
import app.routers.apps_docs as docs
import app.apps.docs as docs
import app.apps.service as repo
from app.auth.auth_bearer import JWTBearer
from app.external.sse_starlette import EventSourceResponse

View file

@ -1,14 +1,14 @@
from decouple import config
from app.models.system import APIPlatform
from app.system.models import APIPlatform
PLATFORM = config("platform", default=APIPlatform.RASPIBLITZ)
apps = None
if PLATFORM == APIPlatform.RASPIBLITZ:
from .apps_impl.raspiblitz import RaspiBlitzApps as Apps
from app.apps.impl.raspiblitz import RaspiBlitzApps as Apps
elif PLATFORM == APIPlatform.NATIVE_PYTHON:
from .apps_impl.native_python import NativePythonApps as Apps
from app.apps.impl.native_python import NativePythonApps as Apps
apps = Apps()

View file

@ -2,17 +2,17 @@ from fastapi import APIRouter, HTTPException, Request, status
from fastapi.params import Depends, Query
from app.auth.auth_bearer import JWTBearer
from app.external.sse_starlette import EventSourceResponse
from app.models.bitcoind import BlockchainInfo, BtcInfo, FeeEstimationMode, NetworkInfo
from app.repositories.bitcoin import (
from app.bitcoind.docs import blocks_sub_doc, estimate_fee_mode_desc
from app.bitcoind.models import BlockchainInfo, BtcInfo, FeeEstimationMode, NetworkInfo
from app.bitcoind.service import (
estimate_fee,
get_blockchain_info,
get_btc_info,
get_network_info,
handle_block_sub,
)
from app.repositories.utils.bitcoin import bitcoin_rpc
from app.routers.bitcoin_docs import blocks_sub_doc, estimate_fee_mode_desc
from app.bitcoind.utils import bitcoin_rpc
from app.external.sse_starlette import EventSourceResponse
_PREFIX = "bitcoin"

View file

@ -10,15 +10,15 @@ from fastapi import Request
from fastapi.exceptions import HTTPException
from starlette import status
from app.core_utils import SSE, broadcast_sse_msg
from app.models.bitcoind import (
from app.api.utils import SSE, broadcast_sse_msg
from app.bitcoind.models import (
BlockchainInfo,
BlockRpcFunc,
BtcInfo,
FeeEstimationMode,
NetworkInfo,
)
from app.repositories.utils.bitcoin import bitcoin_config, bitcoin_rpc_async
from app.bitcoind.utils import bitcoin_config, bitcoin_rpc_async
_initialized = False

View file

@ -6,7 +6,7 @@ import requests
from decouple import config
from starlette import status
from app.models.bitcoind import BlockRpcFunc
from app.bitcoind.models import BlockRpcFunc
class _BitcoinConfig:

View file

@ -1,3 +1,68 @@
tx_id_desc = """
Unique identifier for this transaction.
Depending on the type of the transaction it will be different:
#### On-chain
The transaction hash
#### Lightning Invoice and Payment
The payment request
"""
tx_amount_desc = """
The value of the transaction, depending on the category in satoshis or millisatoshis.
#### On-chain
Transaction amount in satoshis
#### Lightning Invoice
* value in millisatoshis of the invoice if *unsettled*
* amount in millisatoshis paid if invoice is *settled*
#### Lightning Payment
* amount sent in millisatoshis
"""
tx_status_desc = """
The status of the transaction. Depending on the transaction category this can be different values:
May have different meanings in different situations:
#### unknown
An unknown state was found.
#### in_flight
* A lightning payment is being sent
* An invoice is waiting for the incoming payment
* An on-chain transaction is waiting in the mempool
#### succeeded
* A lighting payment was successfully sent
* An incoming payment was received for an invoice
* An on-chain transaction was included in a block
#### failed
* A lightning payment attempt which could not be completed (no route found, insufficient funds, ...)
* An invoice is expired or some other error happened
"""
tx_time_stamp_desc = """
The unix timestamp in seconds for the transaction.
The timestamp can mean different things in different situations:
#### Lightning Invoice
* Creation date for in-flight or failed invoices
* Settle date for succeeded invoices
#### On-chain
* Creation date for transaction waiting in the mempool
* Timestamp of the block where this transaction is included
#### Lightning Payment
"""
add_invoice_desc = """
Adds a new invoice to the database.

View file

@ -11,11 +11,13 @@ from decouple import config
from fastapi.exceptions import HTTPException
from starlette import status
import app.repositories.ln_impl.protos.cln.node_pb2 as ln
import app.repositories.ln_impl.protos.cln.node_pb2_grpc as clnrpc
import app.repositories.ln_impl.protos.cln.primitives_pb2 as lnp
from app.core_utils import config_get_hex_str, next_push_id
from app.models.lightning import (
import app.lightning.impl.protos.cln.node_pb2 as ln
import app.lightning.impl.protos.cln.node_pb2_grpc as clnrpc
import app.lightning.impl.protos.cln.primitives_pb2 as lnp
from app.api.utils import config_get_hex_str, next_push_id
from app.bitcoind.utils import bitcoin_rpc_async
from app.lightning.impl.ln_base import LightningNodeBase
from app.lightning.models import (
Channel,
FeeRevenue,
ForwardSuccessEvent,
@ -35,8 +37,6 @@ from app.models.lightning import (
TxStatus,
WalletBalance,
)
from app.repositories.ln_impl.ln_base import LightningNodeBase
from app.repositories.utils.bitcoin import bitcoin_rpc_async
async def _make_local_call(cmd: str):

View file

@ -1,7 +1,7 @@
from abc import abstractmethod
from typing import AsyncGenerator, List, Optional
from app.models.lightning import (
from app.lightning.models import (
Channel,
FeeRevenue,
ForwardSuccessEvent,

View file

@ -14,7 +14,7 @@ import app.repositories.ln_impl.protos.lnd.router_pb2 as router
import app.repositories.ln_impl.protos.lnd.router_pb2_grpc as routerrpc
import app.repositories.ln_impl.protos.lnd.walletunlocker_pb2 as unlocker
import app.repositories.ln_impl.protos.lnd.walletunlocker_pb2_grpc as unlockerrpc
from app.core_utils import SSE, broadcast_sse_msg, config_get_hex_str
from app.api.utils import SSE, broadcast_sse_msg, config_get_hex_str
from app.models.lightning import (
Channel,
FeeRevenue,

View file

@ -2,7 +2,7 @@
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import app.repositories.ln_impl.protos.cln.node_pb2 as node__pb2
import app.lightning.impl.protos.cln.node_pb2 as node__pb2
class NodeStub(object):

View file

@ -6,7 +6,7 @@ from decouple import config
from fastapi.exceptions import HTTPException
from starlette import status
from app.core_utils import call_script2, redis_get
from app.api.utils import call_script2, redis_get
from app.models.lightning import (
Channel,
FeeRevenue,

View file

@ -7,7 +7,7 @@ from fastapi.param_functions import Query
from pydantic import BaseModel
from pydantic.types import conint
import app.models.lightning_docs as docs
import app.lightning.docs as docs
class LnInitState(str, Enum):

View file

@ -4,7 +4,15 @@ from fastapi import APIRouter, HTTPException, Query, status
from fastapi.params import Depends
from app.auth.auth_bearer import JWTBearer
from app.models.lightning import (
from app.lightning.docs import (
get_balance_response_desc,
new_address_desc,
open_channel_desc,
send_coins_desc,
send_payment_desc,
unlock_wallet_desc,
)
from app.lightning.models import (
Channel,
FeeRevenue,
GenericTx,
@ -20,7 +28,7 @@ from app.models.lightning import (
UnlockWalletInput,
WalletBalance,
)
from app.repositories.lightning import (
from app.lightning.service import (
add_invoice,
channel_close,
channel_list,
@ -39,14 +47,6 @@ from app.repositories.lightning import (
send_payment,
unlock_wallet,
)
from app.routers.lightning_docs import (
get_balance_response_desc,
new_address_desc,
open_channel_desc,
send_coins_desc,
send_payment_desc,
unlock_wallet_desc,
)
_PREFIX = "lightning"

View file

@ -6,8 +6,8 @@ from decouple import config
from fastapi import status
from fastapi.exceptions import HTTPException
from app.core_utils import SSE, broadcast_sse_msg, redis_get
from app.models.lightning import (
from app.api.utils import SSE, broadcast_sse_msg, redis_get
from app.lightning.models import (
Channel,
FeeRevenue,
GenericTx,
@ -22,17 +22,17 @@ from app.models.lightning import (
SendCoinsInput,
SendCoinsResponse,
)
from app.models.system import APIPlatform
from app.system.models import APIPlatform
PLATFORM = config("platform", cast=str)
ln_node = config("ln_node")
if ln_node == "lnd_grpc":
from app.repositories.ln_impl.lnd_grpc import LnNodeLNDgRPC as LnNode
from app.lightning.impl.lnd_grpc import LnNodeLNDgRPC as LnNode
elif ln_node == "cln_grpc" and PLATFORM != APIPlatform.RASPIBLITZ:
from app.repositories.ln_impl.cln_grpc import LnNodeCLNgRPC as LnNode
from app.lightning.impl.cln_grpc import LnNodeCLNgRPC as LnNode
elif ln_node == "cln_grpc" and PLATFORM == APIPlatform.RASPIBLITZ:
from app.repositories.ln_impl.specializations.cln_grpc_blitz import (
from app.lightning.impl.specializations.cln_grpc_blitz import (
LnNodeCLNgRPCBlitz as LnNode,
)
elif ln_node == "none":

View file

@ -15,29 +15,34 @@ from starlette import status
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import RedirectResponse
from app.api.models import ApiStartupStatus, StartupState
from app.api.utils import SSE, broadcast_sse_msg, build_sse_event, sse_mgr
from app.api.warmup import (
get_bitcoin_client_warmup_data,
get_full_client_warmup_data,
get_full_client_warmup_data_bitcoinonly,
)
from app.apps import router
from app.apps.router import router as app_router
from app.auth.auth_bearer import JWTBearer
from app.auth.auth_handler import (
handle_local_cookie,
register_cookie_updater,
remove_local_cookie,
)
from app.core_utils import SSE, broadcast_sse_msg, build_sse_event, sse_mgr
from app.external.fastapi_versioning import VersionedFastAPI
from app.models.api import ApiStartupStatus, StartupState
from app.models.lightning import LnInitState
from app.repositories.bitcoin import (
from app.bitcoind.router import router as bitcoin_router
from app.bitcoind.service import (
initialize_bitcoin_repo,
register_bitcoin_status_gatherer,
register_bitcoin_zmq_sub,
)
from app.repositories.lightning import initialize_ln_repo, register_lightning_listener
from app.repositories.system import get_hardware_info, register_hardware_info_gatherer
from app.routers import apps, bitcoin, lightning, setup, system
from app.warmup import (
get_bitcoin_client_warmup_data,
get_full_client_warmup_data,
get_full_client_warmup_data_bitcoinonly,
)
from app.external.fastapi_versioning import VersionedFastAPI
from app.lightning.models import LnInitState
from app.lightning.router import router as ln_router
from app.lightning.service import initialize_ln_repo, register_lightning_listener
from app.setup.router import router as setup_router
from app.system.router import router as system_router
from app.system.service import get_hardware_info, register_hardware_info_gatherer
logging.basicConfig(level=logging.WARNING)
@ -52,13 +57,13 @@ class AppSettings(RedisSettings):
unversioned_app = FastAPI()
config = get_config()
unversioned_app.include_router(apps.router)
unversioned_app.include_router(bitcoin.router)
unversioned_app.include_router(app_router)
unversioned_app.include_router(bitcoin_router)
if node_type != "none":
unversioned_app.include_router(lightning.router)
unversioned_app.include_router(system.router)
if setup.router is not None:
unversioned_app.include_router(setup.router)
unversioned_app.include_router(ln_router)
unversioned_app.include_router(system_router)
if setup_router is not None:
unversioned_app.include_router(setup_router)
app = VersionedFastAPI(

View file

@ -1,64 +0,0 @@
tx_id_desc = """
Unique identifier for this transaction.
Depending on the type of the transaction it will be different:
#### On-chain
The transaction hash
#### Lightning Invoice and Payment
The payment request
"""
tx_amount_desc = """
The value of the transaction, depending on the category in satoshis or millisatoshis.
#### On-chain
Transaction amount in satoshis
#### Lightning Invoice
* value in millisatoshis of the invoice if *unsettled*
* amount in millisatoshis paid if invoice is *settled*
#### Lightning Payment
* amount sent in millisatoshis
"""
tx_status_desc = """
The status of the transaction. Depending on the transaction category this can be different values:
May have different meanings in different situations:
#### unknown
An unknown state was found.
#### in_flight
* A lightning payment is being sent
* An invoice is waiting for the incoming payment
* An on-chain transaction is waiting in the mempool
#### succeeded
* A lighting payment was successfully sent
* An incoming payment was received for an invoice
* An on-chain transaction was included in a block
#### failed
* A lightning payment attempt which could not be completed (no route found, insufficient funds, ...)
* An invoice is expired or some other error happened
"""
tx_time_stamp_desc = """
The unix timestamp in seconds for the transaction.
The timestamp can mean different things in different situations:
#### Lightning Invoice
* Creation date for in-flight or failed invoices
* Settle date for succeeded invoices
#### On-chain
* Creation date for transaction waiting in the mempool
* Timestamp of the block where this transaction is included
#### Lightning Payment
"""

View file

@ -1,11 +0,0 @@
from abc import abstractmethod
class HardwareBase:
@abstractmethod
async def get_hardware_info(self) -> map:
raise NotImplementedError()
@abstractmethod
def get_hardware_info_yield_time(self) -> float:
raise NotImplementedError()

View file

@ -1,73 +0,0 @@
import time
from app.core_utils import redis_get
from app.repositories.hardware_impl.hardware_base import HardwareBase
_HW_INFO_YIELD_TIME = 2
class RaspiBlitzHardware(HardwareBase):
async def get_hardware_info(self) -> map:
info = {}
loads = (await redis_get("system_cpu_load")).split(",")
iloads = []
total = 0
for l in loads:
value = float(l)
total += value
iloads.append(value)
info["cpu_overall_percent"] = round(total / len(loads), 2)
info["cpu_per_cpu_percent"] = iloads
info["vram_total_bytes"] = int(await redis_get("system_ram_mb")) * 1000 * 1000
info["vram_available_bytes"] = (
int(await redis_get("system_ram_available_mb")) * 1000 * 1000
)
info["vram_used_bytes"] = (
info["vram_total_bytes"] - info["vram_available_bytes"]
)
info["vram_usage_percent"] = round(
(100 / info["vram_total_bytes"]) * info["vram_used_bytes"], 2
)
info["temperatures_celsius"] = {
"system_temp": float(await redis_get("system_temp_celsius")),
"coretemp": [],
}
now = time.time()
boot = float(await redis_get("system_up"))
info["boot_time_timestamp"] = now - boot
info["networks"] = {
"internet_online": await redis_get("internet_online"),
"tor_web_addr": await redis_get("tor_web_addr"),
"internet_localip": await redis_get("internet_localip"),
"internet_localiprange": await redis_get("internet_localiprange"),
}
# the following is just available when setup is done
setup_phase = await redis_get("setupPhase")
info["disks"] = []
if setup_phase == "done":
total = int(await redis_get("hdd_capacity_bytes"))
free = int(await redis_get("hdd_free_bytes"))
info["disks"] = [
{
"device": "/",
"mountpoint": "/",
"filesystem_type": "ext4",
"partition_total_bytes": total,
"partition_used_bytes": total - free,
"partition_free_bytes": free,
"partition_percent": round((100 / total) * free, 2),
}
]
return info
def get_hardware_info_yield_time(self) -> float:
return _HW_INFO_YIELD_TIME

View file

@ -1,9 +0,0 @@
from decouple import config
from app.models.system import APIPlatform
router = None
_PLATFORM = config("platform", default=APIPlatform.RASPIBLITZ)
if _PLATFORM == APIPlatform.RASPIBLITZ:
from app.repositories.setup_impl.raspiblitz.router import router

View file

@ -1,2 +0,0 @@
### Setup
Since the setup is not highly specific to the underlying platform, we don't provide an abstraction to it like in the other parts of the framework. Instead, the platform should provide a router that is simply attached to the main router in `main.py` by the API.

View file

@ -1,70 +0,0 @@
import logging
import secrets
from typing import Dict
from decouple import config
from fastapi import HTTPException, status
from app.auth.auth_handler import sign_jwt
from app.constants import API_VERSION
from app.models.system import (
APIPlatform,
ConnectionInfo,
LoginInput,
RawDebugLogData,
SystemInfo,
)
from app.repositories.lightning import get_ln_info
from app.repositories.system_impl.system_base import SystemBase
class NativePythonSystem(SystemBase):
async def get_system_info(self) -> SystemInfo:
lninfo = await get_ln_info()
version = config("np_version", default="")
tor_api = config("np_tor_address_api_endpoint", default="")
tor_api_docs = config("np_tor_address_api_docs", default="")
lan_api = config("np_local_address_api_endpoint", default="")
lan_api_docs = config("np_local_address_api_docs", default="")
ssh_address = config("np_ssh_address", default="")
return SystemInfo(
alias=lninfo.alias,
color=lninfo.color,
platform=APIPlatform.NATIVE_PYTHON,
platform_version=version,
api_version=API_VERSION,
tor_web_ui=tor_api_docs,
tor_api=tor_api,
lan_web_ui=lan_api_docs,
lan_api=lan_api,
ssh_address=ssh_address,
chain=lninfo.chains[0].network,
)
async def shutdown(self, reboot: bool) -> bool:
logging.info("Shutdown / reboot not supported in native_python mode.")
return False
async def get_connection_info(self) -> ConnectionInfo:
# return an empty connection info object for now
return ConnectionInfo()
async def login(self, i: LoginInput) -> Dict[str, str]:
matches = secrets.compare_digest(i.password, config("login_password", cast=str))
if matches:
return sign_jwt()
raise HTTPException(
status.HTTP_401_UNAUTHORIZED, detail="Password is incorrect"
)
async def change_password(self, type: str, old_password: str, new_password: str):
raise NotImplementedError()
async def get_debug_logs_raw(self) -> RawDebugLogData:
raise NotImplementedError()

View file

@ -1 +0,0 @@
from app.repositories.setup import router

View file

2
app/setup/README.md Normal file
View file

@ -0,0 +1,2 @@
### Setup
Since the setup is not highly specific to the underlying platform, we don't provide an abstraction to it like in the other parts of the framework. Instead, the platform implementation itself should provide a router that is simply attached to the main router in `main.py` by the API.

View file

@ -0,0 +1,3 @@
# TODO
Split router into `router.py` and `service.py` (or something like that)

View file

@ -4,11 +4,11 @@ from fastapi import APIRouter, HTTPException, status
from fastapi.params import Depends
from pydantic import BaseModel
from app.api.utils import call_script, parse_key_value_lines, redis_get
from app.auth.auth_bearer import JWTBearer
from app.auth.auth_handler import sign_jwt
from app.core_utils import call_script, parse_key_value_lines, redis_get
from app.repositories.system_impl.raspiblitz import RaspiBlitzSystem
from app.repositories.utils.raspiblitz import name_valid, password_valid
from app.system.impl.raspiblitz import RaspiBlitzSystem
from app.system.impl.raspiblitz_utils import name_valid, password_valid
router = APIRouter(prefix="/setup", tags=["RaspiBlitz Setup"])

9
app/setup/router.py Normal file
View file

@ -0,0 +1,9 @@
from decouple import config
from app.system.models import APIPlatform
router = None
_PLATFORM = config("platform", default=APIPlatform.RASPIBLITZ)
if _PLATFORM != APIPlatform.RASPIBLITZ:
from app.setup.impl.raspiblitz.router import router

View file

@ -1,14 +1,79 @@
import logging
import secrets
from typing import Dict
import psutil
from decouple import config
from fastapi import HTTPException, status
from app.repositories.hardware_impl.hardware_base import HardwareBase
from app.api.constants import API_VERSION
from app.auth.auth_handler import sign_jwt
from app.lightning.service import get_ln_info
from app.system.impl.system_base import SystemBase
from app.system.models import (
APIPlatform,
ConnectionInfo,
LoginInput,
RawDebugLogData,
SystemInfo,
)
_SLEEP_TIME = config("gather_hw_info_interval", default=2, cast=float)
_CPU_AVG_PERIOD = config("cpu_usage_averaging_period", default=0.5, cast=float)
_HW_INFO_YIELD_TIME = _SLEEP_TIME + _CPU_AVG_PERIOD
class NativePythonHardware(HardwareBase):
class NativePythonSystem(SystemBase):
async def get_system_info(self) -> SystemInfo:
lninfo = await get_ln_info()
version = config("np_version", default="")
tor_api = config("np_tor_address_api_endpoint", default="")
tor_api_docs = config("np_tor_address_api_docs", default="")
lan_api = config("np_local_address_api_endpoint", default="")
lan_api_docs = config("np_local_address_api_docs", default="")
ssh_address = config("np_ssh_address", default="")
return SystemInfo(
alias=lninfo.alias,
color=lninfo.color,
platform=APIPlatform.NATIVE_PYTHON,
platform_version=version,
api_version=API_VERSION,
tor_web_ui=tor_api_docs,
tor_api=tor_api,
lan_web_ui=lan_api_docs,
lan_api=lan_api,
ssh_address=ssh_address,
chain=lninfo.chains[0].network,
)
async def shutdown(self, reboot: bool) -> bool:
logging.info("Shutdown / reboot not supported in native_python mode.")
return False
async def get_connection_info(self) -> ConnectionInfo:
# return an empty connection info object for now
return ConnectionInfo()
async def login(self, i: LoginInput) -> Dict[str, str]:
matches = secrets.compare_digest(i.password, config("login_password", cast=str))
if matches:
return sign_jwt()
raise HTTPException(
status.HTTP_401_UNAUTHORIZED, detail="Password is incorrect"
)
async def change_password(self, type: str, old_password: str, new_password: str):
raise NotImplementedError()
async def get_debug_logs_raw(self) -> RawDebugLogData:
raise NotImplementedError()
async def get_hardware_info(self) -> map:
info = {}

View file

@ -1,14 +1,14 @@
import asyncio
import logging
import os
import time
from typing import Dict
from decouple import config
from fastapi import HTTPException, status
from app.auth.auth_handler import sign_jwt
from app.constants import API_VERSION
from app.core_utils import (
from app.api.constants import API_VERSION
from app.api.utils import (
SSE,
broadcast_sse_msg,
call_script,
@ -16,16 +16,19 @@ from app.core_utils import (
parse_key_value_text,
redis_get,
)
from app.models.system import (
from app.auth.auth_handler import sign_jwt
from app.lightning.service import get_ln_info
from app.system.impl.raspiblitz_utils import password_valid
from app.system.impl.system_base import SystemBase
from app.system.models import (
APIPlatform,
ConnectionInfo,
LoginInput,
RawDebugLogData,
SystemInfo,
)
from app.repositories.lightning import get_ln_info
from app.repositories.system_impl.system_base import SystemBase
from app.repositories.utils.raspiblitz import password_valid
_HW_INFO_YIELD_TIME = 2
SHELL_SCRIPT_PATH = config("shell_script_path")
GET_DEBUG_LOG_SCRIPT = os.path.join(
@ -288,3 +291,68 @@ class RaspiBlitzSystem(SystemBase):
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"{cmd} returned no error and no output.",
)
async def get_hardware_info(self) -> map:
info = {}
loads = (await redis_get("system_cpu_load")).split(",")
iloads = []
total = 0
for l in loads:
value = float(l)
total += value
iloads.append(value)
info["cpu_overall_percent"] = round(total / len(loads), 2)
info["cpu_per_cpu_percent"] = iloads
info["vram_total_bytes"] = int(await redis_get("system_ram_mb")) * 1000 * 1000
info["vram_available_bytes"] = (
int(await redis_get("system_ram_available_mb")) * 1000 * 1000
)
info["vram_used_bytes"] = (
info["vram_total_bytes"] - info["vram_available_bytes"]
)
info["vram_usage_percent"] = round(
(100 / info["vram_total_bytes"]) * info["vram_used_bytes"], 2
)
info["temperatures_celsius"] = {
"system_temp": float(await redis_get("system_temp_celsius")),
"coretemp": [],
}
now = time.time()
boot = float(await redis_get("system_up"))
info["boot_time_timestamp"] = now - boot
info["networks"] = {
"internet_online": await redis_get("internet_online"),
"tor_web_addr": await redis_get("tor_web_addr"),
"internet_localip": await redis_get("internet_localip"),
"internet_localiprange": await redis_get("internet_localiprange"),
}
# the following is just available when setup is done
setup_phase = await redis_get("setupPhase")
info["disks"] = []
if setup_phase == "done":
total = int(await redis_get("hdd_capacity_bytes"))
free = int(await redis_get("hdd_free_bytes"))
info["disks"] = [
{
"device": "/",
"mountpoint": "/",
"filesystem_type": "ext4",
"partition_total_bytes": total,
"partition_used_bytes": total - free,
"partition_free_bytes": free,
"partition_percent": round((100 / total) * free, 2),
}
]
return info
def get_hardware_info_yield_time(self) -> float:
return _HW_INFO_YIELD_TIME

View file

@ -1,20 +1,5 @@
import re
from decouple import config
SHELL_SCRIPT_PATH = config("shell_script_path")
available_app_ids = {
"btc-rpc-explorer",
"rtl",
# Specter is deactivated for now because it uses its own self signed HTTPS cert that makes trouble in Chrome on last test
# "specter",
"btcpayserver",
"lnbits",
"mempool",
"thunderhub",
}
def password_valid(password: str):
if len(password) < 8:

View file

@ -1,7 +1,7 @@
from abc import abstractmethod
from typing import Dict
from app.models.system import ConnectionInfo, LoginInput, RawDebugLogData, SystemInfo
from app.system.models import ConnectionInfo, LoginInput, RawDebugLogData, SystemInfo
class SystemBase:
@ -28,3 +28,11 @@ class SystemBase:
@abstractmethod
async def get_debug_logs_raw(self) -> RawDebugLogData:
raise NotImplementedError()
@abstractmethod
async def get_hardware_info(self) -> map:
raise NotImplementedError()
@abstractmethod
def get_hardware_info_yield_time(self) -> float:
raise NotImplementedError()

View file

@ -7,7 +7,7 @@ from fastapi.param_functions import Query
from pydantic import BaseModel
from pydantic.types import constr
from app.routers.system_docs import get_debug_data_sample_str
from app.system.docs import get_debug_data_sample_str
class LoginInput(BaseModel):

View file

@ -3,12 +3,18 @@ from typing import Optional
from fastapi import APIRouter, HTTPException, Request, status
from fastapi.params import Depends, Query
from app.api.utils import SSE
from app.auth.auth_bearer import JWTBearer
from app.auth.auth_handler import sign_jwt
from app.core_utils import SSE
from app.external.sse_starlette import EventSourceResponse
from app.models.system import ConnectionInfo, LoginInput, RawDebugLogData, SystemInfo
from app.repositories.system import (
from app.system.docs import (
get_debug_logs_raw_desc,
get_debug_logs_raw_resp_desc,
get_debug_logs_raw_summary,
get_hw_info_json,
)
from app.system.models import ConnectionInfo, LoginInput, RawDebugLogData, SystemInfo
from app.system.service import (
HW_INFO_YIELD_TIME,
change_password,
get_connection_info,
@ -19,12 +25,6 @@ from app.repositories.system import (
shutdown,
subscribe_hardware_info,
)
from app.routers.system_docs import (
get_debug_logs_raw_desc,
get_debug_logs_raw_resp_desc,
get_debug_logs_raw_summary,
get_hw_info_json,
)
_PREFIX = "system"

View file

@ -4,8 +4,8 @@ from typing import Dict, Optional
from decouple import config
from fastapi import HTTPException, Request, status
from app.core_utils import SSE, broadcast_sse_msg
from app.models.system import (
from app.api.utils import SSE, broadcast_sse_msg
from app.system.models import (
APIPlatform,
ConnectionInfo,
LoginInput,
@ -15,20 +15,17 @@ from app.models.system import (
PLATFORM = config("platform", default=APIPlatform.RASPIBLITZ)
if PLATFORM == APIPlatform.RASPIBLITZ:
from .hardware_impl.raspiblitz import RaspiBlitzHardware as Hardware
from .system_impl.raspiblitz import RaspiBlitzSystem as System
from app.system.impl.raspiblitz import RaspiBlitzSystem as System
elif PLATFORM == APIPlatform.NATIVE_PYTHON:
from .hardware_impl.native_python import NativePythonHardware as Hardware
from .system_impl.native_python import NativePythonSystem as System
from app.system.impl.native_python import NativePythonSystem as System
system = System()
hw = Hardware()
if hw is None or system is None:
if system is None:
raise RuntimeError(f"Unknown platform {PLATFORM}")
HW_INFO_YIELD_TIME = hw.get_hardware_info_yield_time()
HW_INFO_YIELD_TIME = system.get_hardware_info_yield_time()
async def change_password(type: Optional[str], old_password: str, new_password: str):
@ -51,7 +48,7 @@ async def get_system_info() -> SystemInfo:
async def get_hardware_info() -> map:
try:
return await hw.get_hardware_info()
return await system.get_hardware_info()
except HTTPException as r:
raise
except NotImplementedError as r:

View file

@ -1,4 +1,4 @@
from app.models.bitcoind import *
from app.bitcoind.models import *
blockhain_info = {
"chain": "main",

View file

@ -2,7 +2,7 @@ import pytest
from pydantic import AnyStrMinLengthError, ValidationError
import app.repositories.system_impl.native_python as npy
from app.models.system import LoginInput
from app.system.models import LoginInput
@pytest.mark.asyncio

View file

@ -1,8 +1,8 @@
import pytest
from fastapi import HTTPException, status
import app.repositories.system as sys
from app.models.system import LoginInput
import app.system.service as sys
from app.system.models import LoginInput
@pytest.mark.asyncio