You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
12 KiB

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):]
}