Help us shape the future of Go! Take the 2026 Go Developer Survey

config

package
v0.32.41 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

config.go 站点配置模型与校验:SystemConfig/UserSettings 类型、默认值、 写库前校验(纯函数簇,自 admin 域原样迁入)。

presign_policy_migration.go — 旧直传开关 download.presign_anonymous_enabled 退役(2026-10-26 兼容层清理)。

背景:直传策略先后经历两代形态:

① 旧:download.presign_anonymous_enabled(bool,true=匿名可直传)
② 新:download.presign_policy(三档 everyone/authenticated/disabled)

② 引入时 ① 被保留为回退读路径(显式 ② 为空 ⇒ 读 ①)。本次退役 ① 时, 存量库里仍可能带着 ① 的值:**直接忽略会让「曾关闭匿名直传」的站点 静默变成 everyone**(= 桶沦为免费匿名网盘,见 presign handler 的动机注释)。

处置:**读取时并入 ② + 启动响亮提示**。

  • ② 已显式设置 ⇒ 以 ② 为准,① 直接忽略(管理员已在管理台改过策略)。
  • ② 未设置(空串)⇒ 由 ① 推导:false→authenticated,true→everyone。
  • ① 从数据库消失:管理台整段保存即自然清掉(json 解码忽略未知键, 重新序列化时不带该键)。

Package config 全站配置中心域:system_configs 单行 JSON 的唯一写者。

2026-10-10 自 admin 域独立——此前三段职责挤在 admin:管理面 API、治理操作 (用户/文件/统计/维护)、以及被 user/storage/bootstrap/mcp 四面消费的 全站配置中心(~500 行)。配置中心的归属错位使 admin 成为事实上的上帝域, 且"管理端在线设置"的读写方横跨四个域。独立后:

  • 本域持有:内存缓存+懒加载、写穿 DB、校验、全局 conf overlay 热应用、 组件热重建钩子(ReconfigureHooks)、多副本变更广播回调、运行时存储 配置持久化(storage.RuntimePersister 实现)、用户设置生效语义 (EffectiveUserSettings)与配置操作审计。
  • admin 域保留管理面 API 门面(委派方法 + 类型别名,消费方零改动)与 治理/审计职责。
  • bootstrap(装配层)直接指向本域单例接线。

单实例约束:system_configs 是"单行 JSON 读改写"语义,必须全站单实例—— 多实例各自缓存内存副本会互相覆盖(用户设置写入后公共配置读旧值的 2026-10-03 事故即由此而来)。Default() 是全站唯一实例;NewService() 仅供测试/嵌入式构造独立实例。

stale.go — 陈旧配置键检出(2026-10-22 Wave B':设备直传面退役)。

背景:Wave B' 从 SystemConfig.p2p 段删掉了 direct 子段(p2pc 直传参数)。 Go 的 json 解码**静默忽略**未知键 —— 存量库里若仍有 `{"p2p":{"direct":{"registry_url":"http://p2p:56788",...}}}`,该段会被 无声丢弃:用户以为「注册中心还配着」,实际联邦名录已失去在线对端 (名录的 registry 真相源只剩 p2p.federation.registry_url)。

处置:**忽略 + 启动响亮提示**。本文件只做「检出」,不修复、不删库 (改库是管理员的动作,且 admin 后台整段保存即自然清掉该键)。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InitDefault added in v0.16.0

func InitDefault(gormDB *gorm.DB)

InitDefault 注册全站配置中心单例(bootstrap 在 InitDatabase 后调用;幂等)。 单实例约束见包注释:system_configs 单行读改写不允许多实例并存。

Types

type BaseConfig added in v0.18.0

type BaseConfig struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Port        int    `json:"port"`

	// PublicURL 站点公网地址(2026-10-22 落地,可选):用户可访问本柜的对外
	// 地址(如 https://box.example.com)。分享链接与「交付文本」按它拼;
	// 为空 = 未配置 = 前端回退浏览器当前 origin。
	//
	// 为什么需要:分享链接原先按**请求 origin** 拼(frontend-core
	// ShareResultDialog.vue),NAS/内网部署时管理员从内网访问 → 生成的链接
	// 带内网 IP(如 http://10.10.10.3:56789)→ 发给外部用户根本打不开。
	// 这是"多部署方式"下最隐蔽的易用性断点。
	PublicURL string `json:"public_url"`
}

