This commit is contained in:
2024-02-25 08:30:34 +08:00
commit 4947f39e74
273 changed files with 45396 additions and 0 deletions

99
pkg/crontab/collect.go Normal file
View File

@ -0,0 +1,99 @@
package crontab
import (
"context"
"os"
"path/filepath"
"strings"
"time"
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
)
func garbageCollect() {
// 清理打包下载产生的临时文件
collectArchiveFile()
// 清理过期的内置内存缓存
if store, ok := cache.Store.(*cache.MemoStore); ok {
collectCache(store)
}
util.Log().Info("Crontab job \"cron_garbage_collect\" complete.")
}
func collectArchiveFile() {
// 读取有效期、目录设置
tempPath := util.RelativePath(model.GetSettingByName("temp_path"))
expires := model.GetIntSetting("download_timeout", 30)
// 列出文件
root := filepath.Join(tempPath, "archive")
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err == nil && !info.IsDir() &&
strings.HasPrefix(filepath.Base(path), "archive_") &&
time.Now().Sub(info.ModTime()).Seconds() > float64(expires) {
util.Log().Debug("Delete expired batch download temp file %q.", path)
// 删除符合条件的文件
if err := os.Remove(path); err != nil {
util.Log().Debug("Failed to delete temp file %q: %s", path, err)
}
}
return nil
})
if err != nil {
util.Log().Debug("Crontab job cannot list temp batch download folder: %s", err)
}
}
func collectCache(store *cache.MemoStore) {
util.Log().Debug("Cleanup memory cache.")
store.GarbageCollect()
}
func uploadSessionCollect() {
placeholders := model.GetUploadPlaceholderFiles(0)
// 将过期的上传会话按照用户分组
userToFiles := make(map[uint][]uint)
for _, file := range placeholders {
_, sessionExist := cache.Get(filesystem.UploadSessionCachePrefix + *file.UploadSessionID)
if sessionExist {
continue
}
if _, ok := userToFiles[file.UserID]; !ok {
userToFiles[file.UserID] = make([]uint, 0)
}
userToFiles[file.UserID] = append(userToFiles[file.UserID], file.ID)
}
// 删除过期的会话
for uid, filesIDs := range userToFiles {
user, err := model.GetUserByID(uid)
if err != nil {
util.Log().Warning("Owner of the upload session cannot be found: %s", err)
continue
}
fs, err := filesystem.NewFileSystem(&user)
if err != nil {
util.Log().Warning("Failed to initialize filesystem: %s", err)
continue
}
if err = fs.Delete(context.Background(), []uint{}, filesIDs, false, false); err != nil {
util.Log().Warning("Failed to delete upload session: %s", err)
}
fs.Recycle()
}
util.Log().Info("Crontab job \"cron_recycle_upload_session\" complete.")
}

53
pkg/crontab/init.go Normal file
View File

@ -0,0 +1,53 @@
package crontab
import (
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
"github.com/robfig/cron/v3"
)
// Cron 定时任务
var Cron *cron.Cron
// Reload 重新启动定时任务
func Reload() {
if Cron != nil {
Cron.Stop()
}
Init()
}
// Init 初始化定时任务
func Init() {
util.Log().Info("Initialize crontab jobs...")
// 读取cron日程设置
options := model.GetSettingByNames(
"cron_garbage_collect",
"cron_notify_user",
"cron_ban_user",
"cron_recycle_upload_session",
)
Cron := cron.New()
for k, v := range options {
var handler func()
switch k {
case "cron_garbage_collect":
handler = garbageCollect
case "cron_notify_user":
handler = notifyExpiredVAS
case "cron_ban_user":
handler = banOverusedUser
case "cron_recycle_upload_session":
handler = uploadSessionCollect
default:
util.Log().Warning("Unknown crontab job type %q, skipping...", k)
continue
}
if _, err := Cron.AddFunc(v, handler); err != nil {
util.Log().Warning("Failed to start crontab job %q: %s", k, err)
}
}
Cron.Start()
}

83
pkg/crontab/vas.go Normal file
View File

@ -0,0 +1,83 @@
package crontab
import (
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/email"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
)
func notifyExpiredVAS() {
checkStoragePack()
checkUserGroup()
util.Log().Info("Crontab job \"cron_notify_user\" complete.")
}
// banOverusedUser 封禁超出宽容期的用户
func banOverusedUser() {
users := model.GetTolerantExpiredUser()
for _, user := range users {
// 清除最后通知日期标记
user.ClearNotified()
// 检查容量是否超额
if user.Storage > user.Group.MaxStorage+user.GetAvailablePackSize() {
// 封禁用户
user.SetStatus(model.OveruseBaned)
}
}
}
// checkUserGroup 检查已过期用户组
func checkUserGroup() {
users := model.GetGroupExpiredUsers()
for _, user := range users {
// 将用户回退到初始用户组
user.GroupFallback()
// 重新加载用户
user, _ = model.GetUserByID(user.ID)
// 检查容量是否超额
if user.Storage > user.Group.MaxStorage+user.GetAvailablePackSize() {
// 如果超额,则通知用户
sendNotification(&user, "用户组过期")
// 更新最后通知日期
user.Notified()
}
}
}
// checkStoragePack 检查已过期的容量包
func checkStoragePack() {
packs := model.GetExpiredStoragePack()
for _, pack := range packs {
// 删除过期的容量包
pack.Delete()
//找到所属用户
user, err := model.GetUserByID(pack.UserID)
if err != nil {
util.Log().Warning("Crontab job failed to get user info of [UID=%d]: %s", pack.UserID, err)
continue
}
// 检查容量是否超额
if user.Storage > user.Group.MaxStorage+user.GetAvailablePackSize() {
// 如果超额,则通知用户
sendNotification(&user, "容量包过期")
// 更新最后通知日期
user.Notified()
}
}
}
func sendNotification(user *model.User, reason string) {
title, body := email.NewOveruseNotification(user.Nick, reason)
if err := email.Send(user.Email, title, body); err != nil {
util.Log().Warning("Failed to send notification email: %s", err)
}
}