清理项目冗余文件与死代码
删除内容: - config.py:旧架构配置残留,已被 core/config.py 替代 - README_SOCKS.md:内容严重过时(引用已删除的 api_server.py 和测试脚本),功能说明已合并至 README - frontend/src/api/types.js:纯 JSDoc typedef,未被任何模块引用,属于死文档 - frontend/src/assets/vue.svg:默认模板资源,项目中无任何页面引用 - frontend/src/utils/clipboard.js:移除 copyTextFallback 函数(使用已废弃的 document.execCommand)
This commit is contained in:
@@ -1,89 +0,0 @@
|
|||||||
# SOCKS 代理支持说明
|
|
||||||
|
|
||||||
## 更新内容
|
|
||||||
|
|
||||||
已成功为代理池系统添加 SOCKS4/SOCKS5 代理验证支持!
|
|
||||||
|
|
||||||
## 技术实现
|
|
||||||
|
|
||||||
### 1. 新增依赖
|
|
||||||
```
|
|
||||||
aiohttp-socks==0.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 验证器升级 (`core/validator.py`)
|
|
||||||
- 新增 `ProxyValidator` 类,完整支持 HTTP/HTTPS/SOCKS4/SOCKS5
|
|
||||||
- SOCKS 代理使用 `aiohttp_socks.ProxyConnector` 进行验证
|
|
||||||
- 支持远程 DNS 解析 (rdns=True),避免 DNS 泄漏
|
|
||||||
|
|
||||||
### 3. 协议识别
|
|
||||||
以下插件已更新支持 SOCKS 协议:
|
|
||||||
|
|
||||||
| 插件 | 支持协议 |
|
|
||||||
|-----|---------|
|
|
||||||
| Fate0聚合源 | HTTP, HTTPS, SOCKS4, SOCKS5 |
|
|
||||||
| SpeedX代理源 | HTTP, SOCKS4, SOCKS5 |
|
|
||||||
| ProxyListDownload | HTTP, HTTPS, SOCKS4, SOCKS5 |
|
|
||||||
| 快代理 | HTTP, HTTPS |
|
|
||||||
| IP3366 | HTTP, HTTPS |
|
|
||||||
| 89免费代理 | HTTP |
|
|
||||||
| 云代理 | HTTP, HTTPS |
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
### 启动服务
|
|
||||||
```bash
|
|
||||||
# 安装依赖
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
# 启动后端
|
|
||||||
python api_server.py
|
|
||||||
|
|
||||||
# 启动前端
|
|
||||||
cd frontend && npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 抓取 SOCKS 代理
|
|
||||||
1. 打开 WebUI (http://localhost:9948)
|
|
||||||
2. 进入"插件管理"页面
|
|
||||||
3. 点击 SpeedX 或 ProxyListDownload 插件的"立即爬取"
|
|
||||||
4. 系统自动识别 SOCKS 代理并进行验证
|
|
||||||
|
|
||||||
### 查看 SOCKS 代理
|
|
||||||
1. 进入"代理列表"页面
|
|
||||||
2. 使用协议筛选器选择 SOCKS4 或 SOCKS5
|
|
||||||
3. 查看验证结果和延迟
|
|
||||||
|
|
||||||
## 验证流程
|
|
||||||
|
|
||||||
```
|
|
||||||
+-------------+ +------------------+ +-----------------+
|
|
||||||
| 插件爬取 | --> | 识别协议类型 | --> | SOCKS验证器 |
|
|
||||||
+-------------+ +------------------+ +-----------------+
|
|
||||||
|
|
|
||||||
v
|
|
||||||
+-------------+ +------------------+ +-----------------+
|
|
||||||
| 存储结果 | <-- | 评分更新 | <-- | 延迟测试 |
|
|
||||||
+-------------+ +------------------+ +-----------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
## SOCKS 验证特点
|
|
||||||
|
|
||||||
1. **连接器类型**: 使用 `ProxyConnector` 替代 `TCPConnector`
|
|
||||||
2. **DNS 解析**: 远程解析避免泄漏真实 IP
|
|
||||||
3. **协议区分**: 明确区分 SOCKS4 和 SOCKS5
|
|
||||||
4. **统一接口**: 与 HTTP/HTTPS 代理使用相同的验证接口
|
|
||||||
|
|
||||||
## 测试
|
|
||||||
|
|
||||||
运行测试脚本验证 SOCKS 支持:
|
|
||||||
```bash
|
|
||||||
python test_socks_validator.py
|
|
||||||
python test_plugins_socks.py
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. SOCKS 代理验证比 HTTP 代理稍慢,因为有额外的握手过程
|
|
||||||
2. 部分 SOCKS 代理可能只支持 TCP 而不支持 UDP
|
|
||||||
3. SOCKS5 支持认证,当前版本使用无认证模式
|
|
||||||
70
config.py
70
config.py
@@ -1,70 +0,0 @@
|
|||||||
"""
|
|
||||||
代理池系统配置管理
|
|
||||||
统一管理所有配置项,支持环境变量覆盖
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
# 数据库配置
|
|
||||||
DB_PATH: str = os.getenv("DB_PATH", "db/proxies.db")
|
|
||||||
|
|
||||||
# API服务配置
|
|
||||||
HOST: str = os.getenv("HOST", "0.0.0.0")
|
|
||||||
PORT: int = int(os.getenv("PORT", "9949"))
|
|
||||||
|
|
||||||
# 验证器配置
|
|
||||||
VALIDATOR_TIMEOUT: int = int(os.getenv("VALIDATOR_TIMEOUT", "5"))
|
|
||||||
VALIDATOR_MAX_CONCURRENCY: int = int(os.getenv("VALIDATOR_MAX_CONCURRENCY", "200"))
|
|
||||||
VALIDATOR_CONNECT_TIMEOUT: int = int(os.getenv("VALIDATOR_CONNECT_TIMEOUT", "3"))
|
|
||||||
|
|
||||||
# 爬虫配置
|
|
||||||
CRAWLER_NUM_VALIDATORS: int = int(os.getenv("CRAWLER_NUM_VALIDATORS", "50"))
|
|
||||||
CRAWLER_MAX_QUEUE_SIZE: int = int(os.getenv("CRAWLER_MAX_QUEUE_SIZE", "500"))
|
|
||||||
|
|
||||||
# 定时任务配置
|
|
||||||
SCHEDULER_INTERVAL_MINUTES: int = int(os.getenv("SCHEDULER_INTERVAL_MINUTES", "60"))
|
|
||||||
SCHEDULER_ENABLED: bool = os.getenv("SCHEDULER_ENABLED", "true").lower() == "true"
|
|
||||||
|
|
||||||
# 日志配置
|
|
||||||
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
|
|
||||||
LOG_DIR: str = os.getenv("LOG_DIR", "logs")
|
|
||||||
|
|
||||||
# 导出配置
|
|
||||||
EXPORT_MAX_RECORDS: int = int(os.getenv("EXPORT_MAX_RECORDS", "10000"))
|
|
||||||
|
|
||||||
# 代理评分配置
|
|
||||||
SCORE_VALID: int = int(os.getenv("SCORE_VALID", "10"))
|
|
||||||
SCORE_INVALID: int = int(os.getenv("SCORE_INVALID", "-5"))
|
|
||||||
SCORE_MIN: int = int(os.getenv("SCORE_MIN", "0"))
|
|
||||||
SCORE_MAX: int = int(os.getenv("SCORE_MAX", "100"))
|
|
||||||
|
|
||||||
# WebSocket配置
|
|
||||||
WS_PING_INTERVAL: int = int(os.getenv("WS_PING_INTERVAL", "20"))
|
|
||||||
WS_PING_TIMEOUT: int = int(os.getenv("WS_PING_TIMEOUT", "20"))
|
|
||||||
|
|
||||||
# 插件配置
|
|
||||||
PLUGINS_DIR: str = os.getenv("PLUGINS_DIR", "plugins")
|
|
||||||
|
|
||||||
# CORS配置
|
|
||||||
CORS_ORIGINS: str = os.getenv("CORS_ORIGINS", "http://localhost:8080,http://localhost:5173")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, key: str, default=None):
|
|
||||||
"""获取配置项"""
|
|
||||||
return getattr(cls, key, default)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def set(cls, key: str, value):
|
|
||||||
"""设置配置项(仅限运行时)"""
|
|
||||||
setattr(cls, key, value)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update(cls, updates: dict):
|
|
||||||
"""批量更新配置"""
|
|
||||||
for key, value in updates.items():
|
|
||||||
if hasattr(cls, key):
|
|
||||||
setattr(cls, key, value)
|
|
||||||
|
|
||||||
# 全局配置实例
|
|
||||||
config = Config()
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* @typedef {object} ApiResponse<T>
|
|
||||||
* @property {number} code
|
|
||||||
* @property {string} message
|
|
||||||
* @property {T} data
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} StatsData
|
|
||||||
* @property {number} total
|
|
||||||
* @property {number} available
|
|
||||||
* @property {number} today_new
|
|
||||||
* @property {number} avg_score
|
|
||||||
* @property {number} http_count
|
|
||||||
* @property {number} https_count
|
|
||||||
* @property {number} socks4_count
|
|
||||||
* @property {number} socks5_count
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} Proxy
|
|
||||||
* @property {string} ip
|
|
||||||
* @property {number} port
|
|
||||||
* @property {string} protocol
|
|
||||||
* @property {number} score
|
|
||||||
* @property {string} last_check
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} ProxyListData
|
|
||||||
* @property {Proxy[]} list
|
|
||||||
* @property {number} total
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} Plugin
|
|
||||||
* @property {string|number} id
|
|
||||||
* @property {string} name
|
|
||||||
* @property {string} description
|
|
||||||
* @property {boolean} enabled
|
|
||||||
* @property {number} success_count
|
|
||||||
* @property {number} failure_count
|
|
||||||
* @property {string|null} last_run
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} SettingsData
|
|
||||||
* @property {string} db_path
|
|
||||||
* @property {number} crawl_timeout
|
|
||||||
* @property {number} validation_timeout
|
|
||||||
* @property {number} max_retries
|
|
||||||
* @property {number} default_concurrency
|
|
||||||
* @property {number} min_proxy_score
|
|
||||||
* @property {number} proxy_expiry_days
|
|
||||||
*/
|
|
||||||
|
|
||||||
export {}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 496 B |
@@ -39,25 +39,3 @@ export async function copyProxy(proxy) {
|
|||||||
return copyToClipboard(text)
|
return copyToClipboard(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 复制文本(备选方案:使用 DOM)
|
|
||||||
* @param {string} text
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function copyTextFallback(text) {
|
|
||||||
const textarea = document.createElement('textarea')
|
|
||||||
textarea.value = text
|
|
||||||
textarea.style.cssText = 'position:fixed;left:-9999px;opacity:0;'
|
|
||||||
document.body.appendChild(textarea)
|
|
||||||
|
|
||||||
try {
|
|
||||||
textarea.select()
|
|
||||||
textarea.setSelectionRange(0, text.length)
|
|
||||||
const success = document.execCommand('copy')
|
|
||||||
document.body.removeChild(textarea)
|
|
||||||
return success
|
|
||||||
} catch {
|
|
||||||
document.body.removeChild(textarea)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user