Skip to content

Commit 7edcf03

Browse files
committed
release: v1.7.1
1 parent 9a7ee0c commit 7edcf03

File tree

13 files changed

+2621
-439
lines changed

13 files changed

+2621
-439
lines changed

config.yaml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
base:
22
name: FileCodeBox
33
description: 开箱即用的文件快传系统
4-
keywords: ""
4+
keywords: FileCodeBox, 文件快递柜, 口令传送箱, 匿名口令分享文本, 文件
55
port: 12345
66
host: 0.0.0.0
77
datapath: /Users/zhangyi/zy/FileCodeBox/data
@@ -44,8 +44,6 @@ mcp:
4444
enablemcpserver: 0
4545
mcpport: ""
4646
mcphost: ""
47-
notifytitle: ""
48-
notifycontent: ""
4947
ui:
5048
themes_select: themes/2025
5149
background: ""
@@ -54,15 +52,9 @@ ui:
5452
User-agent: *
5553
Disallow: /
5654
show_admin_addr: 0
57-
opacity: 0
58-
themes_select: themes/2025
59-
robots_text: |-
60-
User-agent: *
61-
Disallow: /
62-
page_explain: 请勿上传或分享违法内容。根据《中华人民共和国网络安全法》、《中华人民共和国刑法》、《中华人民共和国治安管理处罚法》等相关规定。 传播或存储违法、违规内容,会受到相关处罚,严重者将承担刑事责任。本站坚决配合相关部门,确保网络内容的安全,和谐,打造绿色网络环境。
63-
show_admin_addr: 0
64-
opacity: 0
65-
background: ""
55+
opacity: 1
56+
notify_title: ""
57+
notify_content: ""
6658
sys_start: ""
6759
upload_minute: 0
6860
upload_count: 0

