588 lines
23 KiB
Python
588 lines
23 KiB
Python
"""主窗口 - PyQt6 GUI界面"""
|
|
import sys
|
|
from PyQt6.QtWidgets import (
|
|
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
QPushButton, QLabel, QTableWidget, QTableWidgetItem,
|
|
QTextEdit, QGroupBox, QFormLayout, QLineEdit,
|
|
QSpinBox, QComboBox, QCheckBox, QMessageBox,
|
|
QHeaderView, QProgressBar, QTabWidget, QDialog,
|
|
QDialogButtonBox, QFileDialog
|
|
)
|
|
from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QThread
|
|
from PyQt6.QtGui import QFont, QColor
|
|
from loguru import logger
|
|
import yaml
|
|
import os
|
|
|
|
from core import ProxyManager
|
|
from core.models import ProxyInfo, ProxyStatus
|
|
|
|
|
|
class WorkerThread(QThread):
|
|
"""工作线程 - 处理耗时操作"""
|
|
progress_signal = pyqtSignal(str)
|
|
finished_signal = pyqtSignal(bool, str)
|
|
|
|
def __init__(self, task_func, *args, **kwargs):
|
|
super().__init__()
|
|
self.task_func = task_func
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def run(self):
|
|
try:
|
|
result = self.task_func(*self.args, **self.kwargs)
|
|
self.finished_signal.emit(True, str(result))
|
|
except Exception as e:
|
|
self.finished_signal.emit(False, str(e))
|
|
|
|
|
|
class ConfigDialog(QDialog):
|
|
"""配置对话框"""
|
|
|
|
def __init__(self, config: dict, parent=None):
|
|
super().__init__(parent)
|
|
self.config = config.copy()
|
|
self.setWindowTitle("配置设置")
|
|
self.setFixedSize(600, 500)
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
layout = QVBoxLayout(self)
|
|
|
|
# 代理源设置
|
|
source_group = QGroupBox("代理源设置")
|
|
source_layout = QFormLayout()
|
|
|
|
self.url_edit = QLineEdit(self.config.get('proxy_sources', {}).get('auto_fetch', {}).get('url', ''))
|
|
source_layout.addRow("自动获取URL:", self.url_edit)
|
|
|
|
self.pages_spin = QSpinBox()
|
|
self.pages_spin.setRange(1, 20)
|
|
self.pages_spin.setValue(self.config.get('proxy_sources', {}).get('auto_fetch', {}).get('pages', 3))
|
|
source_layout.addRow("抓取页数:", self.pages_spin)
|
|
|
|
self.refresh_interval_spin = QSpinBox()
|
|
self.refresh_interval_spin.setRange(1, 60)
|
|
self.refresh_interval_spin.setValue(self.config.get('proxy_sources', {}).get('auto_fetch', {}).get('refresh_interval', 10))
|
|
source_layout.addRow("刷新间隔(分钟):", self.refresh_interval_spin)
|
|
|
|
self.local_file_checkbox = QCheckBox("启用本地文件")
|
|
self.local_file_checkbox.setChecked(self.config.get('proxy_sources', {}).get('local_file', {}).get('enabled', True))
|
|
source_layout.addRow("", self.local_file_checkbox)
|
|
|
|
source_group.setLayout(source_layout)
|
|
layout.addWidget(source_group)
|
|
|
|
# 轮转策略
|
|
rotation_group = QGroupBox("轮转策略")
|
|
rotation_layout = QFormLayout()
|
|
|
|
self.mode_combo = QComboBox()
|
|
self.mode_combo.addItems(["manual", "auto"])
|
|
self.mode_combo.setCurrentText(self.config.get('rotation', {}).get('mode', 'manual'))
|
|
rotation_layout.addRow("切换模式:", self.mode_combo)
|
|
|
|
self.switch_interval_spin = QSpinBox()
|
|
self.switch_interval_spin.setRange(30, 3600)
|
|
self.switch_interval_spin.setValue(self.config.get('rotation', {}).get('auto_switch_interval', 300))
|
|
rotation_layout.addRow("自动切换间隔(秒):", self.switch_interval_spin)
|
|
|
|
self.latency_threshold_spin = QSpinBox()
|
|
self.latency_threshold_spin.setRange(100, 2000)
|
|
self.latency_threshold_spin.setValue(self.config.get('rotation', {}).get('latency_threshold', 500))
|
|
rotation_layout.addRow("延迟阈值(ms):", self.latency_threshold_spin)
|
|
|
|
rotation_group.setLayout(rotation_layout)
|
|
layout.addWidget(rotation_group)
|
|
|
|
# 输出设置
|
|
output_group = QGroupBox("输出设置")
|
|
output_layout = QFormLayout()
|
|
|
|
self.host_edit = QLineEdit(self.config.get('output', {}).get('host', '127.0.0.1'))
|
|
output_layout.addRow("监听地址:", self.host_edit)
|
|
|
|
self.port_spin = QSpinBox()
|
|
self.port_spin.setRange(1024, 65535)
|
|
self.port_spin.setValue(self.config.get('output', {}).get('port', 8745))
|
|
output_layout.addRow("监听端口:", self.port_spin)
|
|
|
|
output_group.setLayout(output_layout)
|
|
layout.addWidget(output_group)
|
|
|
|
# 按钮
|
|
button_box = QDialogButtonBox(
|
|
QDialogButtonBox.StandardButton.Ok |
|
|
QDialogButtonBox.StandardButton.Cancel
|
|
)
|
|
button_box.accepted.connect(self.accept)
|
|
button_box.rejected.connect(self.reject)
|
|
layout.addWidget(button_box)
|
|
|
|
def get_config(self) -> dict:
|
|
"""获取配置"""
|
|
return {
|
|
'proxy_sources': {
|
|
'auto_fetch': {
|
|
'enabled': True,
|
|
'url': self.url_edit.text(),
|
|
'pages': self.pages_spin.value(),
|
|
'refresh_interval': self.refresh_interval_spin.value(),
|
|
'output_file': 'proxy.json'
|
|
},
|
|
'local_file': {
|
|
'enabled': self.local_file_checkbox.isChecked(),
|
|
'path': 'local.json'
|
|
}
|
|
},
|
|
'rotation': {
|
|
'mode': self.mode_combo.currentText(),
|
|
'auto_switch_interval': self.switch_interval_spin.value(),
|
|
'latency_threshold': self.latency_threshold_spin.value()
|
|
},
|
|
'output': {
|
|
'host': self.host_edit.text(),
|
|
'port': self.port_spin.value()
|
|
}
|
|
}
|
|
|
|
|
|
class MainWindow(QMainWindow):
|
|
"""主窗口"""
|
|
|
|
def __init__(self, config_path='config.yaml'):
|
|
super().__init__()
|
|
self.config_path = config_path
|
|
self.config = self.load_config()
|
|
self.proxy_manager = None
|
|
self.worker_thread = None
|
|
|
|
self.setWindowTitle("WhereAmI - 多协议轮转代理工具")
|
|
self.resize(1200, 800)
|
|
|
|
self.init_ui()
|
|
self.init_proxy_manager()
|
|
|
|
def load_config(self) -> dict:
|
|
"""加载配置文件"""
|
|
if os.path.exists(self.config_path):
|
|
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
return yaml.safe_load(f)
|
|
return {}
|
|
|
|
def save_config(self):
|
|
"""保存配置文件"""
|
|
with open(self.config_path, 'w', encoding='utf-8') as f:
|
|
yaml.dump(self.config, f, allow_unicode=True, default_flow_style=False)
|
|
|
|
def init_ui(self):
|
|
"""初始化UI"""
|
|
central_widget = QWidget()
|
|
self.setCentralWidget(central_widget)
|
|
main_layout = QVBoxLayout(central_widget)
|
|
|
|
# 顶部状态栏
|
|
status_layout = QHBoxLayout()
|
|
|
|
self.status_label = QLabel("状态: 未启动")
|
|
self.status_label.setStyleSheet("font-weight: bold; color: red;")
|
|
status_layout.addWidget(self.status_label)
|
|
|
|
self.active_proxy_label = QLabel("当前代理: 无")
|
|
status_layout.addWidget(self.active_proxy_label)
|
|
|
|
self.stats_label = QLabel("统计: 0/0")
|
|
status_layout.addWidget(self.stats_label)
|
|
|
|
status_layout.addStretch()
|
|
main_layout.addLayout(status_layout)
|
|
|
|
# 控制按钮
|
|
control_layout = QHBoxLayout()
|
|
|
|
self.start_button = QPushButton("▶ 开始服务")
|
|
self.start_button.clicked.connect(self.on_start_service)
|
|
control_layout.addWidget(self.start_button)
|
|
|
|
self.stop_button = QPushButton("⏹ 停止服务")
|
|
self.stop_button.clicked.connect(self.on_stop_service)
|
|
self.stop_button.setEnabled(False)
|
|
control_layout.addWidget(self.stop_button)
|
|
|
|
self.switch_button = QPushButton("🔄 切换下一个")
|
|
self.switch_button.clicked.connect(self.on_switch_proxy)
|
|
self.switch_button.setEnabled(False)
|
|
control_layout.addWidget(self.switch_button)
|
|
|
|
self.fetch_button = QPushButton("🌐 获取免费代理")
|
|
self.fetch_button.clicked.connect(self.on_fetch_proxies)
|
|
control_layout.addWidget(self.fetch_button)
|
|
|
|
self.use_local_button = QPushButton("📁 使用本地代理")
|
|
self.use_local_button.clicked.connect(self.on_use_local_proxies)
|
|
control_layout.addWidget(self.use_local_button)
|
|
|
|
self.fetch_other_button = QPushButton("🔧 其他代理(预留)")
|
|
self.fetch_other_button.clicked.connect(self.on_fetch_other_proxies)
|
|
self.fetch_other_button.setEnabled(False) # 暂时禁用,预留功能
|
|
control_layout.addWidget(self.fetch_other_button)
|
|
|
|
self.config_button = QPushButton("⚙️ 配置")
|
|
self.config_button.clicked.connect(self.on_open_config)
|
|
control_layout.addWidget(self.config_button)
|
|
|
|
main_layout.addLayout(control_layout)
|
|
|
|
# 进度条
|
|
self.progress_bar = QProgressBar()
|
|
self.progress_bar.setVisible(False)
|
|
main_layout.addWidget(self.progress_bar)
|
|
|
|
# 标签页
|
|
tab_widget = QTabWidget()
|
|
|
|
# 代理列表标签页
|
|
proxy_tab = QWidget()
|
|
proxy_layout = QVBoxLayout(proxy_tab)
|
|
|
|
# 过滤选项
|
|
filter_layout = QHBoxLayout()
|
|
self.show_unavailable_checkbox = QCheckBox("显示不可用代理")
|
|
self.show_unavailable_checkbox.setChecked(False)
|
|
self.show_unavailable_checkbox.stateChanged.connect(self.on_filter_changed)
|
|
filter_layout.addWidget(self.show_unavailable_checkbox)
|
|
filter_layout.addStretch()
|
|
proxy_layout.addLayout(filter_layout)
|
|
|
|
self.proxy_table = QTableWidget()
|
|
self.proxy_table.setColumnCount(10)
|
|
self.proxy_table.setHorizontalHeaderLabels([
|
|
"IP地址", "端口", "协议", "国家", "状态",
|
|
"延迟(ms)", "匿名级别", "速度", "运行时间", "最后更新"
|
|
])
|
|
self.proxy_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
|
|
self.proxy_table.setAlternatingRowColors(True)
|
|
self.proxy_table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
|
self.proxy_table.setSelectionMode(QTableWidget.SelectionMode.SingleSelection)
|
|
self.proxy_table.cellClicked.connect(self.on_proxy_selected)
|
|
proxy_layout.addWidget(self.proxy_table)
|
|
|
|
tab_widget.addTab(proxy_tab, "代理列表")
|
|
|
|
# 连接日志标签页
|
|
connection_log_tab = QWidget()
|
|
connection_log_layout = QVBoxLayout(connection_log_tab)
|
|
|
|
self.connection_log_text = QTextEdit()
|
|
self.connection_log_text.setReadOnly(True)
|
|
self.connection_log_text.setFont(QFont("Consolas", 9))
|
|
connection_log_layout.addWidget(self.connection_log_text)
|
|
|
|
clear_connection_log_button = QPushButton("清空连接日志")
|
|
clear_connection_log_button.clicked.connect(self.connection_log_text.clear)
|
|
connection_log_layout.addWidget(clear_connection_log_button)
|
|
|
|
tab_widget.addTab(connection_log_tab, "连接日志")
|
|
|
|
# 日志标签页
|
|
log_tab = QWidget()
|
|
log_layout = QVBoxLayout(log_tab)
|
|
|
|
self.log_text = QTextEdit()
|
|
self.log_text.setReadOnly(True)
|
|
self.log_text.setFont(QFont("Consolas", 9))
|
|
log_layout.addWidget(self.log_text)
|
|
|
|
clear_log_button = QPushButton("清空日志")
|
|
clear_log_button.clicked.connect(self.log_text.clear)
|
|
log_layout.addWidget(clear_log_button)
|
|
|
|
tab_widget.addTab(log_tab, "日志")
|
|
|
|
main_layout.addWidget(tab_widget)
|
|
|
|
def init_proxy_manager(self):
|
|
"""初始化代理管理器"""
|
|
# 定义连接日志回调
|
|
def log_connection(message: str):
|
|
from datetime import datetime
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
self.connection_log_text.append(f"[{timestamp}] {message}")
|
|
|
|
self.proxy_manager = ProxyManager(self.config, connection_log_callback=log_connection)
|
|
self.selected_proxy = None # 用户选择的代理
|
|
self.log("代理管理器已初始化")
|
|
|
|
def on_start_service(self):
|
|
"""启动服务 - 仅启动端口监听,需要先选择代理"""
|
|
# 检查是否选择了代理
|
|
if not self.selected_proxy:
|
|
QMessageBox.warning(self, "警告", "请先选择一个代理节点!\n\n点击代理列表中的某一行来选择代理。")
|
|
return
|
|
|
|
self.start_button.setEnabled(False)
|
|
self.progress_bar.setVisible(True)
|
|
self.progress_bar.setRange(0, 0)
|
|
self.log(f"正在启动服务,使用代理: {self.selected_proxy.get_address()}")
|
|
|
|
def start_task():
|
|
# 只使用选中的代理
|
|
self.proxy_manager.set_proxies([self.selected_proxy])
|
|
return self.proxy_manager.start_service()
|
|
|
|
self.worker_thread = WorkerThread(start_task)
|
|
self.worker_thread.finished_signal.connect(self.on_service_started)
|
|
self.worker_thread.start()
|
|
|
|
def on_service_started(self, success: bool, message: str):
|
|
"""服务启动完成"""
|
|
self.progress_bar.setVisible(False)
|
|
self.start_button.setEnabled(True)
|
|
|
|
if success:
|
|
self.status_label.setText("状态: 运行中")
|
|
self.status_label.setStyleSheet("font-weight: bold; color: green;")
|
|
self.stop_button.setEnabled(True)
|
|
self.switch_button.setEnabled(True)
|
|
self.log("服务启动成功")
|
|
self.update_proxy_table()
|
|
self.update_stats()
|
|
|
|
# 定时更新状态
|
|
self.update_timer = QTimer()
|
|
self.update_timer.timeout.connect(self.update_status)
|
|
self.update_timer.start(5000)
|
|
else:
|
|
self.log(f"服务启动失败: {message}")
|
|
QMessageBox.warning(self, "错误", f"启动服务失败:\n{message}")
|
|
|
|
def on_stop_service(self):
|
|
"""停止服务"""
|
|
self.log("正在停止服务...")
|
|
self.proxy_manager.stop_service()
|
|
|
|
self.status_label.setText("状态: 已停止")
|
|
self.status_label.setStyleSheet("font-weight: bold; color: red;")
|
|
self.start_button.setEnabled(True)
|
|
self.stop_button.setEnabled(False)
|
|
self.switch_button.setEnabled(False)
|
|
|
|
if hasattr(self, 'update_timer'):
|
|
self.update_timer.stop()
|
|
|
|
self.log("服务已停止")
|
|
|
|
def on_switch_proxy(self):
|
|
"""切换代理"""
|
|
self.log("正在切换代理...")
|
|
|
|
def switch_task():
|
|
return self.proxy_manager.switch_to_next_proxy()
|
|
|
|
self.worker_thread = WorkerThread(switch_task)
|
|
self.worker_thread.finished_signal.connect(self.on_proxy_switched)
|
|
self.worker_thread.start()
|
|
|
|
def on_proxy_switched(self, success: bool, message: str):
|
|
"""代理切换完成"""
|
|
if success:
|
|
self.log("代理切换成功")
|
|
self.update_status()
|
|
self.update_proxy_table()
|
|
else:
|
|
self.log(f"代理切换失败: {message}")
|
|
QMessageBox.warning(self, "警告", f"切换代理失败:\n{message}")
|
|
|
|
def on_fetch_proxies(self):
|
|
"""获取代理 - 保留旧方法以兼容"""
|
|
self.log("正在从网页获取代理...")
|
|
self.progress_bar.setVisible(True)
|
|
self.progress_bar.setRange(0, 0)
|
|
|
|
def fetch_task():
|
|
count = self.proxy_manager.load_proxies()
|
|
self.proxy_manager.check_all_proxies()
|
|
return count
|
|
|
|
self.worker_thread = WorkerThread(fetch_task)
|
|
self.worker_thread.finished_signal.connect(self.on_fetch_completed)
|
|
self.worker_thread.start()
|
|
|
|
def on_use_local_proxies(self):
|
|
"""使用本地代理"""
|
|
self.log("正在加载本地代理...")
|
|
self.progress_bar.setVisible(True)
|
|
self.progress_bar.setRange(0, 0)
|
|
|
|
def load_local_task():
|
|
# 只加载本地文件
|
|
config_backup = self.proxy_manager.config.copy()
|
|
self.proxy_manager.config['proxy_sources']['auto_fetch']['enabled'] = False
|
|
self.proxy_manager.config['proxy_sources']['local_file']['enabled'] = True
|
|
|
|
count = self.proxy_manager.load_proxies()
|
|
self.proxy_manager.check_all_proxies()
|
|
|
|
# 恢复配置
|
|
self.proxy_manager.config = config_backup
|
|
return count
|
|
|
|
self.worker_thread = WorkerThread(load_local_task)
|
|
self.worker_thread.finished_signal.connect(self.on_fetch_completed)
|
|
self.worker_thread.start()
|
|
|
|
def on_fetch_other_proxies(self):
|
|
"""获取其他代理(预留功能 - 后续用于启动 scratch.py 测试)"""
|
|
self.log("⚠️ 此功能暂未实现,预留用于后续测试")
|
|
QMessageBox.information(self, "提示",
|
|
"此功能暂未实现。\n\n"
|
|
"计划用途:启动 scratch.py 进行代理测试\n"
|
|
"后续将根据需求完善此功能。")
|
|
|
|
def on_fetch_completed(self, success: bool, message: str):
|
|
"""获取代理完成"""
|
|
self.progress_bar.setVisible(False)
|
|
|
|
if success:
|
|
self.log(f"成功获取 {message} 个代理")
|
|
self.update_proxy_table()
|
|
self.update_stats()
|
|
else:
|
|
self.log(f"获取代理失败: {message}")
|
|
QMessageBox.warning(self, "错误", f"获取代理失败:\n{message}")
|
|
|
|
def on_open_config(self):
|
|
"""打开配置对话框"""
|
|
dialog = ConfigDialog(self.config, self)
|
|
if dialog.exec() == QDialog.DialogCode.Accepted:
|
|
self.config = dialog.get_config()
|
|
self.save_config()
|
|
self.log("配置已保存")
|
|
|
|
def on_proxy_selected(self, row: int, column: int):
|
|
"""用户选择代理"""
|
|
proxies = self.get_filtered_proxies()
|
|
if row < len(proxies):
|
|
self.selected_proxy = proxies[row]
|
|
self.active_proxy_label.setText(
|
|
f"选中代理: {self.selected_proxy.ip_address}:{self.selected_proxy.port} "
|
|
f"({self.selected_proxy.protocol.value}) - {self.selected_proxy.latency_ms:.0f}ms"
|
|
)
|
|
self.log(f"已选择代理: {self.selected_proxy.get_address()}")
|
|
|
|
def on_filter_changed(self, state):
|
|
"""过滤条件改变"""
|
|
self.update_proxy_table()
|
|
|
|
def get_filtered_proxies(self):
|
|
"""获取过滤后的代理列表"""
|
|
if not self.proxy_manager:
|
|
return []
|
|
|
|
proxies = self.proxy_manager.proxies
|
|
|
|
# 如果不显示不可用代理,则过滤掉
|
|
if not self.show_unavailable_checkbox.isChecked():
|
|
from core.models import ProxyStatus
|
|
proxies = [p for p in proxies if p.status != ProxyStatus.UNAVAILABLE]
|
|
|
|
return proxies
|
|
|
|
def update_status(self):
|
|
"""更新状态显示"""
|
|
active_proxy = self.proxy_manager.get_active_proxy()
|
|
if active_proxy:
|
|
self.active_proxy_label.setText(
|
|
f"当前代理: {active_proxy.ip_address}:{active_proxy.port} "
|
|
f"({active_proxy.protocol.value}) - {active_proxy.latency_ms:.0f}ms"
|
|
)
|
|
else:
|
|
self.active_proxy_label.setText("当前代理: 无")
|
|
|
|
self.update_stats()
|
|
|
|
def update_stats(self):
|
|
"""更新统计信息"""
|
|
stats = self.proxy_manager.get_statistics()
|
|
self.stats_label.setText(
|
|
f"统计: 总计{stats['total']} | "
|
|
f"可用{stats['available']} | "
|
|
f"优秀{stats['excellent']} | "
|
|
f"不可用{stats['unavailable']}"
|
|
)
|
|
|
|
def update_proxy_table(self):
|
|
"""更新代理列表表格"""
|
|
proxies = self.get_filtered_proxies()
|
|
|
|
self.proxy_table.setRowCount(len(proxies))
|
|
|
|
for row, proxy in enumerate(proxies):
|
|
# IP地址
|
|
self.proxy_table.setItem(row, 0, QTableWidgetItem(proxy.ip_address))
|
|
|
|
# 端口
|
|
self.proxy_table.setItem(row, 1, QTableWidgetItem(str(proxy.port)))
|
|
|
|
# 协议
|
|
self.proxy_table.setItem(row, 2, QTableWidgetItem(proxy.protocol.value))
|
|
|
|
# 国家
|
|
self.proxy_table.setItem(row, 3, QTableWidgetItem(proxy.country or "-"))
|
|
|
|
# 状态
|
|
status_item = QTableWidgetItem(self.get_status_text(proxy.status))
|
|
status_item.setForeground(self.get_status_color(proxy.status))
|
|
self.proxy_table.setItem(row, 4, status_item)
|
|
|
|
# 延迟
|
|
latency_text = f"{proxy.latency_ms:.0f}" if proxy.latency_ms < 9999 else "-"
|
|
self.proxy_table.setItem(row, 5, QTableWidgetItem(latency_text))
|
|
|
|
# 匿名级别
|
|
self.proxy_table.setItem(row, 6, QTableWidgetItem(proxy.anonymity or "-"))
|
|
|
|
# 速度
|
|
self.proxy_table.setItem(row, 7, QTableWidgetItem(proxy.speed or "-"))
|
|
|
|
# 运行时间
|
|
self.proxy_table.setItem(row, 8, QTableWidgetItem(proxy.uptime_percentage or "-"))
|
|
|
|
# 最后更新
|
|
self.proxy_table.setItem(row, 9, QTableWidgetItem(proxy.last_updated or "-"))
|
|
|
|
def get_status_text(self, status: ProxyStatus) -> str:
|
|
"""获取状态文本"""
|
|
status_map = {
|
|
ProxyStatus.UNKNOWN: "未知",
|
|
ProxyStatus.CHECKING: "检测中",
|
|
ProxyStatus.AVAILABLE: "可用",
|
|
ProxyStatus.EXCELLENT: "优秀",
|
|
ProxyStatus.UNAVAILABLE: "不可用"
|
|
}
|
|
return status_map.get(status, "未知")
|
|
|
|
def get_status_color(self, status: ProxyStatus) -> QColor:
|
|
"""获取状态颜色"""
|
|
color_map = {
|
|
ProxyStatus.UNKNOWN: QColor("gray"),
|
|
ProxyStatus.CHECKING: QColor("orange"),
|
|
ProxyStatus.AVAILABLE: QColor("green"),
|
|
ProxyStatus.EXCELLENT: QColor("darkgreen"),
|
|
ProxyStatus.UNAVAILABLE: QColor("red")
|
|
}
|
|
return color_map.get(status, QColor("gray"))
|
|
|
|
def log(self, message: str):
|
|
"""添加日志"""
|
|
from datetime import datetime
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
self.log_text.append(f"[{timestamp}] {message}")
|
|
|
|
def closeEvent(self, event):
|
|
"""关闭事件"""
|
|
if self.proxy_manager:
|
|
self.proxy_manager.stop_service()
|
|
event.accept()
|