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

admin

package
v0.15.0 Latest Latest
Warning

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

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

Documentation

Overview

janitor.go 存储对账与日志保留(治理 2026-10-03)。

此前代码注释多次声称"孤儿文件由清理任务兜底"但该任务并不存在: 物理文件在 DB 无引用(写库失败/分片中断/老 bug 遗留)时永不回收。 本文件补上两个低频后台任务:

  • ReconcileOrphans:物理文件 vs DB 引用差集清理。local 后端真删除; 远端后端(s3/webdav/多云)只统计报告不删除(远端误删代价不对称, 且全量 List 成本高,等真实需求出现再做远端对账)。
  • CleanupLogs:transfer_log / admin_operation_log 按保留天数清理 (此前审计表无限膨胀)。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Audit

func Audit(ctx context.Context, action, target string, success bool)

Audit 管理端操作审计的统一入口(transport 侧审计写入收口到此,消除与 service 层的孪生实现;经全站唯一 Default() 实例落库)。

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 {
	ShareDeleted(code string)
}

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

func (j *Janitor) CleanupLogs(ctx context.Context) (int64, error)

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

func (j *Janitor) ReconcileOrphans(ctx context.Context) (int, int, error)

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

func (s *Service) BatchDeleteFiles(ctx context.Context, ids []uint) (int, error)

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

func (s *Service) ChildFileCounts(ctx context.Context, ids []uint) map[uint]int64

ChildFileCounts 批量取子文件数(一次 GROUP BY;失败返回 nil 由调用方降级为 0)。

func (*Service) CleanExpiredFiles

func (s *Service) CleanExpiredFiles(ctx context.Context) (int64, int64, error)

CleanExpiredFiles 清理过期文件(DB 记录 + 物理文件)。 物理删除失败不阻断 DB 删除(记日志);DB 删除失败不阻断(下轮重试)。

func (*Service) CleanTempFiles

func (s *Service) CleanTempFiles(ctx context.Context) (int64, int64, error)

CleanTempFiles 清理临时文件

func (*Service) CleanupExpiredFiles

func (s *Service) CleanupExpiredFiles(ctx context.Context) (int, error)

CleanupExpiredFiles 清理过期文件

func (*Service) CleanupIncompleteUploads

func (s *Service) CleanupIncompleteUploads(ctx context.Context, olderThanHours int) (int, error)

CleanupIncompleteUploads 清理未完成的上传

func (*Service) DeleteFile

func (s *Service) DeleteFile(ctx context.Context, fileID uint) error

DeleteFile 删除文件(DB 记录 + 物理文件;此前物理删除被注释,造成存储泄漏)

func (*Service) DeleteUser

func (s *Service) DeleteUser(ctx context.Context, userID uint) error

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

func (s *Service) GetFileByCode(ctx context.Context, code string) (*model.FileCode, error)

GetFileByCode 按取件码获取文件

func (*Service) GetFileByID

func (s *Service) GetFileByID(ctx context.Context, id uint) (*model.FileCode, error)

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

func (s *Service) OptimizeDatabase(ctx context.Context) (string, string, error)

OptimizeDatabase 数据库优化(维护工具「优化数据库」)。 sqlite:VACUUM 回收空间 + ANALYZE 刷新统计(此前前端按钮调用的是 后端从未实现的 /admin/maintenance/optimize,恒 404——2026-10-06 补齐); mysql:ANALYZE 核心表;postgres:VACUUM ANALYZE;其他后端 no-op。 返回 (实际优化的驱动, 执行说明)。

func (*Service) PurgeFiles

func (s *Service) PurgeFiles(ctx context.Context, ids []uint) (int64, error)

PurgeFiles 彻底删除(回收站 → 物理删除):DB 行硬删 + COS/本地对象删除。 对象删除失败不阻断 DB 硬删(孤儿由桶生命周期/对账兜底);返回成功数。

func (*Service) ResetUserPassword

func (s *Service) ResetUserPassword(ctx context.Context, userID uint, passwordHash string) error

ResetUserPassword 管理员重置用户密码(写入已哈希口令)。

func (*Service) RestoreAdminSettings

func (s *Service) RestoreAdminSettings()

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

func (*Service) RestoreFiles

func (s *Service) RestoreFiles(ctx context.Context, ids []uint) (int64, error)

RestoreFiles 从回收站恢复(软删 → 存活):deleted_at 置空,COS 对象未动无需处理。 仅恢复"当前处于软删态"的 id,忽略其余;返回实际恢复数。

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) SetFederationNotifier

func (s *Service) SetFederationNotifier(f FederationNotifier)

SetFederationNotifier 注入联邦撤销钩子(bootstrap 调用;nil = 非联邦)

func (*Service) SetFilesStatus

func (s *Service) SetFilesStatus(ctx context.Context, ids []uint, status string) (int64, error)

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

func (s *Service) TrendSeries(ctx context.Context, days int) ([]TrendDay, error)

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 并即时应用副作用(会话时长)。

func (*Service) UpdateUserStatus

func (s *Service) UpdateUserStatus(ctx context.Context, userID uint, status string) error

UpdateUserStatus 更新用户状态

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

type UserListFilter struct {
	Keyword  string
	Status   string
	Role     string
	Page     int
	PageSize int
}

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 全局配置。注册开关、配额默认值、会话时长的 运行时消费点统一走这里(修复管理端开关不生效)。

Jump to

Keyboard shortcuts

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