BaseConfig 站点基础信息段。指针语义与其余段一致:nil = 本次未提交, UpdateConfig 保留现状(值类型无法表达"未提交",局部保存曾把整段清零)。

type P2PSection added in v0.19.0

type P2PSection struct {
	// Federation 联邦控制面(overlay → conf.Federation;nil = 保留现状)
	Federation *conf.FederationConfig `json:"federation,omitempty"`
}

P2PSection P2P 能力配置段(spec 2026-10-14 §5)。

2026-10-22 Wave B':直传段(direct)随 Box 侧直传编排层整体退役 —— 本段 只剩联邦段。存量 DB 里若仍有 p2p.direct.*(尤其 registry_url),该段被 **忽略**并在启动日志响亮提示(见 stale.go);注册中心请改配 p2p.federation.registry_url。

type ReconfigureHooks

type ReconfigureHooks struct {
	// OnNotifyChanged Webhook+SMTP 热重建(mailer 按新 SMTP 段重建,host 空=卸载)
	OnNotifyChanged func(n *conf.NotifyConfig)
	// OnOIDCChanged OIDC service 热重建(按新段;Enabled=false 时 handler 走未启用响应)
	OnOIDCChanged func(o *conf.OIDCConfig)
	// OnP2PFederationChanged federation 运行时热切换(bootstrap 注册;P1 对称节点
	// spec §6)。返回 error 时 UpdateConfig 透传给管理员——切换失败但配置已持久化
	// 的分叉必须响亮(spec §12.4),禁止静默。
	OnP2PFederationChanged func(f *conf.FederationConfig) error
	// OnOverlayApplied SystemConfig 段 overlay 进全局 conf 之后的回调(bootstrap
	// 注册 env 恒覆盖重施器:统一优先级 yaml < DB < env,2026-10-15)。持 configMu
	// 同步调用,实现方只许操作全局 conf/env,不得回调 config service。
	OnOverlayApplied func()
}

ReconfigureHooks 存储域之外的组件热重建钩子(bootstrap 注册;SMTP mailer / OIDC service)。 参数为合并后的新段;nil 段表示维持现状。

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service 配置中心服务。

func Default

func Default() *Service

Default 全站共享的配置中心实例。未 InitDefault 直接取用是装配错误,fail-loud。

func DefaultSafe added in v0.32.30

func DefaultSafe() *Service

DefaultSafe 未装配时返回 nil(**不** panic)——供「可选读取」场景使用。

与 Default 的区别:Default 是 fail-loud(业务路径拿不到配置中心 = 装配错误, 必须当场炸出来);DefaultSafe 供**确实可能没有配置中心**的读取点, 例如能力快照(bootstrap 早期阶段、单元测试未 InitDefault)。 ⚠️ 用它的地方必须自己处理 nil(缺配置 ≠ 崩溃,但也不能假装有值)。

func NewService

func NewService(gormDB *gorm.DB) *Service

NewService 构造独立实例(测试/嵌入式;全站运行时请用 Default()—— 单行读改写语义不允许多实例并存,见包注释)。

func (*Service) EffectiveUploadBatchCap added in v0.32.31

func (s *Service) EffectiveUploadBatchCap(ctx context.Context) int64

EffectiveUploadBatchCap 生效的站点默认「单次发送**总量**上限」(字节,0=不限)。

与 upload.max_file_size(**单文件**上限)是两个不同的闸:

· max_file_size:单个文件的体积上限
· 本值:一次发送(多文件合计)的体积上限,**只约束登录用户**
  (匿名走访客日配额 upload.anonymous_daily_bytes)

取值 = 管理后台持久化的 user 段(无记录回退 yaml),与 user 域 GetUploadSizeCap 的**系统默认层**同源;**不含** per-user 覆盖 (users.max_upload_size 是登录用户私有值,不上公开面——服务端 413 才是权威, 本值只用于前端**提示**)。

func (*Service) GetConfig

func (s *Service) GetConfig(ctx context.Context) (*SystemConfig, error)

GetConfig 获取系统配置(首次调用会从 DB 加载管理后台保存的配置)

func (*Service) InvalidateRuntimeConfig

func (s *Service) InvalidateRuntimeConfig()

InvalidateRuntimeConfig 丢弃内存配置缓存(仅影响缓存,不写库)。 多副本:public 副本收到管理端变更广播后调用,下次 GetConfig 重读 DB—— 单机 standalone 不调用(保持既有"进程内即真相"语义)。

func (*Service) LoadRuntimeStorage

