2bbdb00a4d
包含节点账本、每日清算,以及 Ubuntu 交互式部署脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
157 lines
3.5 KiB
Python
157 lines
3.5 KiB
Python
"""接口请求与响应。金额在 JSON 里用字符串,避免浮点误差。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import date, datetime
|
|
from decimal import Decimal
|
|
from typing import Annotated
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, PlainSerializer
|
|
|
|
from app.models import NodeStatus, TaskStatus, WithdrawalStatus, YieldStatus
|
|
|
|
SN = Annotated[str, Field(min_length=4, max_length=64, pattern=r"^[A-Za-z0-9_-]+$")]
|
|
WALLET = Annotated[str, Field(min_length=4, max_length=128, pattern=r"^[A-Za-z0-9:_-]+$")]
|
|
MoneyText = Annotated[Decimal, PlainSerializer(lambda value: format(value, "f"), return_type=str)]
|
|
|
|
|
|
class APIModel(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class UserCreate(APIModel):
|
|
wallet_address: WALLET
|
|
|
|
|
|
class UserOut(APIModel):
|
|
id: int
|
|
wallet_address: str
|
|
created_at: datetime
|
|
|
|
|
|
class NodeCreate(APIModel):
|
|
wallet_address: WALLET
|
|
sn: SN
|
|
purchase_amount: Decimal = Field(gt=0, max_digits=24, decimal_places=8)
|
|
callback_url: str | None = None
|
|
|
|
|
|
class NodeOut(APIModel):
|
|
id: int
|
|
user_id: int
|
|
sn: str
|
|
purchase_amount: MoneyText
|
|
license_months: int
|
|
licensed_at: datetime
|
|
license_expires_at: datetime
|
|
status: NodeStatus
|
|
last_heartbeat_at: datetime | None
|
|
callback_url: str | None
|
|
|
|
|
|
class HeartbeatIn(APIModel):
|
|
sn: SN
|
|
|
|
|
|
class HeartbeatOut(APIModel):
|
|
sn: str
|
|
status: NodeStatus
|
|
last_heartbeat_at: datetime
|
|
server_time: datetime
|
|
|
|
|
|
class TaskOut(APIModel):
|
|
task_id: str
|
|
task_type: str
|
|
payload: dict
|
|
status: TaskStatus
|
|
dispatched_at: datetime
|
|
deadline_at: datetime
|
|
|
|
|
|
class TaskReportIn(APIModel):
|
|
sn: SN
|
|
task_id: str = Field(min_length=36, max_length=36)
|
|
success: bool
|
|
nonce: str = Field(min_length=8, max_length=128)
|
|
|
|
|
|
class ContributionOut(APIModel):
|
|
sn: str
|
|
yield_date: date
|
|
eligible: bool
|
|
online_seconds: int
|
|
eligible_seconds: int
|
|
online_rate: MoneyText
|
|
tasks_dispatched: int
|
|
tasks_completed: int
|
|
task_response_rate: MoneyText
|
|
online_weight: MoneyText
|
|
task_weight: MoneyText
|
|
performance: MoneyText
|
|
compute_output: MoneyText
|
|
points_delta: MoneyText
|
|
cycle_days: int
|
|
|
|
|
|
class YieldOut(APIModel):
|
|
id: int
|
|
node_id: int
|
|
user_id: int
|
|
yield_date: date
|
|
compute_output: MoneyText
|
|
points_delta: MoneyText
|
|
online_seconds: int
|
|
eligible_seconds: int
|
|
online_rate: MoneyText
|
|
tasks_dispatched: int
|
|
tasks_completed: int
|
|
task_response_rate: MoneyText
|
|
online_weight: MoneyText
|
|
task_weight: MoneyText
|
|
performance: MoneyText
|
|
cycle_days: int
|
|
status: YieldStatus
|
|
is_partial: bool
|
|
created_at: datetime
|
|
|
|
|
|
class SettleOut(APIModel):
|
|
yield_date: date
|
|
created: int
|
|
skipped: int
|
|
total_points: MoneyText
|
|
is_partial: bool
|
|
|
|
|
|
class WithdrawalCreate(APIModel):
|
|
wallet_address: WALLET
|
|
amount: Decimal = Field(gt=0, max_digits=24, decimal_places=8)
|
|
asset_symbol: str = Field(default="POINT", min_length=1, max_length=32)
|
|
|
|
|
|
class WithdrawalConfirm(APIModel):
|
|
tx_hash: str = Field(min_length=6, max_length=128, pattern=r"^[A-Za-z0-9]+$")
|
|
|
|
|
|
class WithdrawalReject(APIModel):
|
|
note: str | None = Field(default=None, max_length=500)
|
|
|
|
|
|
class WithdrawalOut(APIModel):
|
|
id: int
|
|
user_id: int
|
|
amount: MoneyText
|
|
asset_symbol: str
|
|
tx_hash: str | None
|
|
status: WithdrawalStatus
|
|
note: str | None
|
|
available_after: MoneyText | None = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class BalanceOut(APIModel):
|
|
wallet_address: str
|
|
available_points: MoneyText
|