package main import ( "bytes" "context" "encoding/json" "fmt" "github.com/go-redis/redis/v8" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" "log" "os" "os/exec" "strconv" "strings" "time" ) const redisAdress = "test.taoyuanjilogin.com:4114" const redisPass = "peach" const linkAccount = "mongodb://peach:peach@test.taoyuanjilogin.com:4113/PeachValley4" const link = "mongodb://127.0.0.1:21017/PeachValley" const hasAccount = true func main() { //fmt.Println("参数: ", len(os.Args)) var model string fmt.Print("下载账号数据输入 1 , 替换账号数据输入 2 : ") _, err := fmt.Scan(&model) // 读取输入并赋值给变量 if err != nil { fmt.Println("输入错误:", err) return } ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: redisAdress, DialTimeout: 10 * time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, PoolSize: 10, PoolTimeout: 30 * time.Second, Password: redisPass, }) if model == "1" { fmt.Printf("%s准备下载账号信息: \n", model) copyUnit(ctx, rdb) } else { fmt.Printf("%s准备替换账号信息: \n", model) updateUnit(ctx, rdb) } ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() fmt.Println("操作完成... (输入 'ctrl-c' 退出)") for { select { case <-ticker.C: // 这里可以添加条件检查(如读取文件、网络请求等) default: // 非阻塞检查用户输入(需配合 goroutine) } } } func copyUnit(ctx context.Context, rdb *redis.Client) { var destUid string fmt.Print("输入需要下载的UniqueId: ") _, err := fmt.Scan(&destUid) // 读取输入并赋值给变量 if err != nil { fmt.Println("输入错误:", err) return } int64Uid, _ := strconv.ParseInt(destUid, 10, 64) fmt.Printf("准备下载账号: %s\n", destUid) rdb.Do(ctx, "select", 0) destId, err := rdb.HGet(ctx, "public_id_for_uid", fmt.Sprint(destUid)).Result() if err != nil { fmt.Println("redis打开失败 无法搜索 _id, err", err) fmt.Println("尝试通过数据库查查找账号_id。") destFileName := "DestUnit" + destUid + ".json" if hasAccount { mongoexportCommand(ctx, destFileName, "Unit", int64Uid, linkAccount, 1) } else { mongoexportCommand(ctx, destFileName, "Unit", int64Uid, link, 1) } time.Sleep(5 * time.Second) destId, _ = writeDestFile(destFileName) if destId == "" { fmt.Println("未找到需要下载的账号_id") fmt.Print("请手动输入需要下载的账号_id: ") _, err = fmt.Scan(&destId) // 读取输入并赋值给变量 if err != nil { fmt.Println("输入错误:", err) return } } } if destId == "" { fmt.Println("未找到需要下载的账号_id") return } int64Id, _ := strconv.ParseInt(destId, 10, 64) filename := "Unit" + destUid + ".json" storeFilename := "StoreComponent" + destUid + ".json" deadFilename := "DeadVillagerManagerComponent" + destUid + ".json" decorationFilename := "DecorationManagerComponent" + destUid + ".json" log.Printf("download Unit destid: %d, destUniqueId: %d", int64Id, int64Uid) g.Try(ctx, func(ctx context.Context) { if hasAccount { mongoexportCommand(ctx, filename, "Unit", int64Uid, linkAccount, 1) mongoexportCommand(ctx, storeFilename, "StoreComponent", int64Id, linkAccount, 2) mongoexportCommand(ctx, deadFilename, "DeadVillagerManagerComponent", int64Id, linkAccount, 2) mongoexportCommand(ctx, decorationFilename, "DecorationManagerComponent", int64Id, linkAccount, 2) } else { mongoexportCommand(ctx, filename, "Unit", int64Uid, link, 1) mongoexportCommand(ctx, storeFilename, "StoreComponent", int64Id, link, 2) mongoexportCommand(ctx, deadFilename, "DeadVillagerManagerComponent", int64Id, link, 2) mongoexportCommand(ctx, decorationFilename, "DecorationManagerComponent", int64Id, link, 2) } }) } func writeDestFile(fileName string) (destId string, err error) { destUserDir := "./" + fileName writeByte, err1 := os.ReadFile(destUserDir) if err1 != nil { return "", err1 } var v1 map[string]interface{} if strings.HasPrefix(string(writeByte), "[") { user := []interface{}{} json.Unmarshal(writeByte, &user) v1 = user[0].(map[string]interface{}) } else { json.Unmarshal(writeByte, &v1) } if _, ok := v1["_id"]; ok { uid := v1["_id"].(map[string]interface{}) destId = fmt.Sprint(uid["$numberLong"]) } err = os.Remove(destUserDir) if err != nil { log.Printf("%s os.Remove failed with %s\n", destUserDir, err) return } return } func mongoexportCommand(ctx context.Context, filename string, collection string, uid int64, url string, qType int) { g.Try(ctx, func(ctx context.Context) { args := []string{} dir := "./" + filename args = append(args, fmt.Sprintf("--uri=\"%s\"", url)) args = append(args, fmt.Sprintf("--authenticationDatabase=admin")) args = append(args, fmt.Sprintf("--collection=%s", collection)) args = append(args, "--jsonArray") args = append(args, fmt.Sprintf("--out=\"%s\"", dir)) if qType == 1 { args = append(args, fmt.Sprintf("--query=\"{\\\"UniqueId\\\":%d}\"", uid)) } else { args = append(args, fmt.Sprintf("--query=\"{\\\"_id\\\":%d}\"", uid)) } args = append(args, "--jsonFormat=canonical") args = append(args, "--type=json") err := cmdCommand(ctx, "mongoexport", args...) if err != nil { log.Printf(" %s cmd.Run() args failed with %s\n", dir, err) return } }) } func updateUnit(ctx context.Context, rdb *redis.Client) { var destUid string var srcUid string fmt.Print("输入需要修改的UniqueId: ") _, err := fmt.Scan(&destUid) // 读取输入并赋值给变量 if err != nil { fmt.Println("输入错误:", err) return } fmt.Print("输入需要导入的UniqueId: ") _, err = fmt.Scan(&srcUid) // 读取输入并赋值给变量 if err != nil { fmt.Println("输入错误:", err) return } var filename = "Unit" + srcUid + ".json" var storeFilename = "StoreComponent" + srcUid + ".json" var deadFilename = "DeadVillagerManagerComponent" + srcUid + ".json" var decorationFilename = "DecorationManagerComponent" + srcUid + ".json" fmt.Printf("导入账号Unit信息: %s\n", filename) fmt.Printf("导入账号store信息: %s\n", storeFilename) fmt.Printf("导入账号deadVillager信息: %s\n", deadFilename) fmt.Printf("导入账号decoration信息: %s\n", decorationFilename) fmt.Printf("请按照以上命名修改需要导入的文件放到当前文件夹下 \n") time.Sleep(2 * time.Second) fmt.Printf("输入任意字符,按回车键继续... :") pause1 := "" _, err = fmt.Scan(&pause1) if err != nil { fmt.Println("输入错误:", err) return } fmt.Printf("准备修改账号: %s\n", destUid) int64Uid, _ := strconv.ParseInt(destUid, 10, 64) destId, err := rdb.HGet(ctx, "public_id_for_uid", fmt.Sprint(destUid)).Result() if err != nil { fmt.Println("redis无法打开 无法搜索 _id, err:", err) fmt.Println("尝试通过数据库查查找账号_id。") destFileName := "DestUnit" + destUid + ".json" if hasAccount { mongoexportCommand(ctx, destFileName, "Unit", int64Uid, linkAccount, 1) } else { mongoexportCommand(ctx, destFileName, "Unit", int64Uid, link, 1) } time.Sleep(5 * time.Second) destId, _ = writeDestFile(destFileName) if destId == "" { fmt.Print("请手动输入需要修改的账号_id: ") _, err = fmt.Scan(&destId) // 读取输入并赋值给变量 if err != nil { fmt.Println("输入错误:", err) return } } } if destId == "" { fmt.Println("未找到需要修改的账号_id") return } int64Id, _ := strconv.ParseInt(destId, 10, 64) //intUid, _ := strconv.Atoi(destUid) userDir := "./Unit" + destId + fmt.Sprint(time.Now().Unix()) + ".json" srcId, err1 := writeFile1(int64Id, userDir, filename, int64Uid) if err1 != nil { err = err1 return } log.Printf("copyUnit srcid: %s, destid: %d, DestName: %d", srcId, int64Id, int64Uid) userStoreDir := "./StoreComponent" + destUid + fmt.Sprint(time.Now().Unix()) + ".json" err = writeFile(int64Id, srcId, userStoreDir, storeFilename) if err != nil { return } userDeadDir := "./DeadVillagerManagerComponent" + destUid + fmt.Sprint(time.Now().Unix()) + ".json" err = writeFile(int64Id, srcId, userDeadDir, deadFilename) if err != nil { return } userDecorationDir := "./DecorationManagerComponent" + destUid + fmt.Sprint(time.Now().Unix()) + ".json" err = writeFile(int64Id, srcId, userDecorationDir, decorationFilename) if err != nil { return } g.Try(ctx, func(ctx context.Context) { if hasAccount { mongoimportCommand(ctx, "Unit", userDir, linkAccount) mongoimportCommand(ctx, "StoreComponent", userStoreDir, linkAccount) mongoimportCommand(ctx, "DeadVillagerManagerComponent", userDeadDir, linkAccount) mongoimportCommand(ctx, "DecorationManagerComponent", userDecorationDir, linkAccount) } else { mongoimportCommand(ctx, "Unit", userDir, link) mongoimportCommand(ctx, "StoreComponent", userStoreDir, link) mongoimportCommand(ctx, "DeadVillagerManagerComponent", userDeadDir, link) mongoimportCommand(ctx, "DecorationManagerComponent", userDecorationDir, link) } }) fmt.Println("CopyUnit GetRoleDelta", destId) } func writeFile1(destId int64, userDir string, fileName string, destName int64) (srcId string, err error) { srcUserDir := "./" + fileName writeByte, err1 := os.ReadFile(srcUserDir) if err1 != nil { return "", err1 } srcUid := "" var v1 map[string]interface{} if strings.HasPrefix(string(writeByte), "[") { user := []interface{}{} json.Unmarshal(writeByte, &user) v1 = user[0].(map[string]interface{}) } else { json.Unmarshal(writeByte, &v1) } if _, ok := v1["UniqueId"]; ok { UniqueId := v1["UniqueId"].(map[string]interface{}) srcUid = fmt.Sprint(UniqueId["$numberInt"]) } if _, ok := v1["_id"]; ok { uid := v1["_id"].(map[string]interface{}) srcId = fmt.Sprint(uid["$numberLong"]) } log.Printf("copyUnit srcid: %s, uid: %s, destId: %d, destName: %d", srcId, srcUid, destId, destName) if srcId == "" || srcUid == "" { return } writeUnitString := strings.ReplaceAll(gjson.MustEncodeString(v1), srcId, fmt.Sprint(destId)) writeUnitString = ReplaceLastOccurrence(writeUnitString, srcUid, fmt.Sprint(destName)) if err = os.WriteFile(userDir, []byte(writeUnitString), 0666); err != nil { log.Println(err) return } return } func writeFile(destId int64, srcId string, userDir string, fileName string) (err error) { srcDir := "./" + fileName writeByte, err1 := os.ReadFile(srcDir) if err1 != nil { return err1 } var v map[string]interface{} if strings.HasPrefix(string(writeByte), "[") { user := []interface{}{} json.Unmarshal(writeByte, &user) if len(user) != 0 { v = user[0].(map[string]interface{}) } } else { json.Unmarshal(writeByte, &v) } if len(v) != 0 { writeString := strings.ReplaceAll(gjson.MustEncodeString(v), srcId, fmt.Sprint(destId)) if err = os.WriteFile(userDir, []byte(writeString), 0666); err != nil { log.Println(err) return } } return } func mongoimportCommand(ctx context.Context, collection, dir, url string) { args := []string{} args = append(args, fmt.Sprintf("--uri=\"%s\"", url)) args = append(args, fmt.Sprintf("--authenticationDatabase=admin")) args = append(args, fmt.Sprintf("--collection=%s", collection)) args = append(args, fmt.Sprintf("--file=\"%s\"", dir)) args = append(args, "--type=json") args = append(args, "--mode=upsert") err := cmdCommand(ctx, "mongoimport", args...) if err != nil { log.Printf("%s cmd.Run() failed with %s\n", dir, err) return } err = os.Remove(dir) if err != nil { log.Printf("%s os.Remove failed with %s\n", dir, err) return } } func cmdCommand(ctx context.Context, name string, args ...string) (err error) { err = g.Try(ctx, func(ctx context.Context) { cmd := exec.Command(name, args...) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout // 标准输出 cmd.Stderr = &stderr // 标准错误 err = cmd.Run() if err != nil { log.Printf("cmd.Run() failed with %s\n", err) return } outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes()) fmt.Printf("out:\n%s\nerr:\n%s\n", outStr, errStr) }) return } // ReplaceLastOccurrence 替换最后一个匹配的子字符串 func ReplaceLastOccurrence(s, oldStr, newStr string) string { lastIndex := strings.LastIndex(s, oldStr) if lastIndex == -1 { return s // 未找到,直接返回原字符串 } return s[:lastIndex] + newStr + s[lastIndex+len(oldStr):] }