126 lines
5.2 KiB
Python
126 lines
5.2 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
数据模型:Django ORM 表模型 + Pydantic 内存模型。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import time
|
||
import uuid
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
from django.db import models
|
||
from pydantic import BaseModel, Field
|
||
|
||
from common.protocol import TaskStatus, TaskType
|
||
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# Django ORM 模型
|
||
# ══════════════════════════════════════════════════════════════
|
||
|
||
class BossAccount(models.Model):
|
||
"""BOSS 账号登录状态表。"""
|
||
worker_id = models.CharField(max_length=64, verbose_name="Worker 标识")
|
||
browser_id = models.CharField(max_length=128, default="", verbose_name="比特浏览器窗口 ID")
|
||
browser_name = models.CharField(max_length=128, default="", verbose_name="比特浏览器窗口名称(环境名)")
|
||
boss_username = models.CharField(max_length=128, default="", verbose_name="BOSS 直聘用户名")
|
||
is_logged_in = models.BooleanField(default=False, verbose_name="是否已登录")
|
||
current_task_id = models.CharField(max_length=32, null=True, blank=True, verbose_name="当前检测任务 ID")
|
||
current_task_status = models.CharField(max_length=32, null=True, blank=True, verbose_name="当前检测任务状态")
|
||
checked_at = models.DateTimeField(null=True, blank=True, verbose_name="最近一次检测时间")
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
||
|
||
class Meta:
|
||
db_table = "boss_account"
|
||
unique_together = [("worker_id", "browser_id")]
|
||
verbose_name = "BOSS 账号"
|
||
verbose_name_plural = verbose_name
|
||
|
||
def __str__(self):
|
||
return f"{self.browser_name}@{self.worker_id}"
|
||
|
||
|
||
class TaskLog(models.Model):
|
||
"""任务执行记录表。"""
|
||
task_id = models.CharField(max_length=32, unique=True, verbose_name="任务 ID")
|
||
task_type = models.CharField(max_length=64, verbose_name="任务类型")
|
||
worker_id = models.CharField(max_length=64, default="", verbose_name="执行的 Worker")
|
||
status = models.CharField(max_length=32, default="", verbose_name="最终状态")
|
||
params = models.JSONField(null=True, blank=True, verbose_name="任务参数")
|
||
result = models.JSONField(null=True, blank=True, verbose_name="任务结果")
|
||
error = models.TextField(null=True, blank=True, verbose_name="错误信息")
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||
|
||
class Meta:
|
||
db_table = "task_log"
|
||
verbose_name = "任务日志"
|
||
verbose_name_plural = verbose_name
|
||
|
||
def __str__(self):
|
||
return f"{self.task_id} ({self.task_type})"
|
||
|
||
|
||
class AuthToken(models.Model):
|
||
"""登录 token 表:每个用户名仅保留当前有效 token。"""
|
||
username = models.CharField(max_length=64, unique=True, verbose_name="用户名")
|
||
token = models.CharField(max_length=64, verbose_name="当前有效 token")
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||
|
||
class Meta:
|
||
db_table = "auth_token"
|
||
verbose_name = "登录 Token"
|
||
verbose_name_plural = verbose_name
|
||
|
||
def __str__(self):
|
||
return self.username
|
||
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# Pydantic 内存模型(非数据库,用于 Worker 运行时状态与任务调度)
|
||
# ══════════════════════════════════════════════════════════════
|
||
|
||
# ─── Worker ───
|
||
|
||
class BrowserProfile(BaseModel):
|
||
"""比特浏览器窗口信息(Worker 上报)。"""
|
||
id: str
|
||
name: str = ""
|
||
remark: str = ""
|
||
|
||
|
||
class WorkerInfo(BaseModel):
|
||
"""一台 Worker 的运行时信息(内存中保存)。"""
|
||
worker_id: str
|
||
worker_name: str = ""
|
||
browsers: List[BrowserProfile] = []
|
||
online: bool = True
|
||
last_heartbeat: float = Field(default_factory=time.time)
|
||
connected_at: float = Field(default_factory=time.time)
|
||
current_task_id: Optional[str] = None
|
||
|
||
|
||
# ─── Task ───
|
||
|
||
class TaskCreate(BaseModel):
|
||
"""前端提交任务的请求体(也用于内部创建任务)。"""
|
||
task_type: TaskType
|
||
worker_id: Optional[str] = None
|
||
account_name: Optional[str] = None
|
||
params: Dict[str, Any] = {}
|
||
|
||
|
||
class TaskInfo(BaseModel):
|
||
"""任务完整信息(内存中保存)。"""
|
||
task_id: str = Field(default_factory=lambda: uuid.uuid4().hex[:12])
|
||
task_type: TaskType
|
||
status: TaskStatus = TaskStatus.PENDING
|
||
worker_id: Optional[str] = None
|
||
account_name: Optional[str] = None
|
||
params: Dict[str, Any] = {}
|
||
progress: Optional[str] = None
|
||
result: Any = None
|
||
error: Optional[str] = None
|
||
created_at: float = Field(default_factory=time.time)
|
||
updated_at: float = Field(default_factory=time.time)
|