# AirToSocks

将 vmess / vless / trojan / ss 代理订阅链接批量转换为可用的 SOCKS5 代理，并提供 Web 管理界面和随机获取 API。

## 原理

```
┌─────────────────────────────────────────────────────────┐
│                    AirToSocks 系统                        │
│                                                          │
│  订阅地址 ──► 解析订阅内容 ──► 导入节点列表                 │
│                                    │                      │
│                              定时健康检查                  │
│                           (每10分钟并发检测)               │
│                                    │                      │
│                         ┌──────────┴──────────┐          │
│                         ▼                      ▼          │
│                   xray-core A             xray-core B    │
│                 (本地 SOCKS5 端口)      (本地 SOCKS5 端口)  │
│                  :10001 ~ :11000        :10001 ~ :11000   │
│                         │                      │          │
│                         └──────────┬──────────┘          │
│                                    ▼                      │
│                          /api/random                     │
│                       随机返回可用 SOCKS5                  │
└─────────────────────────────────────────────────────────┘
```

**核心流程：**

1. **订阅解析**：通过订阅地址获取代理链接（base64 编码或明文），解析为节点对象
2. **协议转换**：为每个节点启动独立的 xray-core 进程，将 vmess/vless/trojan/ss 协议转换为本地 SOCKS5 代理
3. **健康检查**：并发通过 SOCKS5 代理访问 `ifconfig.me/ip`，验证代理可用性并获取出口 IP
4. **随机返回**：通过 API 随机返回一个经过验证的可用 SOCKS5 代理地址

**每个节点对应一个独立的 xray-core 进程，监听在不同端口（10001-11000），互不干扰。**

## 功能特性

| 功能 | 说明 |
|------|------|
| 订阅管理 | 添加订阅地址，自动同步节点，支持定时自动更新 |
| 协议支持 | vmess / vless / trojan / ss |
| 健康检查 | 并发 20 线程检测，32 节点约 10 秒完成 |
| 自定义节点池 | 关键字搜索节点，组合创建专属节点池 |
| 随机 API | 全局随机 / 池内随机，返回前验证端口存活 |
| Web 管理 | 一站式管理页面，可视化操作 |

## 部署

### 方式一：Docker Compose（推荐）

```bash
# 克隆项目
git clone <repo-url> airtosocks
cd airtosocks

# 启动
docker-compose up -d

# 查看日志
docker-compose logs -f

# 停止
docker-compose down
```

服务启动后访问 `http://<your-ip>:8080`

### 方式二：直接运行

```bash
# 环境要求：Python 3.10+
cd airtosocks

# 创建虚拟环境
python3 -m venv venv
source venv/bin/activate

# 安装依赖
pip install -r requirements.txt

# 启动
python main.py

# 或使用启动脚本
chmod +x start.sh
./start.sh
```

### 方式三：后台运行

```bash
source venv/bin/activate
nohup python main.py &> data/server.log &
```

### 配置文件

创建 `config.yaml` 可自定义参数：

```yaml
port: 8080           # Web 服务端口
check_interval: 600  # 健康检查间隔（秒），默认 600（10分钟）
```

## 使用方法

### 1. 导入订阅

打开 Web 页面，在「订阅管理」板块：

1. 输入订阅名称（可选）
2. 粘贴订阅地址
3. 选择自动更新频率（不更新 / 每1小时 / 每2小时 / 每6小时 / 每12小时 / 每24小时）
4. 点击「添加订阅」

支持的订阅格式：
- base64 编码的多行链接
- 明文多行链接（每行一个）
- 自动识别 vmess / vless / trojan / ss 协议

### 2. 手动导入链接

在「导入代理链接」板块，直接粘贴代理链接（每行一个），点击「添加链接」。

### 3. 健康检查

- **自动检查**：每 10 分钟自动检测所有节点
- **手动检查**：点击「检查全部」按钮立即检测

检查通过的节点标记为可用（绿色），未通过的标记为不可用（红色）。

