mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-06-26 09:41:31 +08:00
refactor: refactor task logic for better scalability (#76)
* refactor: a big refactor. wip * refactor: port handle file * refactor: place all handlers * fix: task info nil pointer * feat: enhance task progress tracking and context management * feat: cancel task * feat: stream mode * feat: silent mode * feat: dir cmd * refactor: remove unused old file * feat: rule cmd * feat: handle silent mode * feat: batch task * fix: batch task progress and temp file cleanup * refactor: update file creation and cleanup methods for better resource management * feat: add save command with silent mode handling * feat: message link * feat: update message prompts to include file count in storage selection * feat: slient save links * refactor: reduce dup code * feat: rule type * feat: chose dir * feat: refactor file handling and storage rules, improve error handling and logging * feat: rule mode * feat: telegraph pics * fix: tphpics nil pointer and inaccurate dirpath * feat: silent save telegraph * feat: add suffix to avoid file overwrite * feat: new storage telegram * chore: tidy go mod
This commit is contained in:
86
database/db.go
Normal file
86
database/db.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/krau/SaveAny-Bot/config"
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
"github.com/ncruces/go-sqlite3/gormlite"
|
||||
"gorm.io/gorm"
|
||||
glogger "gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func Init(ctx context.Context) {
|
||||
logger := log.FromContext(ctx)
|
||||
if err := os.MkdirAll(filepath.Dir(config.Cfg.DB.Path), 0755); err != nil {
|
||||
logger.Fatal("Failed to create data directory: ", err)
|
||||
}
|
||||
var err error
|
||||
db, err = gorm.Open(gormlite.Open(config.Cfg.DB.Path), &gorm.Config{
|
||||
Logger: glogger.New(logger, glogger.Config{
|
||||
Colorful: true,
|
||||
SlowThreshold: time.Second * 5,
|
||||
LogLevel: glogger.Error,
|
||||
IgnoreRecordNotFoundError: true,
|
||||
ParameterizedQueries: true,
|
||||
}),
|
||||
PrepareStmt: true,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("Failed to open database: ", err)
|
||||
}
|
||||
logger.Debug("Database connected")
|
||||
if err := db.AutoMigrate(&User{}, &Dir{}, &Rule{}); err != nil {
|
||||
logger.Fatal("迁移数据库失败, 如果您从旧版本升级, 建议手动删除数据库文件后重试: ", err)
|
||||
}
|
||||
if err := syncUsers(ctx); err != nil {
|
||||
logger.Fatal("Failed to sync users:", err)
|
||||
}
|
||||
logger.Debug("Database migrated")
|
||||
logger.Info("Database initialized")
|
||||
}
|
||||
|
||||
func syncUsers(ctx context.Context) error {
|
||||
logger := log.FromContext(ctx)
|
||||
dbUsers, err := GetAllUsers(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get users: %w", err)
|
||||
}
|
||||
|
||||
dbUserMap := make(map[int64]User)
|
||||
for _, u := range dbUsers {
|
||||
dbUserMap[u.ChatID] = u
|
||||
}
|
||||
|
||||
cfgUserMap := make(map[int64]struct{})
|
||||
for _, u := range config.Cfg.Users {
|
||||
cfgUserMap[u.ID] = struct{}{}
|
||||
}
|
||||
|
||||
for cfgID := range cfgUserMap {
|
||||
if _, exists := dbUserMap[cfgID]; !exists {
|
||||
if err := CreateUser(ctx, cfgID); err != nil {
|
||||
return fmt.Errorf("failed to create user %d: %w", cfgID, err)
|
||||
}
|
||||
logger.Infof("创建用户: %d", cfgID)
|
||||
}
|
||||
}
|
||||
|
||||
for dbID, dbUser := range dbUserMap {
|
||||
if _, exists := cfgUserMap[dbID]; !exists {
|
||||
if err := DeleteUser(ctx, &dbUser); err != nil {
|
||||
return fmt.Errorf("failed to delete user %d: %w", dbID, err)
|
||||
}
|
||||
logger.Infof("删除用户: %d", dbID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
57
database/dir.go
Normal file
57
database/dir.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package database
|
||||
|
||||
import "context"
|
||||
|
||||
func CreateDirForUser(ctx context.Context, userID uint, storageName, path string) error {
|
||||
dir := Dir{
|
||||
UserID: userID,
|
||||
StorageName: storageName,
|
||||
Path: path,
|
||||
}
|
||||
return db.WithContext(ctx).Create(&dir).Error
|
||||
}
|
||||
|
||||
func GetDirByID(ctx context.Context, id uint) (*Dir, error) {
|
||||
dir := &Dir{}
|
||||
err := db.WithContext(ctx).First(dir, id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dir, err
|
||||
}
|
||||
|
||||
func GetUserDirs(ctx context.Context, userID uint) ([]Dir, error) {
|
||||
var dirs []Dir
|
||||
err := db.WithContext(ctx).Where("user_id = ?", userID).Find(&dirs).Error
|
||||
return dirs, err
|
||||
}
|
||||
|
||||
func GetUserDirsByChatID(ctx context.Context, chatID int64) ([]Dir, error) {
|
||||
user, err := GetUserByChatID(ctx, chatID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetUserDirs(ctx, user.ID)
|
||||
}
|
||||
|
||||
func GetDirsByUserIDAndStorageName(ctx context.Context, userID uint, storageName string) ([]Dir, error) {
|
||||
var dirs []Dir
|
||||
err := db.WithContext(ctx).Where("user_id = ? AND storage_name = ?", userID, storageName).Find(&dirs).Error
|
||||
return dirs, err
|
||||
}
|
||||
|
||||
func GetDirsByUserChatIDAndStorageName(ctx context.Context, chatID int64, storageName string) ([]Dir, error) {
|
||||
user, err := GetUserByChatID(ctx, chatID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetDirsByUserIDAndStorageName(ctx, user.ID, storageName)
|
||||
}
|
||||
|
||||
func DeleteDirForUser(ctx context.Context, userID uint, storageName, path string) error {
|
||||
return db.WithContext(ctx).Unscoped().Where("user_id = ? AND storage_name = ? AND path = ?", userID, storageName, path).Delete(&Dir{}).Error
|
||||
}
|
||||
|
||||
func DeleteDirByID(ctx context.Context, id uint) error {
|
||||
return db.WithContext(ctx).Unscoped().Delete(&Dir{}, id).Error
|
||||
}
|
||||
31
database/model.go
Normal file
31
database/model.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
ChatID int64 `gorm:"uniqueIndex;not null"`
|
||||
Silent bool
|
||||
DefaultStorage string
|
||||
Dirs []Dir
|
||||
ApplyRule bool
|
||||
Rules []Rule
|
||||
}
|
||||
|
||||
type Dir struct {
|
||||
gorm.Model
|
||||
UserID uint
|
||||
StorageName string
|
||||
Path string
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
gorm.Model
|
||||
UserID uint
|
||||
Type string
|
||||
Data string
|
||||
StorageName string
|
||||
DirPath string
|
||||
}
|
||||
24
database/rule.go
Normal file
24
database/rule.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package database
|
||||
|
||||
import "context"
|
||||
|
||||
func CreateRule(ctx context.Context, rule *Rule) error {
|
||||
return db.WithContext(ctx).Create(rule).Error
|
||||
}
|
||||
|
||||
func DeleteRule(ctx context.Context, ruleID uint) error {
|
||||
return db.WithContext(ctx).Unscoped().Delete(&Rule{}, ruleID).Error
|
||||
}
|
||||
|
||||
func UpdateUserApplyRule(ctx context.Context, chatID int64, applyRule bool) error {
|
||||
return db.WithContext(ctx).Model(&User{}).Where("chat_id = ?", chatID).Update("apply_rule", applyRule).Error
|
||||
}
|
||||
|
||||
func GetRulesByUserChatID(ctx context.Context, chatID int64) ([]Rule, error) {
|
||||
var rules []Rule
|
||||
err := db.WithContext(ctx).Where("user_id = (SELECT id FROM users WHERE chat_id = ?)", chatID).Find(&rules).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
40
database/user.go
Normal file
40
database/user.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package database
|
||||
|
||||
import "context"
|
||||
|
||||
func CreateUser(ctx context.Context, chatID int64) error {
|
||||
if _, err := GetUserByChatID(ctx, chatID); err == nil {
|
||||
return nil
|
||||
}
|
||||
return db.Create(&User{ChatID: chatID}).Error
|
||||
}
|
||||
|
||||
func GetAllUsers(ctx context.Context) ([]User, error) {
|
||||
var users []User
|
||||
err := db.Preload("Dirs").
|
||||
WithContext(ctx).
|
||||
Preload("Rules").
|
||||
Find(&users).Error
|
||||
return users, err
|
||||
}
|
||||
|
||||
func GetUserByChatID(ctx context.Context, chatID int64) (*User, error) {
|
||||
var user User
|
||||
err := db.
|
||||
Preload("Dirs").
|
||||
WithContext(ctx).
|
||||
Preload("Rules").
|
||||
Where("chat_id = ?", chatID).First(&user).Error
|
||||
return &user, err
|
||||
}
|
||||
|
||||
func UpdateUser(ctx context.Context, user *User) error {
|
||||
if _, err := GetUserByChatID(ctx, user.ChatID); err != nil {
|
||||
return err
|
||||
}
|
||||
return db.WithContext(ctx).Save(user).Error
|
||||
}
|
||||
|
||||
func DeleteUser(ctx context.Context, user *User) error {
|
||||
return db.WithContext(ctx).Unscoped().Select("Dirs", "Rules").Delete(user).Error
|
||||
}
|
||||
Reference in New Issue
Block a user