diff --git a/main.go b/main.go index 0cea6336..12dd4bd4 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { log.Warn("检测到 auto_update.exe,即将自动退出当前程序并进行升级") log.Warn("程序目录下会出现“升级日志.log”,这代表升级正在进行中,如果失败了请检查此文件。") - err := CheckUpdater(diceManager) + err = CheckUpdater(diceManager) if err != nil { log.Error("升级程序检查失败: ", err.Error()) } else { @@ -353,7 +353,7 @@ func main() { } if doNext { - err := CheckUpdater(diceManager) + err = CheckUpdater(diceManager) if err != nil { log.Error("升级程序检查失败: ", err.Error()) } else { @@ -368,7 +368,7 @@ func main() { removeUpdateFiles() if opts.UpdateTest { - err := CheckUpdater(diceManager) + err = CheckUpdater(diceManager) if err != nil { log.Error("升级程序检查失败: ", err.Error()) } else { @@ -378,7 +378,7 @@ func main() { // 先临时放这里,后面再整理一下升级模块 diceManager.UpdateSealdiceByFile = func(packName string, log *log.Helper) bool { - err := CheckUpdater(diceManager) + err = CheckUpdater(diceManager) if err != nil { log.Error("升级程序检查失败: ", err.Error()) return false @@ -399,7 +399,8 @@ func main() { useBuiltinUI := false checkFrontendExists := func() bool { - stat, err := os.Stat("./frontend_overwrite") + var stat os.FileInfo + stat, err = os.Stat("./frontend_overwrite") return err == nil && stat.IsDir() } if !checkFrontendExists() { @@ -438,8 +439,11 @@ func main() { log.Fatalf("移除旧帮助文档时出错,%v", migrateErr) } // v150升级 - if !migrate.V150Upgrade() { - return + err = migrate.V150Upgrade() + if err != nil { + // Fatalf将会退出程序...或许应该用Errorf一类的吗? + log.Fatalf("您的146数据库可能存在问题,为保护数据,已经停止执行150升级命令。请尝试联系开发者,并提供你的日志。\n"+ + "数据已回滚,您可暂时使用旧版本等待进一步的修复和更新。您的报错内容为: %v", err) } if !opts.ShowConsole || opts.MultiInstanceOnWindows { diff --git a/migrate/v150_attrs.go b/migrate/v150_attrs.go index 8794e5e6..4c43324e 100644 --- a/migrate/v150_attrs.go +++ b/migrate/v150_attrs.go @@ -15,6 +15,7 @@ import ( "sealdice-core/dice" "sealdice-core/dice/model" "sealdice-core/utils" + log "sealdice-core/utils/kratos" ) func convertToNew(name string, ownerId string, data []byte, updatedAt int64) (*model.AttributesItemModel, error) { @@ -391,37 +392,10 @@ func checkTableExists(db *sqlx.DB, tableName string) (bool, error) { } } -func V150Upgrade() bool { - dbDataPath, _ := filepath.Abs("./data/default/data.db") - if _, err := os.Stat(dbDataPath); errors.Is(err, os.ErrNotExist) { - return true - } - - db, err := openDB(dbDataPath) - if err != nil { - fmt.Fprintln(os.Stdout, "升级失败,无法打开数据库:", err) - return false - } - defer func() { - _ = db.Close() - }() - - exists, err := checkTableExists(db, "attrs") - if err != nil { - fmt.Fprintln(os.Stdout, "V150数据转换未知错误:", err.Error()) - return false - } - if exists { - // 表格已经存在,说明转换完成,退出 - return true - } - - fmt.Fprintln(os.Stdout, "1.5 数据迁移") - sheetIdBindByGroupUserId = map[string]string{} - // Pinenutn: 2024-10-28 我要把这个注释全文背诵,它扰乱了GORM的初始化逻辑 - // -- 坏,Get这个方法太严格了,所有的字段都要有默认值,不然无法反序列化 - sqls := []string{ - ` +// Pinenutn: 2024-10-28 我要把这个注释全文背诵,它扰乱了GORM的初始化逻辑 +// -- 坏,Get这个方法太严格了,所有的字段都要有默认值,不然无法反序列化 +var v150sqls = []string{ + ` CREATE TABLE IF NOT EXISTS attrs ( id TEXT PRIMARY KEY, data BYTEA, @@ -435,63 +409,114 @@ CREATE TABLE IF NOT EXISTS attrs ( updated_at INTEGER default 0 ); `, - `create index if not exists idx_attrs_binding_sheet_id on attrs (binding_sheet_id);`, - `create index if not exists idx_attrs_owner_id_id on attrs (owner_id);`, - `create index if not exists idx_attrs_attrs_type_id on attrs (attrs_type);`, + `create index if not exists idx_attrs_binding_sheet_id on attrs (binding_sheet_id);`, + `create index if not exists idx_attrs_owner_id_id on attrs (owner_id);`, + `create index if not exists idx_attrs_attrs_type_id on attrs (attrs_type);`, +} + +func V150Upgrade() error { + dbDataPath, _ := filepath.Abs("./data/default/data.db") + if _, err := os.Stat(dbDataPath); errors.Is(err, os.ErrNotExist) { + return errors.New("未能查找到旧版本数据库") } - for _, i := range sqls { - _, _ = db.Exec(i) + + db, err := openDB(dbDataPath) + if err != nil { + return fmt.Errorf("升级失败,无法打开数据库: %w", err) } + defer db.Close() tx, err := db.Beginx() if err != nil { - fmt.Fprintln(os.Stdout, "V150数据转换创建事务失败:", err.Error()) - return false + return fmt.Errorf("创建事务失败: %w", err) + } + defer func() { + if p := recover(); p != nil { + err = tx.Rollback() + if err != nil { + log.Errorf("回滚事务时出错: %v", err) + } + panic(p) // 继续传播 panic + } else if err != nil { + log.Errorf("日志处理时出现异常行为: %v", err) + err = tx.Rollback() + if err != nil { + log.Errorf("回滚事务时出错: %v", err) + return + } + } else { + err = tx.Commit() + if err != nil { + log.Errorf("提交事务时出错: %v", err) + } + } + }() + + exists, err := checkTableExists(db, "attrs") + if err != nil { + return fmt.Errorf("检查表是否存在时出错: %w", err) } + // 特判146->150的倒霉蛋 + exists146, err := checkTableExists(db, "attrs_group") - if exists, _ := checkTableExists(db, "attrs_user"); exists { - count, countSheetsNum, countFailed, err2 := attrsUserMigrate(tx) - fmt.Fprintf(os.Stdout, "数据卡转换 - 角色卡,成功人数%d 失败人数 %d 卡数 %d\n", count, countFailed, countSheetsNum) - if err2 != nil { - fmt.Fprintln(os.Stdout, "异常", err2.Error()) - return false + if exists { + if exists146 { + log.Errorf("1.4.6的数据部分迁移!您可能是150部分版本的受害者,请联系开发者") + return errors.New("150和146的数据库共同存在,请联系开发者") } + // 表格已经存在,说明转换完成 + return nil } - if exists, _ := checkTableExists(db, "attrs_group_user"); exists { - count, countFailed, err2 := attrsGroupUserMigrate(tx) - fmt.Fprintf(os.Stdout, "数据卡转换 - 群组个人数据,成功%d 失败 %d\n", count, countFailed) - if err2 != nil { - fmt.Fprintln(os.Stdout, "异常", err2.Error()) - return false + log.Info("1.5 数据迁移") + sheetIdBindByGroupUserId = map[string]string{} + + for _, singleSql := range v150sqls { + if _, err = tx.Exec(singleSql); err != nil { + return fmt.Errorf("执行 SQL 出错: %w", err) } } - if exists, _ := checkTableExists(db, "attrs_group"); exists { + if exists, _ = checkTableExists(db, "attrs_user"); exists { + count, countSheetsNum, countFailed, err0 := attrsUserMigrate(tx) + log.Infof("数据卡转换 - 角色卡,成功人数%d 失败人数 %d 卡数 %d\n", count, countFailed, countSheetsNum) + if err0 != nil { + return fmt.Errorf("角色卡转换出错: %w", err0) + } + } + + if exists, _ = checkTableExists(db, "attrs_group_user"); exists { + count, countFailed, err1 := attrsGroupUserMigrate(tx) + log.Infof("数据卡转换 - 群组个人数据,成功%d 失败 %d\n", count, countFailed) + if err1 != nil { + return fmt.Errorf("群组个人数据转换出错: %w", err1) + } + } + + if exists, _ = checkTableExists(db, "attrs_group"); exists { count, countFailed, err2 := attrsGroupMigrate(tx) - fmt.Fprintf(os.Stdout, "数据卡转换 - 群数据,成功%d 失败 %d\n", count, countFailed) + log.Infof("数据卡转换 - 群数据,成功%d 失败 %d\n", count, countFailed) if err2 != nil { - fmt.Fprintln(os.Stdout, "异常", err2.Error()) - return false + return fmt.Errorf("群数据转换出错: %w", err2) } } - // 删档 - fmt.Fprintln(os.Stdout, "删除旧版本数据") - _, _ = tx.Exec("drop table attrs_group") - _, _ = tx.Exec("drop table attrs_group_user") - _, _ = tx.Exec("drop table attrs_user") + // 删除旧版本数据 + log.Info("删除旧版本数据") + deleteSQLs := []string{ + "drop table attrs_group", + "drop table attrs_group_user", + "drop table attrs_user", + } + for _, deleteSQL := range deleteSQLs { + if _, err = tx.Exec(deleteSQL); err != nil { + return fmt.Errorf("删除旧数据时出错: %w", err) + } + } + // 放在这里保证能执行 _, _ = db.Exec("PRAGMA wal_checkpoint(TRUNCATE);") - _, _ = tx.Exec("VACUUM;") // 收尾 - + _, _ = db.Exec("VACUUM;") sheetIdBindByGroupUserId = nil - - err = tx.Commit() - if err != nil { - fmt.Fprintln(os.Stdout, "V150 数据转换失败:", err.Error()) - return false - } - - fmt.Fprintln(os.Stdout, "V150 数据转换完成") - return true + log.Info("V150 数据转换完成") + return nil }