### 4. 创建节点池

在「自定义节点池」板块：

1. 输入关键字（如 `香港`），点击「搜索」
2. 勾选需要的节点
3. 输入新的关键字（如 `日本`），点击「搜索」，之前的选择保留
4. 继续搜索并勾选更多节点
5. 输入池名称，点击「创建节点池」

### 5. 获取 SOCKS5 代理

**全局随机：**
```bash
curl http://<your-ip>:8080/api/random
```

**节点池随机：**
```bash
curl http://<your-ip>:8080/api/pools/<pool_id>/random
```

返回示例：
```json
{
  "protocol": "socks5",
  "host": "64.81.114.33",
  "port": 10234,
  "url": "socks5://64.81.114.33:10234",
  "available": true,
  "last_check": "2026-03-30T22:00:00",
  "source": {
    "name": "香港 01 | 高级专线",
    "protocol": "vless",
    "address": "hk1.example.com",
    "port": 443
  }
}
```

## API 接口

| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/api/random` | 全局随机获取 SOCKS5 |
| `GET` | `/api/random/info` | 随机获取（纯文本格式） |
| `GET` | `/api/links` | 获取所有节点列表 |
| `POST` | `/api/links` | 批量添加链接 `{"links": ["vmess://..."]}` |
| `DELETE` | `/api/links/<node_id>` | 删除节点 |
| `POST` | `/api/check` | 检查所有节点 |
| `POST` | `/api/check/<node_id>` | 检查单个节点 |
| `GET` | `/api/subscriptions` | 获取订阅列表 |
| `POST` | `/api/subscriptions` | 添加订阅 `{"name":"xx","url":"...","sync_interval":120}` |
| `POST` | `/api/subscriptions/<id>/sync` | 手动同步订阅 |
| `DELETE` | `/api/subscriptions/<id>` | 删除订阅及关联节点 |
| `GET` | `/api/nodes/search?q=<keyword>` | 按关键字搜索节点 |
| `GET` | `/api/pools` | 获取所有节点池 |
| `POST` | `/api/pools` | 创建节点池 `{"name":"xx","node_ids":["..."]}` |
| `PUT` | `/api/pools/<id>` | 更新节点池 |
| `DELETE` | `/api/pools/<id>` | 删除节点池 |
| `GET` | `/api/pools/<id>/random` | 从指定池随机获取 SOCKS5 |

## 目录结构

```
airtosocks/
├── main.py              # 主程序
├── requirements.txt     # Python 依赖
├── start.sh             # 启动脚本
├── config.yaml.example  # 配置文件示例
├── Dockerfile           # Docker 镜像定义
├── docker-compose.yml   # Docker Compose 编排
├── config/              # 配置数据
│   ├── proxies.json     # 节点数据
│   ├── subscriptions.json # 订阅数据
│   └── pools.json       # 节点池数据
├── data/                # 运行数据
│   └── xray_*.json      # xray 配置文件
└── bin/                 # xray-core 二进制（自动下载）
```

## 常见问题

**Q: 代理全部显示不可用？**
- 检查服务器网络是否能访问目标代理服务器
- 部分代理可能需要特定的 TLS/SNI 配置
- 查看 `data/server.log` 日志排查具体错误

**Q: Docker 部署后无法访问？**
- 确认端口映射正确：`-p 8080:8080`
- 检查防火墙是否放行端口

**Q: 如何修改检查间隔？**
- 创建 `config.yaml`，设置 `check_interval: 600`（秒）
- 重启服务生效

**Q: SOCKS5 代理绑定在哪个地址？**
- 默认绑定 `0.0.0.0`，可通过服务器公网 IP 直接访问
- 随机 API 返回的 host 是当前请求的主机地址

## 技术栈

- **Python 3** + Flask（Web 服务）
- **xray-core**（协议转换引擎）
- **requests[socks]**（健康检查）
- **Docker**（容器化部署）