internal/config/manager.go

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package config
33
import (
44
"errors"
55
"os"
6-
"strconv"
76
"strings"
87

98
"gopkg.in/yaml.v3"
@@ -56,15 +55,17 @@ func NewConfigManager() *ConfigManager {
5655
func InitManager() *ConfigManager {
5756
cm := NewConfigManager()
5857

59-
// 尝试加载 YAML 配置文件
58+
var sources []ConfigSource
59+
6060
if configPath := os.Getenv("CONFIG_PATH"); configPath != "" {
61-
_ = cm.LoadFromYAML(configPath)
61+
sources = append(sources, YAMLFileSource{Path: configPath})
6262
} else if _, err := os.Stat("./config.yaml"); err == nil {
63-
_ = cm.LoadFromYAML("./config.yaml")
63+
sources = append(sources, YAMLFileSource{Path: "./config.yaml"})
6464
}
6565

66-
// 应用环境变量覆盖
67-
cm.applyEnvironmentOverrides()
66+
sources = append(sources, NewDefaultEnvSource())
67+
68+
_ = cm.ApplySources(sources...)
6869
return cm
6970
}
7071

@@ -135,24 +136,24 @@ func (cm *ConfigManager) mergeSimpleFields(fileCfg *ConfigManager) {
135136
}
136137
}
137138

138-
// LoadFromYAML 从 YAML 文件加载配置
139-
func (cm *ConfigManager) LoadFromYAML(path string) error {
140-
b, err := os.ReadFile(path)
141-
if err != nil {
142-
return err
143-
}
144-
145-
var fileCfg ConfigManager
146-
if err := yaml.Unmarshal(b, &fileCfg); err != nil {
147-
return err
139+
// ApplySources processes a group of configuration sources and collects errors.
140+
func (cm *ConfigManager) ApplySources(sources ...ConfigSource) error {
141+
var errs []error
142+
for _, source := range sources {
143+
if source == nil {
144+
continue
145+
}
146+
if err := source.Apply(cm); err != nil {
147+
errs = append(errs, err)
148+
}
148149
}
149150

150-
// 按模块合并配置
151-
cm.mergeConfigModules(&fileCfg)
152-
cm.mergeUserConfig(fileCfg.User)
153-
cm.mergeSimpleFields(&fileCfg)
151+
return errors.Join(errs...)
152+
}
154153

155-
return nil
154+
// LoadFromYAML 从 YAML 文件加载配置
155+
func (cm *ConfigManager) LoadFromYAML(path string) error {
156+
return cm.ApplySources(YAMLFileSource{Path: path})
156157
}
157158

158159
// ReloadConfig 重新加载配置(仅支持环境变量,保持端口不变)
@@ -190,30 +191,8 @@ func (cm *ConfigManager) PersistYAML() error {
190191

191192
// applyEnvironmentOverrides 应用环境变量覆盖配置
192193
func (cm *ConfigManager) applyEnvironmentOverrides() {
193-
// 基础配置环境变量
194-
if port := os.Getenv("PORT"); port != "" {
195-
if n, err := strconv.Atoi(port); err == nil {
196-
cm.Base.Port = n
197-
}
198-
}
199-
if dataPath := os.Getenv("DATA_PATH"); dataPath != "" {
200-
cm.Base.DataPath = dataPath
201-
}
202-
203-
// MCP 配置环境变量
204-
if enableMCP := os.Getenv("ENABLE_MCP_SERVER"); enableMCP != "" {
205-
if enableMCP == "true" || enableMCP == "1" {
206-
cm.MCP.EnableMCPServer = 1
207-
} else {
208-
cm.MCP.EnableMCPServer = 0
209-
}
210-
}
211-
if mcpPort := os.Getenv("MCP_PORT"); mcpPort != "" {
212-
cm.MCP.MCPPort = mcpPort
213-
}
214-
if mcpHost := os.Getenv("MCP_HOST"); mcpHost != "" {
215-
cm.MCP.MCPHost = mcpHost
216-
}
194+
// 收集错误以便在调用者中统一处理,保持现有签名
195+
_ = NewDefaultEnvSource().Apply(cm)
217196
}
218197

219198
// Save 保存配置(已废弃,请使用 config.yaml 和环境变量)

internal/config/manager_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,18 @@ func TestEnvOverride(t *testing.T) {
6666
t.Fatalf("expected PORT env to override to 9090, got %d", cm.Base.Port)
6767
}
6868
}
69+
70+
func TestApplySourcesAggregatesErrors(t *testing.T) {
71+
cm := NewConfigManager()
72+
src := NewDefaultEnvSource()
73+
src.lookup = func(key string) string {
74+
if key == "ENABLE_MCP_SERVER" {
75+
return "definitely-not-bool"
76+
}
77+
return ""
78+
}
79+
80+
if err := cm.ApplySources(src); err == nil {
81+
t.Fatalf("expected aggregated error when environment value invalid")
82+
}
83+
}

internal/config/source.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"strconv"
8+
"strings"
9+
10+
"gopkg.in/yaml.v3"
11+
)
12+
13+
// ConfigSource represents a configuration input that can mutate the manager state.
14+
type ConfigSource interface {
15+
Apply(*ConfigManager) error
16+
}
17+
18+
// ConfigSourceFunc allows plain functions to be used as ConfigSource.
19+
type ConfigSourceFunc func(*ConfigManager) error
20+
21+
// Apply executes the underlying function.
22+
func (f ConfigSourceFunc) Apply(cm *ConfigManager) error { return f(cm) }
23+
24+
// YAMLFileSource loads configuration values from a YAML file.
25+
type YAMLFileSource struct {
26+
Path string
27+
}
28+
29+
// Apply reads and merges YAML content into the manager.
30+
func (s YAMLFileSource) Apply(cm *ConfigManager) error {
31+
if strings.TrimSpace(s.Path) == "" {
32+
return errors.New("config: YAML path is empty")
33+
}
34+
35+
data, err := os.ReadFile(s.Path)
36+
if err != nil {
37+
return err
38+
}
39+
40+
var fileCfg ConfigManager
41+
if err := yaml.Unmarshal(data, &fileCfg); err != nil {
42+
return fmt.Errorf("config: unmarshal %s: %w", s.Path, err)
43+
}
44+
45+
cm.mergeConfigModules(&fileCfg)
46+
cm.mergeUserConfig(fileCfg.User)
47+
cm.mergeSimpleFields(&fileCfg)
48+
return nil
49+
}
50+
51+
type envOverride struct {
52+
key string
53+
apply func(string, *ConfigManager) error
54+
}
55+
56+
// EnvSource mutates configuration using environment variables.
57+
type EnvSource struct {
58+
overrides []envOverride
59+
lookup func(string) string
60+
}
61+
62+
// NewDefaultEnvSource returns the built-in environment overrides.
63+
func NewDefaultEnvSource() EnvSource {
64+
return EnvSource{
65+
overrides: []envOverride{
66+
{key: "PORT", apply: applyPortOverride},
67+
{key: "DATA_PATH", apply: applyDataPathOverride},
68+
{key: "ENABLE_MCP_SERVER", apply: applyMCPEnabledOverride},
69+
{key: "MCP_PORT", apply: applyMCPPortOverride},
70+
{key: "MCP_HOST", apply: applyMCPHostOverride},
71+
},
72+
}
73+
}
74+
75+
// Apply applies every configured override.
76+
func (s EnvSource) Apply(cm *ConfigManager) error {
77+
lookup := s.lookup
78+
if lookup == nil {
79+
lookup = os.Getenv
80+
}
81+
82+
var errs []error
83+
for _, override := range s.overrides {
84+
if value := lookup(override.key); value != "" {
85+
if err := override.apply(value, cm); err != nil {
86+
errs = append(errs, fmt.Errorf("%s: %w", override.key, err))
87+
}
88+
}
89+
}
90+
91+
return errors.Join(errs...)
92+
}
93+
94+
func applyPortOverride(val string, cm *ConfigManager) error {
95+
port, err := strconv.Atoi(val)
96+
if err != nil {
97+
return fmt.Errorf("invalid port %q", val)
98+
}
99+
cm.Base.Port = port
100+
return nil
101+
}
102+
103+
func applyDataPathOverride(val string, cm *ConfigManager) error {
104+
if strings.TrimSpace(val) == "" {
105+
return errors.New("data path cannot be blank")
106+
}
107+
cm.Base.DataPath = val
108+
return nil
109+
}
110+
111+
func applyMCPEnabledOverride(val string, cm *ConfigManager) error {
112+
enabled, err := parseBool(val)
113+
if err != nil {
114+
return err
115+
}
116+
if enabled {
117+
cm.MCP.EnableMCPServer = 1
118+
} else {
119+
cm.MCP.EnableMCPServer = 0
120+
}
121+
return nil
122+
}
123+
124+
func applyMCPPortOverride(val string, cm *ConfigManager) error {
125+
cm.MCP.MCPPort = val
126+
return nil
127+
}
128+
129+
func applyMCPHostOverride(val string, cm *ConfigManager) error {
130+
cm.MCP.MCPHost = val
131+
return nil
132+
}
133+
134+
func parseBool(val string) (bool, error) {
135+
switch strings.ToLower(strings.TrimSpace(val)) {
136+
case "1", "true", "t", "yes", "y":
137+
return true, nil
138+
case "0", "false", "f", "no", "n":
139+
return false, nil
140+
default:
141+
return false, fmt.Errorf("invalid boolean value %q", val)
142+
}
143+
}

internal/handlers/admin.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ func (h *AdminHandler) GetConfig(c *gin.Context) {
137137
SysStart: &cfg.SysStart,
138138
},
139139
}
140+
141+
resp.NotifyTitle = &cfg.NotifyTitle
142+
resp.NotifyContent = &cfg.NotifyContent
140143
common.SuccessResponse(c, resp)
141144
}
142145

internal/models/web/admin.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ type AdminConfigRequest struct {
160160

161161
// 系统运行时特有字段(不属于配置模块的字段)
162162
SysStart *string `json:"sys_start,omitempty"`
163+
164+
// 顶层通知字段保留与历史配置结构兼容
165+
NotifyTitle *string `json:"notify_title,omitempty"`
166+
NotifyContent *string `json:"notify_content,omitempty"`
163167
}
164168

165169
// CountResponse 通用计数响应

0 commit comments

Comments
 (0)