func (s *Service) LoadRuntimeStorage(ctx context.Context) *conf.StorageConfig

LoadRuntimeStorage 读取持久化的运行时存储配置(storage.RuntimePersister 实现)。 无记录/未设置返回 nil;DB 不可用返回 nil(与配置加载的降级策略一致)。

func (*Service) RestoreAdminSettings

func (s *Service) RestoreAdminSettings()

RestoreAdminSettings 启动时把持久化的新段 overlay 回全局 conf(DB 先于服务启动就绪)。 由 bootstrap 在 restoreRuntimeStorage 同相位调用。

func (*Service) SaveRuntimeStorage

func (s *Service) SaveRuntimeStorage(ctx context.Context, cfg *conf.StorageConfig) error

SaveRuntimeStorage 持久化运行时存储配置(storage.RuntimePersister 实现)。 读改写单行 JSON,只更新 runtime_storage 段;DB 不可用时返回错误, 由调用方(存储域)决定提示语义——切换已生效,仅持久化失败。

func (*Service) SetConfig

func (s *Service) SetConfig(config *SystemConfig)

SetConfig 设置配置(显式注入优先于 DB 持久化配置)

func (*Service) SetOnConfigPersisted

func (s *Service) SetOnConfigPersisted(fn func())

SetOnConfigPersisted 注入配置持久化回调(bootstrap 调用)。多副本拆分时 admin 实例经它发布 Redis 变更广播,public 副本订阅后失效本地缓存并热重建 (详见 docs/specs/2026-10-06-multi-replica-deployment-modes.md §4)。

func (*Service) SetReconfigureHooks

func (s *Service) SetReconfigureHooks(h *ReconfigureHooks)

SetReconfigureHooks 注册组件热重建钩子(bootstrap 调用)。

func (*Service) UpdateConfig

func (s *Service) UpdateConfig(ctx context.Context, newConfig *SystemConfig) error

UpdateConfig 更新系统配置:写穿到 DB(单行),成功后才更新内存。 防御性合并:handler 会从请求重建 SystemConfig,请求不含 runtime_storage (存储域维护的运行时段),为 nil 时保留旧值,避免保存站点配置时被冲掉。

func (*Service) UpdateConfigJSON added in v0.31.3

func (s *Service) UpdateConfigJSON(ctx context.Context, raw []byte) error

UpdateConfigJSON 按**字段级**合并提交的 JSON 到已落库配置后保存。

此前 PUT /admin/config 的语义只到「段级」:nil 段保留现状,但**段内**未提及的 字段会被**整体清零**(JSON 反序列化进结构体 ⇒ 未提及字段取零值)。实测后果 (2026-10-23 真机):

PUT {"upload_ex":{"max_file_size":1024}}
  ⇒ upload_ex 其余字段全部归零 ⇒ open_upload=false(匿名上传被"关闭",
    /share/file/ 立刻 10012)、enable_chunk=false、enable_magic_check=false、
    text_max_bytes=0、local_import.roots 清空……
  ⇒ 看起来只改了一个字段,实际把整段配置弄没了。

