8b55b9cf55
Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
3.5 KiB
Python
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
|