config

package
v0.33.3 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 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"`

	// 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