新语义(**字段级合并**):

  • 提交里**出现**的字段生效(显式 null 视为"清空该字段" ⇒ **切片/指针项 可清空**;⚠️ **标量字段的 null 是 no-op** —— Go 的 json 把 null 解进 非指针标量不改值(那些字段的 0 本身就是"不限/关闭"语义,清不清等价);
  • 提交里**未出现**的字段保留现状(含嵌套对象:改 notify.smtp.host 不会把 同级的 smtp.port/smtp.username 清零);
  • 未提交的段整体保留。

合并底座用**已落库**的配置(不是 overlay 后的运行态:overlay 含 env 种子, 把它当底座会把 env 值固化进库)。

func (*Service) UpdateUserSettings

func (s *Service) UpdateUserSettings(ctx context.Context, u UserSettings) error

UpdateUserSettings 在线更新"用户配置"段:读改写当前配置,仅替换 User, 其余段保持不变;写穿 DB 并即时应用副作用(会话时长)。

func (*Service) UpdateUserSettingsJSON added in v0.31.4

func (s *Service) UpdateUserSettingsJSON(ctx context.Context, raw []byte) error

UpdateUserSettingsJSON 按**字段级**合并提交的 JSON 到当前用户配置段后保存。

与 UpdateConfigJSON 同一原则:部分提交**不得**把未提及的字段清零 —— 例如只提交 {"allowuserregistration":true},此前会把 sessionexpiryhours / useruploadsize / userstoragequota 一并清零(0 = 走包默认/不限)⇒ 看着只改 一个开关,实际把会话时长等配置弄没了(2026-10-23 真机实测同类问题)。

合并底座 = 当前**生效**的用户配置(已在线配置的取持久化值,未配置的取 yaml 默认)⇒ 合并后未提及的字段保持当前生效值。

type StorageSettings added in v0.18.0

type StorageSettings struct {
	Type    string `json:"type"`
	MaxSize int64  `json:"max_size"`
}

StorageSettings 存储概览段(nil 语义同 BaseConfig;运行时存储后端走 runtime_storage)。

type SystemConfig

type SystemConfig struct {
	Base     *BaseConfig       `json:"base,omitempty"`
	Storage  *StorageSettings  `json:"storage,omitempty"`
	Transfer *TransferSettings `json:"transfer,omitempty"`

	// RuntimeStorage 运行时存储配置(存储域经 RuntimePersister 接口读写,
	// 本域只负责持久化不解释其内容;nil 表示管理端从未在线改过存储后端)。
	RuntimeStorage *conf.StorageConfig `json:"runtime_storage,omitempty"`

	// User 用户设置(注册开关/上传限制/存储配额/会话时长)。
	// nil 表示从未在线保存过 → 运行时回退 yaml 全局配置(EffectiveUserSettings)。
	// JSON 键沿用前端 configForm.user 的既有键名,读写端点直传免转换。
	User *UserSettings `json:"user,omitempty"`

	// ===== v0.7.3 扩容的在线设置段(同 User 语义:nil = 未在线设置 → yaml 生效;
	// 非 nil = 保存时整体 overlay 到全局 conf 并热应用,重启由 restoreAdminSettings 恢复)=====
	// 外观(背景图/主题色/管理入口可见性)
	UI *conf.UIConfig `json:"ui,omitempty"`
	// 上传细项(文本上限/扩展名白黑名单/匿名日配额/整文件上限/全局过期上限/过期样式裁剪)
	UploadEx *conf.UploadConfig `json:"upload_ex,omitempty"`
	// 下载(S3 直下/超时/需登录)
	Download *conf.DownloadConfig `json:"download,omitempty"`
	// 通知(Webhook + SMTP;保存经 Reconfigurers 热重建 mailer)
	Notify *conf.NotifyConfig `json:"notify,omitempty"`
	// 本地导入(enabled/roots)
	LocalImport *conf.LocalImportConfig `json:"local_import,omitempty"`
	// OIDC 单点登录
	OIDC *conf.OIDCConfig `json:"oidc,omitempty"`
	// API Key 认证总开关与 per-Key 限流
	APIToken *conf.APITokenConfig `json:"api_token,omitempty"`

	// P2P P2P 能力段(2026-10-14 对称节点 spec §5):Federation 控制面在线开关;
	// 直传数据面参数(enabled/send_roots/…)随 P2a 落地。nil = 未在线设置。
	P2P *P2PSection `json:"p2p,omitempty"`
}

type TransferSettings added in v0.18.0

type TransferSettings struct {
	MaxCount      int `json:"max_count"`
	ExpireDefault int `json:"expire_default"`
}

TransferSettings 分享传输默认值段(nil 语义同 BaseConfig)。

type UserSettings

type UserSettings struct {
	// AllowUserRegistration 是否开放注册(/user/register 与 /api/config 同源读取)
	AllowUserRegistration bool `json:"allowuserregistration"`
	// UserUploadSize 用户单次上传大小默认上限(字节,0 = 不限)
	UserUploadSize int64 `json:"useruploadsize"`
	// UserStorageQuota 用户存储配额默认值(字节,0 = 不限)
	UserStorageQuota int64 `json:"userstoragequota"`
	// SessionExpiryHours 会话时长(小时,0 = auth 包默认 7 天)
	SessionExpiryHours int `json:"sessionexpiryhours"`
}

UserSettings 管理后台"用户配置"标签页的在线设置。 语义:作为对应运行时消费点的系统级默认值(用户级覆盖仍然优先)。

func EffectiveUserSettings

func EffectiveUserSettings(ctx context.Context) UserSettings

EffectiveUserSettings 生效的用户设置:优先管理后台持久化值, 无记录时回退 yaml 全局配置。注册开关、配额默认值、会话时长的 运行时消费点统一走这里(修复管理端开关不生效)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL