Documentation
¶
Overview ¶
janitor.go 存储对账与日志保留(治理 2026-10-03)。
此前代码注释多次声称"孤儿文件由清理任务兜底"但该任务并不存在: 物理文件在 DB 无引用(写库失败/分片中断/老 bug 遗留)时永不回收。 本文件补上两个低频后台任务:
- ReconcileOrphans:物理文件 vs DB 引用差集清理。local 后端真删除; 远端后端(s3/webdav/多云)只统计报告不删除(远端误删代价不对称, 且全量 List 成本高,等真实需求出现再做远端对账)。
- CleanupLogs:transfer_log / admin_operation_log 按保留天数清理 (此前审计表无限膨胀)。
Index ¶
- func Audit(ctx context.Context, action, target string, success bool)
- type AdminStats
- type EnhancedStats
- type FederationNotifier
- type Janitor
- func (j *Janitor) CleanRemotePresignOrphans(ctx context.Context, olderThan time.Duration) (int, error)
- func (j *Janitor) CleanupLogs(ctx context.Context) (int64, error)
- func (j *Janitor) CleanupStaleUploads(ctx context.Context, maxAge time.Duration) (dirsRemoved int, err error)
- func (j *Janitor) CountRemotePresignOrphans(ctx context.Context, olderThan time.Duration) (int, error)
- func (j *Janitor) ReconcileOrphans(ctx context.Context) (int, int, error)
- func (j *Janitor) ScanRemotePresignOrphans(ctx context.Context, olderThan time.Duration) ([]string, error)
- type LogEntry
- type ReconfigureHooks
- type Service
- func (s *Service) BatchDeleteFiles(ctx context.Context, ids []uint) (int, error)
- func (s *Service) BatchExtendFiles(ctx context.Context, ids []uint, expireAt time.Time) (int, error)
- func (s *Service) ChildFileCounts(ctx context.Context, ids []uint) map[uint]int64
- func (s *Service) CleanExpiredFiles(ctx context.Context) (int64, int64, error)
- func (s *Service) CleanTempFiles(ctx context.Context) (int64, int64, error)
- func (s *Service) CleanupExpiredFiles(ctx context.Context) (int, error)
- func (s *Service) CleanupIncompleteUploads(ctx context.Context, olderThanHours int) (int, error)
- func (s *Service) DeleteFile(ctx context.Context, fileID uint) error
- func (s *Service) DeleteUser(ctx context.Context, userID uint) error
- func (s *Service) EnhancedStats(ctx context.Context) (*EnhancedStats, error)
- func (s *Service) GenerateTokenForAdmin(ctx context.Context, username, password string) (string, error)
- func (s *Service) GetConfig(ctx context.Context) (*SystemConfig, error)
- func (s *Service) GetFileByCode(ctx context.Context, code string) (*model.FileCode, error)
- func (s *Service) GetFileByID(ctx context.Context, id uint) (*model.FileCode, error)
- func (s *Service) GetFileDetail(ctx context.Context, id uint) (*model.FileCode, []*model.FileCodeFile, error)
- func (s *Service) GetFiles(ctx context.Context, page, pageSize int, search string) ([]*model.FileCode, int64, error)
- func (s *Service) GetFilesFiltered(ctx context.Context, q model.FileCodeQuery) ([]*model.FileCode, int64, error)
- func (s *Service) GetStats(ctx context.Context) (*AdminStats, error)
- func (s *Service) GetStorageStatus(ctx context.Context) (*StorageStatus, error)
- func (s *Service) GetSystemInfo(ctx context.Context) (*SystemInfo, error)
- func (s *Service) GetSystemLogs(ctx context.Context, level string, page, pageSize int) ([]*LogEntry, int64, error)
- func (s *Service) GetTransferLogs(ctx context.Context, query model.TransferLogQuery) ([]*model.TransferLog, int64, error)
- func (s *Service) GetUsers(ctx context.Context, page, pageSize int) ([]*model.UserResp, int64, error)
- func (s *Service) InvalidateRuntimeConfig()
- func (s *Service) ListUsersFiltered(ctx context.Context, f UserListFilter) ([]*model.UserResp, int64, error)
- func (s *Service) LoadRuntimeStorage(ctx context.Context) *conf.StorageConfig
- func (s *Service) OptimizeDatabase(ctx context.Context) (string, string, error)
- func (s *Service) PurgeFiles(ctx context.Context, ids []uint) (int64, error)
- func (s *Service) ResetUserPassword(ctx context.Context, userID uint, passwordHash string) error
- func (s *Service) RestoreAdminSettings()
- func (s *Service) RestoreFiles(ctx context.Context, ids []uint) (int64, error)
- func (s *Service) SaveRuntimeStorage(ctx context.Context, cfg *conf.StorageConfig) error
- func (s *Service) SetConfig(config *SystemConfig)
- func (s *Service) SetFederationNotifier(f FederationNotifier)
- func (s *Service) SetFilesStatus(ctx context.Context, ids []uint, status string) (int64, error)
- func (s *Service) SetOnConfigPersisted(fn func())
- func (s *Service) SetReconfigureHooks(h *ReconfigureHooks)
- func (s *Service) SetStorage(st storage.StorageInterface)
- func (s *Service) TrendSeries(ctx context.Context, days int) ([]TrendDay, error)
- func (s *Service) UpdateConfig(ctx context.Context, newConfig *SystemConfig) error
- func (s *Service) UpdateFileExpire(ctx context.Context, id uint, expireAt *time.Time, expiredCount *int) error
- func (s *Service) UpdateUserSettings(ctx context.Context, u UserSettings) error
- func (s *Service) UpdateUserStatus(ctx context.Context, userID uint, status string) error
- type StorageProvider
- type StorageStatus
- type SystemConfig
- type SystemInfo
- type TrendDay
- type UserListFilter
- type UserSettings
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type AdminStats ¶
type AdminStats struct {
TotalUsers int64 `json:"total_users"`
TotalFiles int64 `json:"total_files"`
TotalSize int64 `json:"total_size"`
TodayUploads int64 `json:"today_uploads"`
TodayDownloads int64 `json:"today_downloads"`
ExpiredFiles int64 `json:"expired_files"`
AnonymousFiles int64 `json:"anonymous_files"`
UserFiles int64 `json:"user_files"`
// 文件健康洞察维度(2026-10-07;IDL AdminStatsData 同步暴露)
ActiveFiles int64 `json:"active_files"`
ExpiringSoonFiles int64 `json:"expiring_soon_files"`
NeverPickedFiles int64 `json:"never_picked_files"`
ForeverFiles int64 `json:"forever_files"`
}
type EnhancedStats ¶
type EnhancedStats struct {
TodayUploads int64 `json:"today_uploads"`
YesterdayUploads int64 `json:"yesterday_uploads"`
TotalDownloads int64 `json:"total_downloads"`
ExpiredFiles int64 `json:"expired_files"`
AnonymousFiles int64 `json:"anonymous_files"`
PresignFiles int64 `json:"presign_files"`
TopSuffixes []*dao.SuffixStat `json:"top_suffixes"`
// 站点级存储配额(storage.quota,0=不限)与当前用量(存活 file_codes 合计)
StorageUsed int64 `json:"storage_used"`
StorageQuota int64 `json:"storage_quota"`
}
EnhancedStats Dashboard 富指标(昨日对比/下载总量/类型分布)。
type FederationNotifier ¶
type FederationNotifier interface {
}
FederationNotifier P2P 联邦撤销钩子(窄接口,实现在 app/federation; bootstrap 注入。admin 删除路径独立于 share 域,须单独挂钩——否则管理端 删除的分享在联邦里残留到公告 TTL 过期)。
type Janitor ¶
type Janitor struct {
// contains filtered or unexported fields
}
Janitor 存储对账 + 日志保留。svc 为 nil 或非 local 时对账自动跳过。
func NewJanitor ¶
func NewJanitor(svc StorageProvider, retentionDays int) *Janitor
NewJanitor 创建 janitor。
func (*Janitor) CleanRemotePresignOrphans ¶
func (j *Janitor) CleanRemotePresignOrphans(ctx context.Context, olderThan time.Duration) (int, error)
CleanRemotePresignOrphans 清理远端后端的 presign 孤儿对象: Init 后未 Complete 的直传残留(对象 key 形如 uploads/日期/up_<uuid>.ext, basename up_ 前缀与普通上传的 uuid 名可区分),无 DB 引用且超过宽限期的删除。 远端后端此前完全不对账(ReconcileOrphans 对远端只报告),孤儿只增不减—— 且匿名 presign Init 可被滥用为免费网盘(2026-10-06 审计确认),此方法为其兜底。 本地后端不适用(ReconcileOrphans 磁盘对账已覆盖)。
func (*Janitor) CleanupLogs ¶
CleanupLogs 按保留天数清理传输日志与审计日志。返回删除行数。
func (*Janitor) CleanupStaleUploads ¶
func (j *Janitor) CleanupStaleUploads(ctx context.Context, maxAge time.Duration) (dirsRemoved int, err error)
CleanupStaleUploads 清理弃管的分片会话(治理 2026-10-03): init 后永不 complete 的会话此前永久滞留(目录 + DB 行),且唯一的 手动清理在非 SQLite 库上直接 SQL 报错。incomplete 超龄 → 删目录 + 删行; 已完成会话旧行单独清理(防 upload_chunks 表无限膨胀)。
func (*Janitor) CountRemotePresignOrphans ¶ added in v0.14.9
func (j *Janitor) CountRemotePresignOrphans(ctx context.Context, olderThan time.Duration) (int, error)
CountRemotePresignOrphans 只读统计:当前满足清理判定的 presign 孤儿数 (存储洞察 /admin/storage/insights 用,不删除任何对象)。
func (*Janitor) ReconcileOrphans ¶
ReconcileOrphans 物理文件对账。返回 (扫描文件数, 清理文件数, error)。
func (*Janitor) ScanRemotePresignOrphans ¶ added in v0.14.9
func (j *Janitor) ScanRemotePresignOrphans(ctx context.Context, olderThan time.Duration) ([]string, error)
ScanRemotePresignOrphans 列举满足清理判定的远端 presign 孤儿对象 key(只读): up_ 前缀 + 无 DB 引用 + 超过 olderThan 宽限期。本地后端返回空集 (磁盘对账 ReconcileOrphans 已覆盖,无 presign 孤儿语义)。
type LogEntry ¶
type LogEntry struct {
ID uint64 `json:"id"`
Level string `json:"level"`
Message string `json:"message"`
CreatedAt string `json:"created_at"`
Module string `json:"module"`
UserID string `json:"user_id"`
}
LogEntry 日志条目
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)
}
ReconfigureHooks 存储域之外的组件热重建钩子(bootstrap 注册;SMTP mailer / OIDC service)。 参数为合并后的新段;nil 段表示维持现状。
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func Default ¶
func Default() *Service
Default 全站共享的 admin Service 实例。 system_configs 是"单行 JSON 读改写"语义,必须全站单实例: 多实例各自缓存内存副本会互相覆盖(用户设置写入后公共配置读旧值的 2026-10-03 事故即由此而来)。
func NewService ¶
func NewService() *Service
func (*Service) BatchDeleteFiles ¶
BatchDeleteFiles 批量删除:DB 软删 + 物理文件清理(best-effort,失败不阻断, 孤儿由 janitor 对账)。返回受影响行数。
func (*Service) BatchExtendFiles ¶
func (s *Service) BatchExtendFiles(ctx context.Context, ids []uint, expireAt time.Time) (int, error)
BatchExtendFiles 管理端跨用户批量延期。
func (*Service) ChildFileCounts ¶
ChildFileCounts 批量取子文件数(一次 GROUP BY;失败返回 nil 由调用方降级为 0)。
func (*Service) CleanExpiredFiles ¶
CleanExpiredFiles 清理过期文件(DB 记录 + 物理文件)。 物理删除失败不阻断 DB 删除(记日志);DB 删除失败不阻断(下轮重试)。
func (*Service) CleanTempFiles ¶
CleanTempFiles 清理临时文件
func (*Service) CleanupExpiredFiles ¶
CleanupExpiredFiles 清理过期文件
func (*Service) CleanupIncompleteUploads ¶
CleanupIncompleteUploads 清理未完成的上传
func (*Service) DeleteFile ¶
DeleteFile 删除文件(DB 记录 + 物理文件;此前物理删除被注释,造成存储泄漏)
func (*Service) DeleteUser ¶
DeleteUser 删除用户(级联软删其全部分享记录;此前"先删用户文件"逻辑被注释)
func (*Service) EnhancedStats ¶
func (s *Service) EnhancedStats(ctx context.Context) (*EnhancedStats, error)
EnhancedStats 汇总富指标。单项统计失败按 0 降级(与历史 handler 行为一致)。
func (*Service) GenerateTokenForAdmin ¶
func (s *Service) GenerateTokenForAdmin(ctx context.Context, username, password string) (string, error)
GenerateTokenForAdmin 生成管理员登录 token
func (*Service) GetConfig ¶
func (s *Service) GetConfig(ctx context.Context) (*SystemConfig, error)
GetConfig 获取系统配置(首次调用会从 DB 加载管理后台保存的配置)
func (*Service) GetFileByCode ¶
GetFileByCode 按取件码获取文件
func (*Service) GetFileByID ¶
GetFileByID 按主键取分享记录(管理端详情/下载重定向)。
func (*Service) GetFileDetail ¶
func (s *Service) GetFileDetail(ctx context.Context, id uint) (*model.FileCode, []*model.FileCodeFile, error)
GetFileDetail 文件详情:主记录 + 子文件行(旧单文件分享无子行由调用方回退主表合成)。
func (*Service) GetFiles ¶
func (s *Service) GetFiles(ctx context.Context, page, pageSize int, search string) ([]*model.FileCode, int64, error)
GetFiles 获取文件列表
func (*Service) GetFilesFiltered ¶
func (s *Service) GetFilesFiltered(ctx context.Context, q model.FileCodeQuery) ([]*model.FileCode, int64, error)
GetFilesFiltered 管理端文件列表组合过滤(治理 2026-10-03: keyword/user/upload_type/owner_ip/status/大小/时间/过期,供 /admin/files/filter)。
func (*Service) GetStats ¶
func (s *Service) GetStats(ctx context.Context) (*AdminStats, error)
GetStats 获取管理员统计信息
func (*Service) GetStorageStatus ¶
func (s *Service) GetStorageStatus(ctx context.Context) (*StorageStatus, error)
GetStorageStatus 获取存储状态
func (*Service) GetSystemInfo ¶
func (s *Service) GetSystemInfo(ctx context.Context) (*SystemInfo, error)
GetSystemInfo 获取系统信息
func (*Service) GetSystemLogs ¶
func (s *Service) GetSystemLogs(ctx context.Context, level string, page, pageSize int) ([]*LogEntry, int64, error)
GetSystemLogs 获取系统日志
func (*Service) GetTransferLogs ¶
func (s *Service) GetTransferLogs(ctx context.Context, query model.TransferLogQuery) ([]*model.TransferLog, int64, error)
GetTransferLogs 获取传输日志
func (*Service) GetUsers ¶
func (s *Service) GetUsers(ctx context.Context, page, pageSize int) ([]*model.UserResp, int64, error)
GetUsers 获取用户列表
func (*Service) InvalidateRuntimeConfig ¶
func (s *Service) InvalidateRuntimeConfig()
InvalidateRuntimeConfig 丢弃内存配置缓存(仅影响缓存,不写库)。 多副本:public 副本收到管理端变更广播后调用,下次 GetConfig 重读 DB—— 单机 standalone 不调用(保持既有"进程内即真相"语义)。
func (*Service) ListUsersFiltered ¶
func (s *Service) ListUsersFiltered(ctx context.Context, f UserListFilter) ([]*model.UserResp, int64, error)
ListUsersFiltered 带筛选的用户列表(keyword/status/role + 分页)。
func (*Service) LoadRuntimeStorage ¶
func (s *Service) LoadRuntimeStorage(ctx context.Context) *conf.StorageConfig
LoadRuntimeStorage 读取持久化的运行时存储配置(storage.RuntimePersister 实现)。 无记录/未设置返回 nil;DB 不可用返回 nil(与配置加载的降级策略一致)。
func (*Service) OptimizeDatabase ¶
OptimizeDatabase 数据库优化(维护工具「优化数据库」)。 sqlite:VACUUM 回收空间 + ANALYZE 刷新统计(此前前端按钮调用的是 后端从未实现的 /admin/maintenance/optimize,恒 404——2026-10-06 补齐); mysql:ANALYZE 核心表;postgres:VACUUM ANALYZE;其他后端 no-op。 返回 (实际优化的驱动, 执行说明)。
func (*Service) PurgeFiles ¶
PurgeFiles 彻底删除(回收站 → 物理删除):DB 行硬删 + COS/本地对象删除。 对象删除失败不阻断 DB 硬删(孤儿由桶生命周期/对账兜底);返回成功数。
func (*Service) ResetUserPassword ¶
ResetUserPassword 管理员重置用户密码(写入已哈希口令)。
func (*Service) RestoreAdminSettings ¶
func (s *Service) RestoreAdminSettings()
RestoreAdminSettings 启动时把持久化的新段 overlay 回全局 conf(DB 先于服务启动就绪)。 由 bootstrap 在 restoreRuntimeStorage 同相位调用。
func (*Service) RestoreFiles ¶
RestoreFiles 从回收站恢复(软删 → 存活):deleted_at 置空,COS 对象未动无需处理。 仅恢复"当前处于软删态"的 id,忽略其余;返回实际恢复数。
func (*Service) SaveRuntimeStorage ¶
SaveRuntimeStorage 持久化运行时存储配置(storage.RuntimePersister 实现)。 读改写单行 JSON,只更新 runtime_storage 段;DB 不可用时返回错误, 由调用方(存储域)决定提示语义——切换已生效,仅持久化失败。
func (*Service) SetConfig ¶
func (s *Service) SetConfig(config *SystemConfig)
SetConfig 设置配置(显式注入优先于 DB 持久化配置)
func (*Service) SetFederationNotifier ¶
func (s *Service) SetFederationNotifier(f FederationNotifier)
SetFederationNotifier 注入联邦撤销钩子(bootstrap 调用;nil = 非联邦)
func (*Service) SetFilesStatus ¶
SetFilesStatus 管理员设置分享管控状态(单个/批量禁用、恢复共用)。 返回受影响行数;审计按动作分别落账(file.block / file.unblock / file.status)。
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)
func (*Service) SetStorage ¶
func (s *Service) SetStorage(st storage.StorageInterface)
SetStorage 注入存储服务(用于过期清理删物理文件)
func (*Service) TrendSeries ¶
TrendSeries 连续 N 天的上传/下载趋势(缺失日补 0)。下载日志查询失败不阻断 (表可能尚无数据/旧库未建)——降级为全 0 序列。
func (*Service) UpdateConfig ¶
func (s *Service) UpdateConfig(ctx context.Context, newConfig *SystemConfig) error
UpdateConfig 更新系统配置:写穿到 DB(单行),成功后才更新内存。 防御性合并:handler 会从请求重建 SystemConfig,请求不含 runtime_storage (存储域维护的运行时段),为 nil 时保留旧值,避免保存站点配置时被冲掉。
func (*Service) UpdateFileExpire ¶
func (s *Service) UpdateFileExpire(ctx context.Context, id uint, expireAt *time.Time, expiredCount *int) error
UpdateFileExpire 编辑文件(延期 / 改剩余次数)。
func (*Service) UpdateUserSettings ¶
func (s *Service) UpdateUserSettings(ctx context.Context, u UserSettings) error
UpdateUserSettings 在线更新"用户配置"段:读改写当前配置,仅替换 User, 其余段保持不变;写穿 DB 并即时应用副作用(会话时长)。
type StorageProvider ¶
type StorageProvider interface {
storage.StorageInterface
EffectiveType() storage.StorageType
DataPath() string
// ListRemoteObjects 远端对象列举(presign 孤儿清理;本地后端返回错误)。
ListRemoteObjects(ctx context.Context, prefix string) ([]storage.RemoteObjectInfo, error)
}
StorageProvider janitor 所需存储能力:通用操作 + 本地后端判定/根目录。 EffectiveType/DataPath 是 *storage.StorageService 的扩展能力(不在 StorageInterface 内),按消费侧窄接口收窄依赖,bootstrap 传具体实现即可。
type StorageStatus ¶
type StorageStatus struct {
StorageType string `json:"storage_type"`
TotalSpace int64 `json:"total_space"`
UsedSpace int64 `json:"used_space"`
FreeSpace int64 `json:"free_space"`
FileCount int64 `json:"file_count"`
UsagePercent float64 `json:"usage_percent"`
}
StorageStatus 存储状态
type SystemConfig ¶
type SystemConfig struct {
Base struct {
Name string `json:"name"`
Description string `json:"description"`
Port int `json:"port"`
} `json:"base"`
Storage struct {
Type string `json:"type"`
MaxSize int64 `json:"max_size"`
} `json:"storage"`
Transfer struct {
MaxCount int `json:"max_count"`
ExpireDefault int `json:"expire_default"`
} `json:"transfer"`
// 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"`
}
type SystemInfo ¶
type SystemInfo struct {
Version string `json:"version"`
OS string `json:"os"`
Arch string `json:"arch"`
Uptime string `json:"uptime"`
Goroutines int64 `json:"goroutines"`
MemoryAlloc int64 `json:"memory_alloc"`
MemoryTotal int64 `json:"memory_total"`
MemorySys int64 `json:"memory_sys"`
}
SystemInfo 系统信息
type TrendDay ¶
type TrendDay struct {
Date string `json:"date"`
Uploads int64 `json:"uploads"`
Downloads int64 `json:"downloads"`
}
TrendDay 趋势序列单日点。
type UserListFilter ¶
UserListFilter 带筛选的用户列表条件(管理端用户管理)。
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 全局配置。注册开关、配额默认值、会话时长的 运行时消费点统一走这里(修复管理端开关不生效)。