mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-03 07:06:36 +08:00
迁移配置表
This commit is contained in:
@@ -23,12 +23,15 @@ sidebar: false
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 `/api/v1/d/option` 批量更新 OpenResty 等业务配置不生效的问题。根本原因是 option 模块在读写时做了 PascalCase 与 snake_case 的机械转换(如 `OpenRestyEventsUse` → `open_resty_events_use`),与 `w_system_configs` 中实际 key(`openresty_events_use`)不一致,更新写入了错误的幽灵配置行。现改为 API 直接使用与数据库一致的 snake_case key,并同步更新前端性能调优与运维设置页。
|
||||
- 修复 PostgreSQL 数据库执行迁移时报 `duplicate key value violates unique constraint "goose_db_version_pkey"` 导致迁移中断的问题。根本原因:`goose_db_version.id` 自增序列落后于表内 `MAX(id)`(常见于从 dump 恢复或历史迁移以显式 id 复制版本记录后),goose 记录新版本号时自增 id 与既有行冲突。修复方式:在 `goose.Up` 前对 PostgreSQL 执行 `setval` 重新对齐 `goose_db_version` 的 id 序列。
|
||||
- 修复 openflared(Tunnel Client)WebSocket 连接在 Cloudflare 代理环境下频繁收到 EOF 断连的问题。根本原因:服务端 `read_pump` 仅在收到 WebSocket 协议层 Pong 帧时刷新读超时,而客户端(`golang.org/x/net/websocket`)以 JSON 应用层 `{"type":"pong"}` 响应 ping,服务端 90s 读超时到期后主动关闭连接,客户端收到 EOF 并进入无限重连循环。修复方式:在 `clientPongType` 分支中同步调用 `conn.SetReadDeadline` 刷新超时。
|
||||
- 修复 openflared frpc 子进程异常退出(`exit status 1`)时缺乏详细诊断信息的问题。现捕获 frpc stderr 并在进程退出时将其输出记录到结构化日志 `stderr` 字段,便于排查配置格式错误、Auth Token 鉴权失败、relay 端不可达等具体原因。
|
||||
- 修复 Relay 节点启动时在双栈网络环境可能上报 IPv6 地址,导致 Tunnel frpc 客户端无法连接 frps 的问题。强化 `pkg/geoip.HTTPOutboundIPStrategy` 在回退到双栈客户端后仍优先返回 IPv4 地址,确保 Relay 心跳上报的 IP 与 frpc 连接兼容。
|
||||
|
||||
### 变更
|
||||
|
||||
- 将 OpenFlare 配置体系从独立的 `of_options` 表统一迁移至标准系统配置框架 `w_system_configs`(SystemConfig),全部归类为业务类型(`type=business`)。涵盖 Agent(心跳间隔、发现令牌、更新仓库等)、UptimeKuma 集成、GeoIP、数据库自动清理及全部 OpenResty 主配置项共 48 项。业务代码统一改为通过 `repository.GetSystemConfigByKey`/`GetBoolByKey`/`GetIntByKey` 读取,移除进程级内存快照 `OptionMap` 与启动时热重载机制,配置变更经 Redis 缓存失效实现动态生效。已存在的同义配置(如 `password_login_enabled`、`smtp_host`)不重复迁移,旧系统遗留的 `SystemName`、`Footer`、`HomePageLink`、`About` 等无用项一并清理;公开状态接口 `/api/v1/d/status` 相应移除 `system_name`、`home_page_link`、`footer_html` 字段。数据迁移完成后通过 goose 迁移 `202606220005` 删除遗留的 `of_options` 表。
|
||||
- 优化并统一 `agent`、`relay`、`flared` 的 IP 探测与上报逻辑,均复用公用 `nodeip` 包;在未指定 `node_ip` 时实现心跳 Tick 动态探测上报。
|
||||
- 优化 `pkg/geoip.GetOutboundIP` 出口 IP 探测策略,优先通过 `tcp4` 建立 HTTP 连接以获得 IPv4 公网地址,并在纯 IPv6/无 IPv4 路由环境下自动降级为双栈 `tcp` 握手。
|
||||
- 优化 `agent` 系统指纹缓存算法,计算指纹时排除 `UptimeSeconds` 和 `ReportedAtUnix` 动态字段,防止周期心跳时不断触发冗余完整的系统 Profile 数据上报。
|
||||
|
||||
+3
-9
@@ -16173,12 +16173,6 @@ const docTemplate = `{
|
||||
"email_verification": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"footer_html": {
|
||||
"type": "string"
|
||||
},
|
||||
"home_page_link": {
|
||||
"type": "string"
|
||||
},
|
||||
"password_register_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -16188,9 +16182,6 @@ const docTemplate = `{
|
||||
"start_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"system_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -16617,6 +16608,9 @@ const docTemplate = `{
|
||||
},
|
||||
"web_server_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"web_server_port": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
# of_options 迁移到 w_system_configs 方案
|
||||
|
||||
## 背景
|
||||
|
||||
当前 OpenFlare 使用 `of_options` 表存储系统配置,维护了独立的 OptionMap 内存缓存和热重载机制。为了统一配置管理框架,需要将所有配置迁移到标准的 `w_system_configs` 表,复用现有的 SystemConfig 读取 API 和 Redis 缓存机制。
|
||||
|
||||
## 配置项分类
|
||||
|
||||
### 已存在于 w_system_configs,无需迁移
|
||||
|
||||
以下配置在新系统中已存在,不从 of_options 迁移:
|
||||
|
||||
- `PasswordLoginEnabled` → `password_login_enabled` (已存在)
|
||||
- `CapLoginEnabled` → `cap_login_enabled` (已存在)
|
||||
- `PasswordRegisterEnabled` → `password_register_enabled` (已存在)
|
||||
- `EmailVerificationEnabled` → 映射到 `email_login_verification_enabled` (已存在)
|
||||
- `ServerAddress` → `server_address` (已存在)
|
||||
- `SMTPServer` → `smtp_host` (已存在,字段名不同)
|
||||
- `SMTPPort` → `smtp_port` (已存在)
|
||||
- `SMTPAccount` → `smtp_username` (已存在,字段名不同)
|
||||
- `SMTPToken` → `smtp_password` (已存在,字段名不同)
|
||||
|
||||
### 旧系统冗余配置,直接删除
|
||||
|
||||
以下配置是旧系统遗留,当前系统不使用,不迁移:
|
||||
|
||||
- `SystemName` - 前端不再使用系统名称配置
|
||||
- `Footer` - 前端不再使用页脚 HTML
|
||||
- `HomePageLink` - 前端不再使用首页链接
|
||||
- `About` - 前端不再使用关于信息
|
||||
|
||||
### 需要迁移的配置(全部 type=business)
|
||||
|
||||
**所有迁移的配置都设为 business 类型**。system 类型仅用于框架级配置(如 upload_allowed_extensions、disk_cache_max_size_mb 等)。
|
||||
|
||||
#### Agent 相关配置 (business, visibility=0)
|
||||
|
||||
| 原 Key (PascalCase) | 新 Key (snake_case) | 默认值 | 说明 |
|
||||
|---------------------|---------------------|--------|------|
|
||||
| AgentDiscoveryToken | agent_discovery_token | "" | Agent 发现令牌(敏感) |
|
||||
| AgentHeartbeatInterval | agent_heartbeat_interval | 10000 | Agent 心跳间隔(毫秒) |
|
||||
| AgentWebsocketUpgradeEnabled | agent_websocket_upgrade_enabled | true | Agent WebSocket 升级开关 |
|
||||
| NodeOfflineThreshold | node_offline_threshold | 120000 | 节点离线阈值(毫秒) |
|
||||
| AgentUpdateRepo | agent_update_repo | Rain-kl/OpenFlare | Agent 更新仓库 |
|
||||
|
||||
#### 系统功能配置 (business, visibility=0)
|
||||
|
||||
| 原 Key (PascalCase) | 新 Key (snake_case) | 默认值 | 说明 |
|
||||
|---------------------|---------------------|--------|------|
|
||||
| GeoIPProvider | geoip_provider | ipinfo | GeoIP 服务商 |
|
||||
| DatabaseAutoCleanupEnabled | database_auto_cleanup_enabled | false | 数据库自动清理开关 |
|
||||
| DatabaseAutoCleanupRetentionDays | database_auto_cleanup_retention_days | 30 | 数据库保留天数 |
|
||||
|
||||
#### UptimeKuma 集成配置 (business, visibility=0)
|
||||
|
||||
| 原 Key (PascalCase) | 新 Key (snake_case) | 默认值 | 说明 |
|
||||
|---------------------|---------------------|--------|------|
|
||||
| UptimeKumaEnabled | uptime_kuma_enabled | false | UptimeKuma 集成开关 |
|
||||
| UptimeKumaUrl | uptime_kuma_url | "" | UptimeKuma URL |
|
||||
| UptimeKumaUsername | uptime_kuma_username | "" | UptimeKuma 用户名 |
|
||||
| UptimeKumaPassword | uptime_kuma_password | "" | UptimeKuma 密码(敏感) |
|
||||
| UptimeKumaMonitorScope | uptime_kuma_monitor_scope | all | UptimeKuma 监控范围 |
|
||||
| UptimeKumaSelectedSites | uptime_kuma_selected_sites | "" | UptimeKuma 选定站点 |
|
||||
| UptimeKumaSyncInterval | uptime_kuma_sync_interval | 5 | UptimeKuma 同步间隔(分钟) |
|
||||
| UptimeKumaInterval | uptime_kuma_interval | 60 | UptimeKuma 监控间隔(秒) |
|
||||
| UptimeKumaRetry | uptime_kuma_retry | 0 | UptimeKuma 重试次数 |
|
||||
| UptimeKumaRetryInterval | uptime_kuma_retry_interval | 60 | UptimeKuma 重试间隔(秒) |
|
||||
| UptimeKumaTimeout | uptime_kuma_timeout | 48 | UptimeKuma 超时(秒) |
|
||||
|
||||
### OpenResty 配置 (type=business)
|
||||
|
||||
OpenResty 反向代理和缓存配置,全部为 business 类型,visibility=0:
|
||||
|
||||
| 原 Key (PascalCase) | 新 Key (snake_case) | 默认值 |
|
||||
|---------------------|---------------------|--------|
|
||||
| OpenRestyDefaultServerReturnStatus | openresty_default_server_return_status | 421 |
|
||||
| OpenRestyWorkerProcesses | openresty_worker_processes | auto |
|
||||
| OpenRestyWorkerConnections | openresty_worker_connections | 4096 |
|
||||
| OpenRestyWorkerRlimitNofile | openresty_worker_rlimit_nofile | 65535 |
|
||||
| OpenRestyEventsUse | openresty_events_use | epoll |
|
||||
| OpenRestyEventsMultiAcceptEnabled | openresty_events_multi_accept_enabled | true |
|
||||
| OpenRestyKeepaliveTimeout | openresty_keepalive_timeout | 20 |
|
||||
| OpenRestyKeepaliveRequests | openresty_keepalive_requests | 1000 |
|
||||
| OpenRestyClientHeaderTimeout | openresty_client_header_timeout | 15 |
|
||||
| OpenRestyClientBodyTimeout | openresty_client_body_timeout | 15 |
|
||||
| OpenRestyClientMaxBodySize | openresty_client_max_body_size | 64m |
|
||||
| OpenRestyLargeClientHeaderBuffers | openresty_large_client_header_buffers | 4 16k |
|
||||
| OpenRestySendTimeout | openresty_send_timeout | 30 |
|
||||
| OpenRestyResolvers | openresty_resolvers | "" |
|
||||
| OpenRestyProxyConnectTimeout | openresty_proxy_connect_timeout | 3 |
|
||||
| OpenRestyProxySendTimeout | openresty_proxy_send_timeout | 60 |
|
||||
| OpenRestyProxyReadTimeout | openresty_proxy_read_timeout | 60 |
|
||||
| OpenRestyWebsocketEnabled | openresty_websocket_enabled | true |
|
||||
| OpenRestyHTTP3Enabled | openresty_http3_enabled | true |
|
||||
| OpenRestyProxyRequestBufferingEnabled | openresty_proxy_request_buffering_enabled | false |
|
||||
| OpenRestyProxyBufferingEnabled | openresty_proxy_buffering_enabled | true |
|
||||
| OpenRestyProxyBuffers | openresty_proxy_buffers | 16 16k |
|
||||
| OpenRestyProxyBufferSize | openresty_proxy_buffer_size | 8k |
|
||||
| OpenRestyProxyBusyBuffersSize | openresty_proxy_busy_buffers_size | 64k |
|
||||
| OpenRestyGzipEnabled | openresty_gzip_enabled | true |
|
||||
| OpenRestyGzipMinLength | openresty_gzip_min_length | 1024 |
|
||||
| OpenRestyGzipCompLevel | openresty_gzip_comp_level | 5 |
|
||||
| OpenRestyCacheEnabled | openresty_cache_enabled | false |
|
||||
| OpenRestyCachePath | openresty_cache_path | "" |
|
||||
| OpenRestyCacheLevels | openresty_cache_levels | 1:2 |
|
||||
| OpenRestyCacheInactive | openresty_cache_inactive | 30m |
|
||||
| OpenRestyCacheMaxSize | openresty_cache_max_size | 1g |
|
||||
| OpenRestyCacheKeyTemplate | openresty_cache_key_template | $scheme$host$request_uri |
|
||||
| OpenRestyCacheLockEnabled | openresty_cache_lock_enabled | true |
|
||||
| OpenRestyCacheLockTimeout | openresty_cache_lock_timeout | 5s |
|
||||
| OpenRestyCacheUseStale | openresty_cache_use_stale | error timeout updating http_500... |
|
||||
| OpenRestyMainConfigTemplate | openresty_main_config_template | (长模板) |
|
||||
|
||||
**总计**:约 58 个配置需要迁移,全部为 business 类型。
|
||||
|
||||
## 迁移策略
|
||||
|
||||
### 1. 保持向后兼容
|
||||
|
||||
- 在迁移期间同时支持旧 API (`/api/v1/openflare/options`) 和新 API (`/api/v1/admin/system-configs`)
|
||||
- 旧 API 内部委派到 SystemConfig 读写,不再直接操作 of_options 表
|
||||
- 保留 `/api/v1/openflare/status` 接口,但从 SystemConfig 读取数据
|
||||
|
||||
### 2. 数据迁移顺序
|
||||
|
||||
1. 创建新的 ConfigKey 常量(已完成)
|
||||
2. 创建 goose 迁移脚本,将 of_options 真正需要的配置复制到 w_system_configs(已完成)
|
||||
3. 重构代码使用 repository.GetSystemConfigByKey / GetBoolByKey / GetIntByKey
|
||||
4. 标记 of_options 表为 deprecated(保留一段时间用于回滚)
|
||||
5. 后续版本完全删除 of_options 相关代码
|
||||
|
||||
### 3. 配置类型说明
|
||||
|
||||
**所有从 of_options 迁移的配置都设为 business 类型**:
|
||||
- `type='business'`:业务配置,影响业务规则和功能行为
|
||||
- `type='system'`:框架配置,仅用于框架级设置(如 upload_allowed_extensions、disk_cache_max_size_mb)
|
||||
|
||||
**不迁移的配置**:
|
||||
- 已存在于 w_system_configs 的配置(如 password_login_enabled、smtp_host)
|
||||
- 旧系统冗余配置(SystemName、Footer、HomePageLink、About)
|
||||
|
||||
### 4. 包级变量处理
|
||||
|
||||
原 `openflare_option.go` 中的包级变量(如 `SystemName`、`PasswordLoginEnabled`)将被移除。所有读取改为:
|
||||
|
||||
```go
|
||||
// 旧方式(包级变量)
|
||||
systemName := model.SystemName
|
||||
enabled := model.PasswordLoginEnabled
|
||||
|
||||
// 新方式(repository 读取)
|
||||
systemName, err := repository.GetSystemConfigByKey(ctx, model.ConfigKeySystemName)
|
||||
enabled, err := repository.GetBoolByKey(ctx, model.ConfigKeyPasswordLoginEnabled)
|
||||
```
|
||||
|
||||
注意:对于已存在的配置,使用对应的新 key:
|
||||
```go
|
||||
// 已存在的配置使用现有 key
|
||||
enabled, err := repository.GetBoolByKey(ctx, model.ConfigKeyPasswordLoginEnabled) // 不是 ConfigKeySystemName
|
||||
```
|
||||
|
||||
### 5. 热重载机制
|
||||
|
||||
- 移除 `InitOptionMap` 和 `OptionMapRWMutex`
|
||||
- SystemConfig 已通过 Redis 缓存实现热重载,更新后自动失效
|
||||
|
||||
## 实现步骤
|
||||
|
||||
1. ✅ 分析配置项并设计迁移方案(本文档)
|
||||
2. 在 `system_configs.go` 添加所有 ConfigKey 常量
|
||||
3. 创建 goose 迁移脚本(PostgreSQL + SQLite)
|
||||
4. 重构所有业务代码使用 SystemConfig API
|
||||
5. 更新 option 模块 API 和测试
|
||||
6. 清理 of_options 遗留代码并验证
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **敏感配置处理**:包含 Token/Password/Secret 的配置不应暴露给前端(visibility=0)
|
||||
2. **类型转换**:of_options 将数值存为字符串,需要在读取时正确转换
|
||||
3. **默认值一致性**:确保 SQL 迁移中的默认值与代码中的默认值一致
|
||||
4. **模板配置**:`OpenRestyMainConfigTemplate` 是长文本,需要正确处理
|
||||
5. **测试覆盖**:所有使用 OptionMap 的测试需要更新为使用 SystemConfig
|
||||
|
||||
## 后续清理计划
|
||||
|
||||
迁移完成后,在下一个主版本(如 v2.0)中完全移除:
|
||||
|
||||
- `internal/model/openflare_option.go`
|
||||
- `internal/model/openflare_option_apply.go`
|
||||
- `of_options` 表及相关迁移文件
|
||||
- `internal/apps/openflare/option` 模块(或重构为 SystemConfig 的代理)
|
||||
+3
-9
@@ -16166,12 +16166,6 @@
|
||||
"email_verification": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"footer_html": {
|
||||
"type": "string"
|
||||
},
|
||||
"home_page_link": {
|
||||
"type": "string"
|
||||
},
|
||||
"password_register_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -16181,9 +16175,6 @@
|
||||
"start_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"system_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -16610,6 +16601,9 @@
|
||||
},
|
||||
"web_server_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"web_server_port": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+2
-6
@@ -2300,18 +2300,12 @@ definitions:
|
||||
type: boolean
|
||||
email_verification:
|
||||
type: boolean
|
||||
footer_html:
|
||||
type: string
|
||||
home_page_link:
|
||||
type: string
|
||||
password_register_enabled:
|
||||
type: boolean
|
||||
server_address:
|
||||
type: string
|
||||
start_time:
|
||||
type: integer
|
||||
system_name:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
@@ -2592,6 +2586,8 @@ definitions:
|
||||
type: integer
|
||||
web_server_enabled:
|
||||
type: boolean
|
||||
web_server_port:
|
||||
type: integer
|
||||
type: object
|
||||
protocol.RelayProxyStat:
|
||||
properties:
|
||||
|
||||
Reference in New Issue
Block a user