Files
HyperNode-AI/app/services/portal.py
T

91 lines
3.5 KiB
Python

"""控制台要看的实时快照。今日积分按产出公式预览,不写入流水。"""
from __future__ import annotations
from decimal import Decimal
from sqlalchemy import func, select
from sqlalchemy.orm import Session, selectinload
from app.clock import utcnow
from app.models import ComputeNode, NodeStatus, NodeYield, User, WithdrawalLog, WithdrawalStatus, YieldStatus
from app.money import money, to_decimal
from app.services.withdrawals import available_balance
from app.services.yield_engine import compute_node_yield
def settled_points(session: Session, user_id: int | None = None) -> Decimal:
query = select(NodeYield.points_delta).where(NodeYield.status == YieldStatus.SETTLED)
if user_id is not None:
query = query.where(NodeYield.user_id == user_id)
rows = session.scalars(query).all()
return money(sum((to_decimal(item) for item in rows), Decimal("0")))
def pending_withdrawal_amount(session: Session) -> Decimal:
rows = session.scalars(
select(WithdrawalLog.amount).where(WithdrawalLog.status == WithdrawalStatus.PENDING)
).all()
return money(sum((to_decimal(item) for item in rows), Decimal("0")))
def authorized_amount(session: Session) -> Decimal:
rows = session.scalars(select(ComputeNode.purchase_amount)).all()
return money(sum((to_decimal(item) for item in rows), Decimal("0")))
def node_counts(session: Session) -> tuple[int, int]:
nodes = session.scalar(select(func.count()).select_from(ComputeNode)) or 0
online = session.scalar(
select(func.count()).select_from(ComputeNode).where(ComputeNode.status == NodeStatus.ONLINE)
) or 0
return nodes, online
def live_nodes(session: Session, user_id: int | None = None) -> list[dict]:
query = select(ComputeNode).options(selectinload(ComputeNode.user)).order_by(ComputeNode.id.desc())
if user_id is not None:
query = query.where(ComputeNode.user_id == user_id)
today = utcnow().date()
snapshots = []
for node in session.scalars(query).all():
computed = compute_node_yield(session, node, today)
snapshots.append(
{
"id": node.id,
"sn": node.sn,
"user_id": node.user_id,
"wallet_address": node.user.wallet_address,
"purchase_amount": node.purchase_amount,
"license_months": node.license_months,
"licensed_at": node.licensed_at,
"license_expires_at": node.license_expires_at,
"status": node.status,
"last_heartbeat_at": node.last_heartbeat_at,
"callback_url": node.callback_url,
"online_rate": computed.online_rate,
"today_points": computed.points_delta if computed.eligible else Decimal("0"),
}
)
return snapshots
def user_rows(session: Session) -> list[dict]:
counts = dict(
session.execute(select(ComputeNode.user_id, func.count()).group_by(ComputeNode.user_id)).all()
)
rows = []
for user in session.scalars(select(User).order_by(User.id.desc())).all():
rows.append(
{
"id": user.id,
"wallet_address": user.wallet_address,
"username": user.username,
"role": user.role,
"created_at": user.created_at,
"node_count": int(counts.get(user.id, 0)),
"available_points": available_balance(session, user.id),
}
)
return rows