更新代码

This commit is contained in:
hahwu 2024-12-24 15:52:43 +08:00
parent e780ed1f5b
commit 553426e0d6
43 changed files with 5451 additions and 33 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
/Goleaf
Goleaf.tar
source/main
playbook/node_modules/*

15
kafka/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch file",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${file}"
}
]
}

Binary file not shown.

14
kafka/conf/conf.yml Normal file
View File

@ -0,0 +1,14 @@
db:
host: "localhost"
user: root
password: "hef0YMId4DayV0XuGCLmjNjEAVg="
port: 3306
games:
- name: "Merge_Pet_Local"
topic: "Merge_Pet_Local"
partition: 0
db_name: "Merge_Pet_Local"
- name: "Merge_Pet_Test"
topic: "Merge_Pet_Test"
partition: 0
db_name: "Merge_Pet_Test"

98
kafka/config/config.go Normal file
View File

@ -0,0 +1,98 @@
package config
import (
"fmt"
"log"
"os"
"path/filepath"
"gopkg.in/yaml.v2"
)
type Config struct {
DB struct {
Host string `yaml:"host"`
User string `yaml:"user"`
Password string `yaml:"password"`
Port int `yaml:"port"`
} `yaml:"db"`
Games []struct {
Name string `yaml:"name"`
DBName string `yaml:"db_name"`
Topic string `yaml:"topic"`
Partition int `yaml:"partition"`
} `yaml:"games"`
}
type Game struct {
Name string
DBName string
Topic string
Partition int
}
type DBConf struct {
Host string
User string
Password string
Port int
DbNamee string
}
var Conf *Config
func init() {
var err error
Conf, err = loadConfig("./conf/conf.yml")
if err != nil {
log.Fatalf("Error loading config: %v", err)
}
}
func loadConfig(filename string) (*Config, error) {
absPath, err := filepath.Abs(filename)
if err != nil {
return nil, err
}
fmt.Println(absPath)
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
var config Config
err = yaml.Unmarshal(data, &config)
if err != nil {
return nil, err
}
return &config, nil
}
func GetDbConfig(Key string) *DBConf {
DBConf := &DBConf{}
for _, game := range Conf.Games {
if game.Name == Key {
DBConf.Host = Conf.DB.Host
DBConf.User = Conf.DB.User
DBConf.Password = Conf.DB.Password
DBConf.Port = Conf.DB.Port
DBConf.DbNamee = game.DBName
break
}
}
return DBConf
}
func GetGames() []*Game {
games := make([]*Game, 0)
for _, game := range Conf.Games {
games = append(games, &Game{
Name: game.Name,
DBName: game.DBName,
Topic: game.Topic,
Partition: game.Partition,
})
}
return games
}

94
kafka/db/db.go Normal file
View File

@ -0,0 +1,94 @@
package db
import (
"encoding/json"
"kafka-comsumer/config"
"kafka-comsumer/util"
"strconv"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"github.com/segmentio/kafka-go"
)
var Container = map[string]*sqlx.DB{}
func GetContainer(Key string) *sqlx.DB {
v, ok := Container[Key]
if !ok {
DbConf := config.GetDbConfig(Key)
NewDbPass, _ := util.Decrypt(DbConf.Password, util.SECRET_KEY)
db, err := sqlx.Connect("mysql", DbConf.User+":"+NewDbPass+"@tcp("+DbConf.Host+":"+strconv.Itoa(DbConf.Port)+")/"+DbConf.DbNamee)
if err != nil {
return nil
}
Container[Key] = db
return db
}
return v
}
func ProcessMsg(SqlDb *sqlx.DB, m kafka.Message) error {
if SqlDb == nil {
return nil
}
// fmt.Printf("Message at offset %d: %s = %s\n", m.Offset, string(m.Key), string(m.Value))
tx := SqlDb.MustBegin()
var err error
switch string(m.Key) {
case "Login_log":
err = login(SqlDb, m)
case "Login_Out":
err = login(SqlDb, m)
default:
err = event(SqlDb, m)
}
if err != nil {
tx.Rollback()
return err
}
offset(SqlDb, m)
tx.Commit()
// fmt.Println("msg process success")
return nil
}
func login(SqlDb *sqlx.DB, m kafka.Message) error {
var V map[string]interface{}
json.Unmarshal(m.Value, &V)
sql := "INSERT INTO log_login (`Uid`, `Event`, `Timestamp`) VALUES (?, ?, ?)"
_, err := SqlDb.Exec(sql, V["Uid"], m.Key, V["TimeStamp"])
return err
}
func event(SqlDb *sqlx.DB, m kafka.Message) error {
var V map[string]interface{}
json.Unmarshal(m.Value, &V)
Param, err := json.Marshal(V["Param"])
if err != nil {
return err
}
sql := "INSERT INTO log_event (`Uid`, `Event`, `Param`, `Timestamp`) VALUES (?, ?, ?, ?)"
_, err = SqlDb.Exec(sql, V["Uid"], m.Key, string(Param), V["TimeStamp"])
return err
}
func offset(SqlDb *sqlx.DB, m kafka.Message) error {
sql := " INSERT INTO `log_var` (`Key` , `Value`, `Timestamp`) Values (?,?,?) ON DUPLICATE KEY UPDATE `key` = ? , `Value` = ? ,`Timestamp`=?"
Value := strconv.FormatInt(m.Offset+1, 10)
Timestamp := util.GetNowTime()
_, err := SqlDb.Exec(sql, "offset", Value, Timestamp, "offset", Value, Timestamp)
return err
}
func GetOffset(SqlDb *sqlx.DB) int64 {
sql := "select `Value` from `log_var` where `Key` = 'offset'"
var offset string
err := SqlDb.Get(&offset, sql)
if offset == "" || err != nil {
return kafka.FirstOffset
}
v, _ := strconv.ParseInt(offset, 10, 64)
return v
}

17
kafka/go.mod Normal file
View File

@ -0,0 +1,17 @@
module kafka-comsumer
go 1.23.1
require github.com/segmentio/kafka-go v0.4.47
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

83
kafka/go.sum Normal file
View File

@ -0,0 +1,83 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

BIN
kafka/kafka-comsumer.tar Normal file

Binary file not shown.

78
kafka/main.go Normal file
View File

@ -0,0 +1,78 @@
package main
import (
"context"
"kafka-comsumer/config"
"kafka-comsumer/db"
"log"
"os"
"os/signal"
"sync"
"syscall"
"github.com/segmentio/kafka-go"
)
var (
WorkChan = make(chan *kafka.Message, 100)
Wait sync.WaitGroup
)
// GOOS=linux GOARCH=amd64 go build -o /data/pet_home_devops/kafka/release/kafka_comsumer main.go
func main() {
// 打开日志文件
logFile, err := os.OpenFile("./log/kafka-comsumer.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Failed to open log file: %v", err)
}
defer logFile.Close()
// 将日志输出重定向到文件
log.SetOutput(logFile)
log.SetFlags(log.LstdFlags | log.Lshortfile)
Games := config.GetGames()
for _, game := range Games {
go comsumer(game)
}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
sig := <-c
log.Printf("kafka comsumer closing down (signal: %v)\n", sig.String())
Wait.Wait()
}
func comsumer(Game *config.Game) {
sqlDb := db.GetContainer(Game.Name)
if sqlDb == nil {
log.Printf("comsumer db %s not exist \n", Game.Name)
return
}
r := kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{"kafka-server:9092"},
Topic: Game.Topic,
Partition: Game.Partition,
MinBytes: 10e3, // 10KB
MaxBytes: 10e6, // 10MB
})
defer r.Close()
// 设置读取超时时间
offset := db.GetOffset(sqlDb)
r.SetOffset(offset)
ctx := context.Background()
log.Println("comsumer start ", Game.Name)
for {
// 读取消息
m, err := r.ReadMessage(ctx)
if err != nil {
log.Println("comsumer close ", Game.Name)
return
}
Wait.Add(1)
err = db.ProcessMsg(sqlDb, m)
if err != nil {
log.Printf("comsumer %s error :%v", Game.Name, err)
}
Wait.Done()
}
}

View File

@ -0,0 +1,14 @@
db:
host: "rm-f8zd2030feam53n43.mysql.rds.aliyuncs.com"
user: root
password: "V00jJQcC5GQOSEoEXmTfFmBCTk1-g2lBT2n-YA9UUg=="
port: 3306
games:
- name: "Merge_Pet_Local"
topic: "Merge_Pet_Local"
partition: 0
db_name: "Merge_Pet_Local"
- name: "Merge_Pet_Test"
topic: "Merge_Pet_Test"
partition: 0
db_name: "Merge_Pet_Test"

Binary file not shown.

View File

@ -0,0 +1,2 @@
2024/12/18 07:00:46 main.go:48: comsumer db Merge_Pet_Online not exist
2024/12/18 07:00:46 main.go:63: comsumer start Merge_Pet_Local

2
kafka/release/logs Normal file
View File

@ -0,0 +1,2 @@
/data/pet_home_devops/kafka/release/conf/conf.yml
/data/pet_home_devops/kafka/release/conf/conf.yml

51
kafka/release/start.sh Normal file
View File

@ -0,0 +1,51 @@
#!/bin/sh
# Restart the kafka comsumer service
# 获取命令行参数
if [ $# -ne 1 ]; then
echo "Usage: $0 [start|stop|status|restart]"
exit 1
fi
if [ $1 == "start" ]; then
echo "Starting kafka comsumer..."
> log/kafka-comsumer.log # 清空 logs 文件
nohup ./kafka_comsumer >> logs 2>&1 &
echo "kafka comsumer started."
elif [ $1 == "stop" ]; then
echo "Stopping kafka comsumer..."
PID=$(ps -ef | grep kafka_comsumer | grep -v "grep" | awk '{print $2}')
if [ -z $PID ]; then
echo "kafka comsumer is not running."
exit 1
fi
ps -ef | grep kafka_comsumer | grep -v grep | awk '{print $2}' | xargs kill
echo "kafka comsumer stopped."
elif [ $1 == "status" ]; then
echo "kafka comsumer status:"
PID=$(ps -ef | grep kafka_comsumer | grep -v "grep" | awk '{print $2}')
if [ -z $PID ]; then
echo "kafka comsumer is not running."
else
echo "kafka comsumer is running."
fi
elif [ $1 == "restart" ]; then
echo "Restarting kafka comsumer..."
PID=$(ps -ef | grep kafka_comsumer | grep -v "grep" | awk '{print $2}')
if [ -n $PID ]; then
echo "kafka comsumer stoping."
kill $PID
fi
while [ -n "$PID" ]; do
sleep 1
PID=$(ps -ef | grep kafka_comsumer | grep -v "grep" | awk '{print $2}')
done
echo "kafka comsumer stoped."
> log/kafka-comsumer.log # 清空 logs 文件
nohup kafka_comsumer >> logs 2>&1 &
echo "kafka comsumer restarted."
else
echo "Usage: $0 [start|stop|status|restart]"
exit 1
fi

37
kafka/sql/create.sql Normal file
View File

@ -0,0 +1,37 @@
/*==============================================================*/
/* Database name: sg_gamedb */
/* DBMS name: MySQL 5.5.17 */
/* Created on: 2014-10-16 10:00:00 */
/*==============================================================*/
create database if not exists Merge_Pet_Local CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
use Merge_Pet_Local;
CREATE TABLE IF NOT EXISTS `log_var` (
`Key` varchar(128) DEFAULT '' COMMENT '',
`Value` varchar(128) DEFAULT '' COMMENT '',
`Timestamp` int DEFAULT 0 COMMENT '时间',
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录日志';
CREATE TABLE IF NOT EXISTS `log_login` (
`id` int unsigned AUTO_INCREMENT COMMENT '自增id',
`Uid` int unsigned NOT NULL COMMENT '玩家id',
`Event` varchar(128) DEFAULT '' COMMENT '事件',
`Timestamp` int DEFAULT 0 COMMENT '时间',
PRIMARY KEY (`id`),
KEY `Event` (`Event`),
KEY `Uid` (`Uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录日志';
CREATE TABLE IF NOT EXISTS `log_event` (
`id` int unsigned AUTO_INCREMENT COMMENT '自增id',
`Uid` int unsigned NOT NULL COMMENT '玩家id',
`Event` varchar(128) DEFAULT '' COMMENT '事件',
`Param` text COMMENT '参数',
`Timestamp` int DEFAULT 0 COMMENT '时间',
PRIMARY KEY (`id`),
KEY `Event` (`Event`),
KEY `Uid` (`Uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作事件';

23
kafka/unit_test.go Normal file
View File

@ -0,0 +1,23 @@
package main
import (
"fmt"
"kafka-comsumer/util"
"testing"
)
func TestEncrypt(t *testing.T) {
str, err := util.Encrypt("Z4rf7eZZe500dxa", util.SECRET_KEY)
if err != nil {
t.Errorf("Error: %v", err)
}
fmt.Print(str)
}
func TestDecrypt(t *testing.T) {
str, err := util.Decrypt("V00jJQcC5GQOSEoEXmTfFmBCTk1-g2lBT2n-YA9UUg==", util.SECRET_KEY)
if err != nil {
t.Errorf("Error: %v", err)
}
fmt.Print(str)
}

64
kafka/util/util.go Normal file
View File

@ -0,0 +1,64 @@
package util
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"time"
)
const (
SECRET_KEY = ")VQbB(vpy=U(wcp)"
)
// 加密字符串
func Encrypt(plainText, key string) (string, error) {
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
cipherText := make([]byte, aes.BlockSize+len(plainText))
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(cipherText[aes.BlockSize:], []byte(plainText))
return base64.URLEncoding.EncodeToString(cipherText), nil
}
// 解密字符串
func Decrypt(cipherText, key string) (string, error) {
cipherTextBytes, err := base64.URLEncoding.DecodeString(cipherText)
if err != nil {
return "", err
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
if len(cipherTextBytes) < aes.BlockSize {
return "", fmt.Errorf("cipherText too short")
}
iv := cipherTextBytes[:aes.BlockSize]
cipherTextBytes = cipherTextBytes[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(cipherTextBytes, cipherTextBytes)
return string(cipherTextBytes), nil
}
func GetNowTime() int64 {
T := time.Now()
return T.Unix()
}

40
nginx/gitea.conf Normal file
View File

@ -0,0 +1,40 @@
server {
listen 80;
server_name gitea.bywaystudios.com;
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name gitea.bywaystudios.com;
ssl_certificate /etc/nginx/ssl/gitea.bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/gitea.bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /kafka {
proxy_pass http://localhost:500/ui;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 可选:配置日志文件
access_log /var/log/nginx/gitea_access.log;
error_log /var/log/nginx/gitea_error.log;
}

31
nginx/tcp.conf Normal file
View File

@ -0,0 +1,31 @@
server {
listen 80;
server_name pethome.bywaystudios.com;
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name pethome.bywaystudios.com;
ssl_certificate /etc/nginx/ssl/pethome.bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/pethome.bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 可选:配置日志文件
access_log /var/log/nginx/pethome_access.log;
error_log /var/log/nginx/pethome_error.log;
}

View File

@ -1,2 +1,2 @@
cd /data/pet_home/src/server
GOOS=linux GOARCH=amd64 go build -o /data/devops/source/main main.go
cd /data/pet_home_server/src/server
GOOS=linux GOARCH=amd64 go build -o /data/pet_home_devops/source/main main.go

View File

@ -1,6 +1,6 @@
---
- name: Deploy GoLeaf release
hosts: compose
hosts: zone1
remote_user: root
tasks:
@ -12,19 +12,19 @@
# - name: tar
# command: tar -xvf /usr/local/Goleaf.tar -C /usr/local/
- name: sh pack.sh
shell: sh /data/devops/pack.sh
shell: sh /data/pet_home_devops/pack.sh
delegate_to: localhost
- name: copy goleaf
copy:
src: /data/devops/source/main
src: /data/pet_home_devops/source/main
dest: /usr/local/Goleaf
- name: copy config
copy:
src: /data/docs/tool/out/
dest: /usr/local/Goleaf/gamedata/config/
mode: '0777'
# - name: copy config
# copy:
# src: /data/pet_homedocs/tool/out/
# dest: /usr/local/Goleaf/gamedata/config/
# mode: '0777'
# - name: restart goleaf

27
playbook/goleaf-conf.yml Normal file
View File

@ -0,0 +1,27 @@
---
- name: Deploy GoLeaf release
hosts: test
remote_user: root
tasks:
- name: copy config
copy:
src: /data/pet_homedocs/tool/out/
dest: /usr/local/Goleaf/gamedata/config/
mode: '0777'
- name: reload config
command: echo "1" > /usr/local/Goleaf/gamedata/config/reload
register: reload_result
- name: copy config2
copy:
src: /data/pet_homedocs/tool/out/
dest: /usr/local/game/gamedata/config/
mode: '0777'
- name: reload config
command: echo "1" > /usr/local/game/gamedata/config/reload
register: reload_result

View File

@ -0,0 +1,53 @@
---
- name: Deploy GoLeaf release
hosts: google
remote_user: root
vars:
goleaf_src: /data/pet_home_devops/source/main
goleaf_dest: /usr/local/game
config_src: /data/pet_homedocs/tool/out/
config_dest: /usr/local/game/gamedata/config/
pack_script: /data/pet_home_devops/pack.sh
tar_file: /usr/local/Goleaf.tar
tar_dest: /usr/local/game
tasks:
# - name: copy goleaf
# command: tar -cvf /usr/local/Goleaf.tar -C /data/pet_home_devops/Goleaf .
# delegate_to: localhost
# - name: copy tar
# copy:
# src: /usr/local/Goleaf.tar
# dest: /usr/local/game
# - name : untar
# command: tar -xvf /usr/local/game/Goleaf.tar -C /usr/local/game
- name: sh pack.sh
shell: sh /data/pet_home_devops/pack.sh
delegate_to: localhost
- name: stop goleaf
command: sh "{{ goleaf_dest }}"/Restart.sh stop
register: restart_result
- name: copy goleaf
copy:
src: "{{ goleaf_src }}"
dest: "{{goleaf_dest}}"
- name: copy goleaf
command: tar -cvf /usr/local/conf.tar -C /data/pet_homedocs/tool/out .
delegate_to: localhost
- name: copy tar
copy:
src: /usr/local/conf.tar
dest: /usr/local/game
- name : untar
command: tar -xvf /usr/local/game/conf.tar -C /usr/local/game/gamedata/config/
- name: restart goleaf
command: sh "{{ goleaf_dest }}"/Restart.sh start
register: restart_result
- name: show restart result
debug:
var: restart_result.stdout_lines

53
playbook/goleaf-sdk.yml Normal file
View File

@ -0,0 +1,53 @@
---
- name: Deploy GoLeaf release
hosts: test
remote_user: root
vars:
goleaf_src: /data/pet_home_devops/source/main
goleaf_dest: /usr/local/game
config_src: /data/pet_homedocs/tool/out/
config_dest: /usr/local/game/gamedata/config/
pack_script: /data/pet_home_devops/pack.sh
tar_file: /usr/local/Goleaf.tar
tar_dest: /usr/local/game
tasks:
# - name: copy goleaf
# command: tar -cvf /usr/local/Goleaf.tar -C /data/pet_home_devops/Goleaf .
# delegate_to: localhost
# - name: copy tar
# copy:
# src: /usr/local/Goleaf.tar
# dest: /usr/local/game
# - name : untar
# command: tar -xvf /usr/local/game/Goleaf.tar -C /usr/local/game
- name: sh pack.sh
shell: sh /data/pet_home_devops/pack.sh
delegate_to: localhost
- name: restart goleaf
command: sh "{{ goleaf_dest }}"/Restart.sh stop
register: restart_result
- name: copy goleaf
copy:
src: "{{ goleaf_src }}"
dest: "{{goleaf_dest}}"
- name: copy goleaf
command: tar -cvf /usr/local/conf.tar -C /data/pet_homedocs/tool/out .
delegate_to: localhost
- name: copy tar
copy:
src: /usr/local/conf.tar
dest: /usr/local/game
- name : untar
command: tar -xvf /usr/local/game/conf.tar -C /usr/local/game/gamedata/config/
- name: restart goleaf
command: sh "{{ goleaf_dest }}"/Restart.sh start
register: restart_result
- name: show restart result
debug:
var: restart_result.stdout_lines

View File

@ -4,26 +4,38 @@
remote_user: root
tasks:
- name: sh pack.sh
shell: sh /data/devops/pack.sh
delegate_to: localhost
# - name: restart goleaf
# command: sh /usr/local/Goleaf/Restart.sh stop
# register: restart_result
# - name: sh pack.sh
# shell: sh /data/pet_home_devops/pack.sh
# delegate_to: localhost
# - name: copy goleaf
# copy:
# src: /data/pet_home_devops/Goleaf/tool/tool
# dest: /usr/local/Goleaf/tool
# - name: copy goleaf
# copy:
# src: /data/pet_home_devops/source/main
# dest: /usr/local/Goleaf
- name: copy goleaf
command: tar -cvf /usr/local/conf.tar -C /data/pet_homedocs/tool/out .
delegate_to: localhost
- name: copy tar
copy:
src: /data/devops/source/main
src: /usr/local/conf.tar
dest: /usr/local/Goleaf
- name: copy config
copy:
src: /data/docs/tool/out/
dest: /usr/local/Goleaf/gamedata/config/
mode: '0777'
- name : untar
command: tar -xvf /usr/local/Goleaf/conf.tar -C /usr/local/Goleaf/gamedata/config/
- name: restart goleaf
command: sh /usr/local/Goleaf/Restart.sh restart
register: restart_result
# - name: restart goleaf
# command: sh /usr/local/Goleaf/Restart.sh start
# register: restart_result
- name: show restart result
debug:
var: restart_result.stdout_lines
# - name: show restart result
# debug:
# var: restart_result.stdout_lines

View File

@ -1,8 +1,17 @@
[test]
test ansible_ssh_host=1.15.182.107 ansible_ssh_user="root" ansible_ssh_port=22
a1 ansible_ssh_host=1.15.182.107 ansible_ssh_user="root" ansible_ssh_port=22
[compose]
center ansible_ssh_host=172.20.0.2 ansible_ssh_user="root" ansible_ssh_port=22
zone1 ansible_ssh_host=172.20.0.3 ansible_ssh_user="root" ansible_ssh_port=22
zone2 ansible_ssh_host=172.20.0.4 ansible_ssh_user="root" ansible_ssh_port=22
c1 ansible_ssh_host=172.20.0.2 ansible_ssh_user="root" ansible_ssh_port=22
z1 ansible_ssh_host=172.20.0.3 ansible_ssh_user="root" ansible_ssh_port=22
z2 ansible_ssh_host=172.20.0.4 ansible_ssh_user="root" ansible_ssh_port=22
[zone1]
a2 ansible_ssh_host=172.20.0.3 ansible_ssh_user="root" ansible_ssh_port=22
[google]
g1 ansible_ssh_host=47.254.83.25 ansible_ssh_user="root" ansible_ssh_port=22
[release]
a1 ansible_ssh_host=1.15.182.107 ansible_ssh_user="root" ansible_ssh_port=22
g1 ansible_ssh_host=47.254.83.25 ansible_ssh_user="root" ansible_ssh_port=22

1344
playbook/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

5
playbook/package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"protobufjs-cli": "^1.1.3"
}
}

BIN
script/20241216.xlsx Normal file

Binary file not shown.

View File

@ -22,15 +22,16 @@ server = SSHTunnelForwarder(
server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
RID = 100016
MYRID = 100002
print(db_host, db_port)
RID = 200090
MYRID = 100004
conn = pymysql.connect(
host=db_host,
port=db_port,
user="root",
password="Z4rf7eZZe500dxa",
database="Merge_Pet"
database="Merge_Pet_sdk"
)
cursor = conn.cursor()
cursor.execute(("select * from t_player_mod where dwUin = {rid}").format(rid = RID))

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAo6z7cPVcCIu+rT6ywB5dhhpZfCiKQu155+XPR1kmMFwiFVQe
XnzcT5kmdHLJVEZOgV+LM76SeiGi7haF3wH9N9uYUMmp91b4H2IAiybaKGl/Xc7M
WWpn5YJcttCdd3ZfzYqRQoysucmi4qTzSwf3vJqijo+JFmDvolVWO0KtDsRmU6DL
nocygaKROyyCh5HbWZnikb0bUTLYu58zhYvc1eFwrfwjRSPsGDcTbFHWCl1UNnfZ
mWO0ydMnbfzUSQTGJmOVwqFkhMVRGFFjrTRUAeDNQpkr9YN8tGc+111Igq+uAfMc
yrIIlfEy2ltSnu8hxjNb4sk5v9Fv7APkrjGVsQIDAQABAoIBAALK+8Fm/NDyg+iH
fNv1YknDBYrhhpzZjSGtYYOWQr+pgTViKZOzYSKeLbKBl1J8uDzR6T/fsFBgMykJ
flnnU6+Fa9k/dhe2RrNplzIvEaLsTFP79UjptwGK320ixl6yL04d337f6qSci07l
wXcJMquBUf78j22WOt1gxAEGRFcccNj4yTxLOAFUqwegBy9MuH02VCW4z9QEwiWU
MmQHbFIpHreJaIh+CaBWx9CUEzL4iCYqRnmSNgfw5AE0snvXid1tlQT4IBRvcPE4
I2bRKUcxvckXHpVKbNPv2A43DoWjF+vlGjU6utMfZ5DRJWyn03s4HOAtrUGY48Sj
0kNDbOECgYEAzSZYgqJuNXEzuZ9dYeXwvCdmU+krOUGaRu1gAymkRdSu+KFDxaTs
xnbhbC0uUzSL0idqeUt3DpeV5rGJf8InbCVwTjmV8hKGS9zTMvBWAH4TavZswAJz
/MNKXZ96UR9xRZFU4988pMF/yqliCLUgN8FI0KvAdIiMgJt4XWa0UUkCgYEAzD7s
n9F7vo7ZHYt/L81lviw4+BBk1934LIvZsXadxmUE8S46ZgbqRZHbrErQ4GJGpCsc
tGAsJpubDapGHv8iL5e6eUphHsM1wR18ciCSNjkxcvSiQJcCpzXLgDY8Tg7KxIOF
c+HKH5O+awCIJcRBBZIXgTC6Gxy6IFee/GXNCSkCgYA0h4YQZSENJCBXflv97k/X
Dcug3sqHjanAUZXNGYOLserflQNyf0l1hAkyltsOyRyoQhl8V3tzzBLBEGKhyQgp
I+j+zrX7Vwz2LeQSXgHXfHDiaZjtDXO/nA3VrTk3vnJVmuH+uzGfCkD7lqWYjzBh
tmc7r07HSBOZ9rU6TUsMqQKBgQCEoPPNEB4X7vDj85rCstE3vcW8qACkALrQSnwx
dgIcO6sK5mb7q8/jH0UTy315x7dxkaFRLAZfh7oXFJP2Oty7JP7tFjSc4kx8u6X9
AlOPrHIE4QCfirApXpBoEE/2rDpVg8ZcKqmy+aC0ISNHyvoiIOzscnTXeD8RE3Tl
F0IeiQKBgAMSt0sbXy7jgBSUgK8GU5Ox2YcstNMJfeXu5F7WjbtuAlwMNJgBLVYd
gM2lEE8xBUx/5wPkbvzJq4tRPzNO5T7AjOnYH1Ul2iz+kEDOZfPVL0OL/VUYFBYg
4SZnnt1jC9aHLHVqVIIJK//9cEfOJZ6mz3DtyX2wDm/tdoFOr4cG
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,62 @@
-----BEGIN CERTIFICATE-----
MIIGCDCCBPCgAwIBAgIQA0IfJS+AMdxZgd8L1fUl/TANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
RFYgVExTIENBIC0gRzIwHhcNMjQxMjA5MDAwMDAwWhcNMjUwMzA5MjM1OTU5WjAj
MSEwHwYDVQQDExhwZXRob21lLmJ5d2F5c3R1ZGlvcy5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCjrPtw9VwIi76tPrLAHl2GGll8KIpC7Xnn5c9H
WSYwXCIVVB5efNxPmSZ0cslURk6BX4szvpJ6IaLuFoXfAf0325hQyan3VvgfYgCL
JtooaX9dzsxZamflgly20J13dl/NipFCjKy5yaLipPNLB/e8mqKOj4kWYO+iVVY7
Qq0OxGZToMuehzKBopE7LIKHkdtZmeKRvRtRMti7nzOFi9zV4XCt/CNFI+wYNxNs
UdYKXVQ2d9mZY7TJ0ydt/NRJBMYmY5XCoWSExVEYUWOtNFQB4M1CmSv1g3y0Zz7X
XUiCr64B8xzKsgiV8TLaW1Ke7yHGM1viyTm/0W/sA+SuMZWxAgMBAAGjggLrMIIC
5zAfBgNVHSMEGDAWgBR435GQX+7erPbFdevVTFVT7yRKtjAdBgNVHQ4EFgQUKDRG
tBU/MaYUiXNhjO+s2+fcgs0wIwYDVR0RBBwwGoIYcGV0aG9tZS5ieXdheXN0dWRp
b3MuY29tMD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYIKwYBBQUHAgEWG2h0dHA6
Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYw
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGABggrBgEFBQcBAQR0MHIwJAYIKwYBBQUH
MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBKBggrBgEFBQcwAoY+aHR0cDov
L2NhY2VydHMuZGlnaWNlcnQuY29tL0VuY3J5cHRpb25FdmVyeXdoZXJlRFZUTFND
QS1HMi5jcnQwDAYDVR0TAQH/BAIwADCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFo
AHYATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGTqSjTewAABAMA
RzBFAiBZVs4LrOREOEnv8tQKb5UNFkPVfV2nNqCy24bKLAVr/gIhAMg2KsKQ9a6q
8Wc64AKJx3DjFqLFpCytkTVKtrBp0tUzAHUAcyAiDwgWivnzxKaLCrJqmkoA7vV3
hYoITQUA1KVCRFkAAAGTqSjTHwAABAMARjBEAiAiy4Xqcy0oqGMDDBRManyt6VmT
jCZRVA+mHBzoQT0NAgIgOCW5513LuInmKGlKi5jxRkIM0xh6te0uIQvt4ze9EekA
dwDm0jFjQHeMwRBBBtdxuc7B0kD2loSG+7qHMh39HjeOUAAAAZOpKNMvAAAEAwBI
MEYCIQDFKi06ApokpmIizAxE+175uD3bIYO9P3+otQg1ZjSiUQIhAJ0SThOlYjU6
1nvXCCVCrj96Jsb1KuKUdtPAelusunAHMA0GCSqGSIb3DQEBCwUAA4IBAQCoWphr
4DagcE2yZJkgbhtJ05HLnFBqaQQ5+7X6SR/MRAPY65nCKzgntzXvBcpexiF04I2u
ivtR0sH28Riuu+VDL4ltjZQsW20hd0QNeKia4caUaOaX0hEG1EO0sGLfHQI0G+oq
jtEuSQnnzy2El3gs0kORAFqhGkL2q56rscPpandzdF1H5v2CeM54Q9EmCFzwGW7e
NbLm7MSbn0enWs9q/Zjs6+t9n4VYFZw2c8BXDXtrim35ZcJpJZ7D91ve5SaMH5yg
5at5un2nAdDe3D3V1aATz5ebq3M0JHoqkmPE1a3CkzMdfA8CQArmClBn8gquxm/+
dq4rSsSh89wAz+lO
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIQDeD/te5iy2EQn2CMnO1e0zANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xNzExMjcxMjQ2NDBaFw0yNzExMjcxMjQ2NDBaMG4xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO8Uf46i/nr7pkgTDqnE
eSIfCFqvPnUq3aF1tMJ5hh9MnO6Lmt5UdHfBGwC9Si+XjK12cjZgxObsL6Rg1njv
NhAMJ4JunN0JGGRJGSevbJsA3sc68nbPQzuKp5Jc8vpryp2mts38pSCXorPR+sch
QisKA7OSQ1MjcFN0d7tbrceWFNbzgL2csJVQeogOBGSe/KZEIZw6gXLKeFe7mupn
NYJROi2iC11+HuF79iAttMc32Cv6UOxixY/3ZV+LzpLnklFq98XORgwkIJL1HuvP
ha8yvb+W6JislZJL+HLFtidoxmI7Qm3ZyIV66W533DsGFimFJkz3y0GeHWuSVMbI
lfsCAwEAAaOCAU8wggFLMB0GA1UdDgQWBBR435GQX+7erPbFdevVTFVT7yRKtjAf
BgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
-----END CERTIFICATE-----

226
tool/Merge_Pet.sql Normal file
View File

@ -0,0 +1,226 @@
/*==============================================================*/
/* Database name: sg_gamedb */
/* DBMS name: MySQL 5.5.17 */
/* Created on: 2014-10-16 10:00:00 */
/*==============================================================*/
create database if not exists %database% CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
use %database%;
-- ----------------------------
-- Table structure for db_version 版本号,每次更新数据库要改这个地方
-- ----------------------------
CREATE TABLE IF NOT EXISTS `db_version` (
`version_2018_02_06_13` int unsigned NOT NULL COMMENT 'version'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库版本号';
/*==============================================================*/
/* Table: t_account 账号表 */
/*==============================================================*/
CREATE TABLE IF NOT EXISTS t_account
(
`user_name` varchar(50) NOT NULL,
`user_password` varchar(128) NOT NULL,
`login_time` int unsigned DEFAULT '0' COMMENT '上次登录时间',
`logout_time` int unsigned DEFAULT '0' COMMENT '上次下线时间',
`ip_address` char(24) DEFAULT '' COMMENT '上次登录的ip地址',
`gm_level` int DEFAULT '0' COMMENT 'gm等级',
`platform` varchar(50) DEFAULT '' COMMENT '平台',
`is_online` int unsigned DEFAULT '0' COMMENT '角色是否在线',
`channel` varchar(50) DEFAULT '' COMMENT '渠道号',
`device_id` varchar(256) DEFAULT '' COMMENT '是否为刷榜账号',
`auto_id` bigint NOT NULL auto_increment COMMENT '自增id',
PRIMARY KEY (`auto_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='账号密码对照表';
/*==============================================================*/
/* Table: t_gameserver GameServer表 */
/*==============================================================*/
CREATE TABLE IF NOT EXISTS t_gameserver
(
`id` int unsigned COMMENT '服务器id',
`start_time` int unsigned COMMENT '开服时间',
`close_time` int unsigned COMMENT '关服时间',
`is_close` int unsigned COMMENT '是否关服',
primary key(`id`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='服务器设置';
/*==============================================================*/
/* Table: t_gameserver_info GameServer信息表 */
/*==============================================================*/
CREATE TABLE IF NOT EXISTS t_gameserver_info
(
`id` int unsigned COMMENT '服务器id',
`growthfund_buynum` int unsigned NOT NULL DEFAULT '0' COMMENT '全服购买成长基金数量',
`open_servertime` int unsigned NOT NULL DEFAULT '0' COMMENT '开服时间',
`open_activeflag` int unsigned NOT NULL DEFAULT '0' COMMENT '开服活动完成发放奖励标示',
`DailyRenewTime` int unsigned NOT NULL DEFAULT '0' COMMENT '日常刷新时间',
primary key(`id`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='全服全局数据';
-- ----------------------------
-- Table structure for t_player_baseinfo
-- ----------------------------
CREATE TABLE IF NOT EXISTS `t_player_baseinfo` (
`dwUin` int unsigned NOT NULL COMMENT '对应玩家account表中的dwUin',
`energy` int unsigned NOT NULL DEFAULT '0' COMMENT '能量',
`star` int unsigned NOT NULL DEFAULT '0' COMMENT '星星',
`recover_time` int unsigned NOT NULL DEFAULT '0' COMMENT '能量开始恢复时间',
`diamond` int unsigned NOT NULL DEFAULT '1' COMMENT '钻石',
`level` int unsigned NOT NULL DEFAULT '0' COMMENT '玩家等级',
`exp` int unsigned zerofill NOT NULL DEFAULT '0' COMMENT '玩家经验',
`start_order_id` varchar(50) DEFAULT NULL COMMENT '配置订单进度',
`music_code` int unsigned NOT NULL DEFAULT '0' COMMENT '音效状态码改为GUID免费改名状态',
`guild` int unsigned NOT NULL DEFAULT '0' COMMENT '引导进度 ',
`pack_unlock_count` int unsigned NOT NULL DEFAULT '0' COMMENT '背包解锁数量',
`last_play_time` int NOT NULL DEFAULT '0' COMMENT '广告能量购买时间',
`EnergyBuyCount` int NOT NULL DEFAULT '0' COMMENT '能量购买次数',
`user_name` varchar(50) NOT NULL COMMENT '玩家账号',
`login_time` int unsigned NOT NULL DEFAULT '0' COMMENT '上次登录时间',
`logout_time` int unsigned NOT NULL DEFAULT '0' COMMENT '上次下线时间',
`todayolinetime` int unsigned NOT NULL DEFAULT '0' COMMENT '当天的累计在线时间',
`rolecreatetime` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`EmitOrderCnt` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`DailyRenewTime` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`NoAd` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`ChampshipsGroupID` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`LastChampGroupID` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`FaceBookId` varchar(128) DEFAULT '' COMMENT '玩家账号',
PRIMARY KEY (`dwUin`),
KEY `user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='存储玩家基本信息';
-- ----------------------------
-- Table: t_player_auto_pup 客户端数据持久化表
-- ----------------------------
CREATE TABLE IF NOT EXISTS `t_player_auto_pup` (
`dwUin` int unsigned NOT NULL COMMENT 'uid',
`ReqKeys` varchar(2048) DEFAULT '' COMMENT 'key',
`ReqVals` varchar(2048) DEFAULT '' COMMENT 'value',
PRIMARY KEY (`dwUin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='存储玩家基本信息';
/*==============================================================*/
/* Table: t_player_data 玩家模块表 */
/*==============================================================*/
CREATE TABLE IF NOT EXISTS t_player_mod
(
`dwUin` int unsigned COMMENT '玩家uid',
`mData` blob DEFAULT NULL COMMENT '数据',
`updateTime` int unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
primary key(`dwUin`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='玩家模块表';
/*==============================================================*/
/* Table: t_player_data 玩家订单表 */
/*==============================================================*/
CREATE TABLE IF NOT EXISTS t_player_charge
(
`id`int unsigned AUTO_INCREMENT COMMENT '订单id',
`Uid` int unsigned NOT NULL COMMENT '玩家id',
`OrderId` varchar(128) DEFAULT '' COMMENT '订单号',
`ProductId` int unsigned NOT NULL DEFAULT '0' COMMENT '商品id',
`ProductName` varchar(128) DEFAULT '' COMMENT '商品名称',
`ProductDesc` varchar(128) DEFAULT '' COMMENT '商品描述',
`Price` float NOT NULL DEFAULT '0' COMMENT '价格',
`Currency` varchar(128) DEFAULT '' COMMENT '货币',
`CreateTime` int unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`PayTime` int unsigned NOT NULL DEFAULT '0' COMMENT '支付时间',
`PayStatus` int unsigned NOT NULL DEFAULT '0' COMMENT '支付状态 0 未支付 1 已支付 2 支付失败 3 已发货',
`PayType` int unsigned NOT NULL DEFAULT '0' COMMENT '支付类型',
`PayPlatform` varchar(128) DEFAULT '' COMMENT '支付平台',
`PayChannel` varchar(128) DEFAULT '' COMMENT '支付渠道',
`PayChannelOrderId` varchar(128) DEFAULT '' COMMENT '支付渠道订单号',
`PayChannelUserId` varchar(128) DEFAULT '' COMMENT '支付渠道用户id',
`PayChannelExtra` varchar(128) DEFAULT '' COMMENT '支付渠道额外信息',
primary key(`id`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='玩家订单表';
-- ----------------------------
-- Table structure for system_mail_info
-- ----------------------------
CREATE TABLE IF NOT EXISTS `system_mail_info` (
`mail_id` bigint NOT NULL AUTO_INCREMENT COMMENT '邮件ID',
`title` varchar(128) DEFAULT "" COMMENT '邮件标题',
`content` varchar(2048) DEFAULT "" COMMENT '邮件内容',
`items` varchar(2048) DEFAULT "{}" COMMENT '邮件附件',
`start_time` int unsigned NOT NULL DEFAULT '0' COMMENT '开始时间',
`register_time` int unsigned NOT NULL DEFAULT '0' COMMENT '注册时间',
`end_time` int unsigned NOT NULL DEFAULT '0' COMMENT '结束时间',
`mail_type` int unsigned NOT NULL DEFAULT '0' COMMENT '邮件类型',
`to_uids` varchar(2048) DEFAULT "" COMMENT '发送者ID',
PRIMARY KEY (`mail_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='系统邮件';
-- ----------------------------
-- Table structure for t_player_daily_task_data
-- ----------------------------
CREATE TABLE IF NOT EXISTS `t_server_global_data` (
`Id` int unsigned NOT NULL COMMENT '对应玩家account表中的dwUin',
`StartMileStoneSvrTime` int unsigned NOT NULL DEFAULT '0' COMMENT '里程碑时间',
`StartChampshipsSvrTime` int unsigned NOT NULL DEFAULT '0' COMMENT '锦标赛时间',
`InsertChampshipsSvrTime` int unsigned NOT NULL DEFAULT '0' COMMENT '每半小时插入玩家排行锦标赛时间',
`WaitToRank` text COMMENT '排名数据',
`Limit4CardExclude` text COMMENT '排名数据',
`Limit5CardExclude` text COMMENT '排名数据',
`CurChampshipsId` int unsigned NOT NULL DEFAULT '0' COMMENT '锦标赛全局Id',
`LastChampshipsId` int unsigned NOT NULL DEFAULT '0' COMMENT '锦标赛全局Id',
`Limit4Card` int unsigned NOT NULL DEFAULT '0' COMMENT '限时4星金卡ID',
`Limit5Card` int unsigned NOT NULL DEFAULT '0' COMMENT '限时5星金卡ID',
`LimitCardSwapTime` int unsigned NOT NULL DEFAULT '0' COMMENT '限时5星金卡ID',
`OpenSvrTime` int unsigned NOT NULL DEFAULT '0' COMMENT '锦标赛全局Id',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='存储玩家基本信息';
/*==============================================================*/
/* Table: t_player_data 系统模块表 */
/*==============================================================*/
CREATE TABLE IF NOT EXISTS t_server_mod
(
`id` int NOT NULL AUTO_INCREMENT primary key,
`key` varchar(128) DEFAULT '' COMMENT '模块key',
`mData` mediumblob DEFAULT NULL COMMENT '数据',
`updateTime` int unsigned NOT NULL DEFAULT '0' COMMENT '更新时间'
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='系统模块表';
CREATE TABLE IF NOT EXISTS `t_log_login` (
`id` int NOT NULL AUTO_INCREMENT primary key,
`dwUin` int unsigned NOT NULL COMMENT '对应玩家account表中的dwUin',
`type` int unsigned NOT NULL DEFAULT '0' COMMENT '日志类型',
`event` varchar(512) DEFAULT '' COMMENT '事件名',
`timestamp` int DEFAULT 0 COMMENT '时间错',
KEY (`dwUin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='玩家日志';
CREATE TABLE IF NOT EXISTS `t_log_evnet` (
`id` int NOT NULL AUTO_INCREMENT primary key,
`dwUin` int unsigned NOT NULL COMMENT '对应玩家account表中的dwUin',
`type` int unsigned NOT NULL DEFAULT '0' COMMENT '日志类型',
`event` varchar(512) DEFAULT '' COMMENT '事件名',
`param` varchar(512) DEFAULT '' COMMENT '参数',
`timestamp` int DEFAULT 0 COMMENT '时间错',
KEY (`dwUin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='玩家日志';
CREATE TABLE IF NOT EXISTS `t_log_item` (
`dwUin` int unsigned NOT NULL COMMENT '对应玩家account表中的dwUin',
`type` int unsigned NOT NULL DEFAULT '0' COMMENT '日志类型',
`event` varchar(512) DEFAULT '' COMMENT '事件名',
`timestamp` int DEFAULT 0 COMMENT '时间错',
KEY (`dwUin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='玩家日志';

31
tool/app.ini Normal file
View File

@ -0,0 +1,31 @@
[app]
app_name = pet_home
app_id = 1001
app_path = /data/pet_home_devops/Goleaf
conf_path = /etc/pet_home
[server]
tcp_addr = 3600
ws_addr = 3700
listen_addr = 3800
max_conn = 1000
remote = pethome.bywaystudios.com
[mysql]
mysql_user = root
mysql_password = root
mysql_host = 172.20.0.5
mysql_port = 3306
[redis]
redis_host = 172.20.0.6
redis_port = 6379
[cluster]
center_id = 0
center_host = pethome.bywaystudios.com
center_port = 3800
[log]
log_level = debug
te_log_path = /var/log/pet_home/te

7
tool/go.mod Normal file
View File

@ -0,0 +1,7 @@
module tool
go 1.23.1
require gopkg.in/ini.v1 v1.67.0
require github.com/stretchr/testify v1.10.0 // indirect

10
tool/go.sum Normal file
View File

@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

393
tool/main.go Normal file
View File

@ -0,0 +1,393 @@
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"gopkg.in/ini.v1"
)
// GOOS=linux GOARCH=amd64 go build -o /data/pet_home_devops/Goleaf/tool/tool main.go
var help = `
Usage: app.ini [options]
start start the server
stop stop the server
restart restart the server
status get the server status
`
var cfg *ini.File
var FuncMap map[string]func() error
var dirPath string
var app_path string
func main() {
FuncMap = make(map[string]func() error)
// 检查是否提供了命令行参数
if len(os.Args) < 2 {
log.Fatal(help)
}
var err error
// 获取当前文件的绝对路径
execPath, err := os.Executable()
if err != nil {
log.Fatal(err)
}
absPath, err := filepath.Abs(execPath)
if err != nil {
log.Fatal(err)
}
// 获取当前文件的绝对路径的文件夹路径
dirPath = filepath.Dir(absPath)
// 加载 app.ini 文件
cfg, err = ini.Load(dirPath + "/app.ini")
if err != nil {
log.Fatal(err)
}
app_path = cfg.Section("app").Key("app_path").String()
register("start", start)
register("stop", stop)
register("install", install)
register("status", status)
register("restart", restart)
funcName := os.Args[1]
if f, ok := FuncMap[funcName]; ok {
e := f()
if e != nil {
log.Fatal(e)
}
} else {
log.Fatal(help)
}
}
func register(name string, f func() error) {
FuncMap[name] = f
}
func install() error {
fmt.Println("install")
if len(os.Args) < 4 {
log.Fatal("请输入要安装的服务类型和区号 install [center|node] 区号")
}
serverType := os.Args[2]
zone := os.Args[3]
if serverType != "center" && serverType != "node" {
log.Fatal("请输入正确的服务类型 center|node")
}
AppName := cfg.Section("app").Key("app_name").String()
// 生成服务名
serviceName := fmt.Sprintf("%s_%s_%s", AppName, serverType, zone)
// 判断文件夹是否存在
folderPath := fmt.Sprintf("%s/zone/%s", app_path, serviceName)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
err := os.MkdirAll(folderPath, os.ModePerm)
if err != nil {
log.Fatal(err)
}
fmt.Printf("文件夹 %s 创建成功\n", folderPath)
} else {
fmt.Printf("文件夹 %s 已存在\n", folderPath)
}
// 生成配置文件
configPath := fmt.Sprintf("%s/server.json", folderPath)
file, err := os.Create(configPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
zoneId, _ := strconv.Atoi(zone)
cf, confs := createConfigFile(zoneId, serverType)
file.WriteString(confs)
// 读取 SQL 文件内容并替换 %database% 字符串
sqlFilePath := fmt.Sprintf("%s/tool/Merge_Pet.sql", app_path)
sqlContent, err := os.ReadFile(sqlFilePath)
if err != nil {
log.Fatal(err)
}
dbName := cf["DbName"].(string)
modifiedSQL := strings.ReplaceAll(string(sqlContent), "%database%", dbName)
// 将修改后的内容写入临时文件
tempSQLFile, err := os.CreateTemp("", "modified_*.sql")
if err != nil {
log.Fatal(err)
}
// defer os.Remove(tempSQLFile.Name())
_, err = tempSQLFile.WriteString(modifiedSQL)
if err != nil {
log.Fatal(err)
}
tempSQLFile.Close()
// 创建数据库
dbUser := cfg.Section("mysql").Key("mysql_user").String()
dbPassword := cfg.Section("mysql").Key("mysql_password").String()
dbHost := cfg.Section("mysql").Key("mysql_host").String()
dbPort := cfg.Section("mysql").Key("mysql_port").String()
fmt.Println("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, "-e", fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbName))
createDBCmd := exec.Command("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, "-e", fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbName))
createDBCmd.Stdout = os.Stdout
createDBCmd.Stderr = os.Stderr
err = createDBCmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Println("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, dbName, "-e", fmt.Sprintf("source %s", tempSQLFile.Name()))
// 执行修改后的 SQL 文件
cmd := exec.Command("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, dbName, "-e", fmt.Sprintf("source %s", tempSQLFile.Name()))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
cmd = exec.Command("mkdir", cf["LogPath"].(string))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Printf("SQL 文件 %s 执行成功\n", sqlFilePath)
fmt.Printf("配置文件 %s 创建成功\n", configPath)
return nil
}
func createConfigFile(Id int, Type string) (map[string]interface{}, string) {
conf := make(map[string]interface{})
conf["LogLevel"] = cfg.Section("log").Key("log_level").String()
TcpStartAddr, _ := cfg.Section("server").Key("tcp_addr").Int()
conf["TcpAddr"] = fmt.Sprintf(":%d", TcpStartAddr+Id)
WsStartAddr, _ := cfg.Section("server").Key("ws_addr").Int()
conf["WsAddr"] = fmt.Sprintf(":%d", WsStartAddr+Id)
ListenAddr, _ := cfg.Section("server").Key("listen_addr").Int()
conf["MySqlAddr"] = cfg.Section("mysql").Key("mysql_host").String()
conf["MySqlUsr"] = cfg.Section("mysql").Key("mysql_user").String()
conf["MySqlPwd"] = cfg.Section("mysql").Key("mysql_password").String()
conf["MySqlPort"] = cfg.Section("mysql").Key("mysql_port").String()
MaxConnNum, _ := cfg.Section("server").Key("max_conn").Int()
conf["MaxConnNum"] = MaxConnNum
app_name := cfg.Section("app").Key("app_name").String()
conf["LogPath"] = fmt.Sprintf("%s/zone/%s_%s_%d/log/", app_path, app_name, Type, Id)
conf["DbName"] = fmt.Sprintf("%s_%d", app_name, Id)
conf["TELOGDIR"] = cfg.Section("log").Key("te_log_path").String()
conf["GameName"] = app_name
AppId, _ := cfg.Section("app").Key("app_id").Int()
conf["GameId"] = AppId
conf["ServerType"] = Type
conf["ServerID"] = Id
conf["ServerOpenTime"] = "2028-01-01 00:00:00"
conf["ServerName"] = fmt.Sprintf("%s_%d", app_name, Id)
conf["ServerStatus"] = 1
CenterId, _ := cfg.Section("app").Key("center_id").Int()
conf["ServerCenter"] = CenterId
conf["RedisAddr"] = cfg.Section("redis").Key("redis_host").String()
conf["RedisPort"] = cfg.Section("redis").Key("redis_port").String()
conf["GameConfPath"] = app_path + "/config/"
conf["RemoteAddr"] = fmt.Sprintf("%s:%d", cfg.Section("server").Key("remote").String(), ListenAddr+Id) // 服务器地址
conf["ListenAddr"] = fmt.Sprintf(":%d", ListenAddr+Id)
conf["CenterAddr"] = fmt.Sprintf("%s:%s", cfg.Section("cluster").Key("center_host").String(), cfg.Section("cluster").Key("center_port").String()) // 服务器地址
b, _ := json.MarshalIndent(conf, "", " ")
return conf, string(b)
}
func start() error {
fmt.Println("start")
err := status()
if err == nil {
return err
}
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
cmdName := app_path + "/main"
cmdArgs := []string{fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)}
// 创建命令
cmd := exec.Command(cmdName, cmdArgs...)
cmd.SysProcAttr = &syscall.SysProcAttr{}
// 创建管道
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
cmd.Env = os.Environ()
// 打开输出文件
outfile, err := os.OpenFile(fmt.Sprintf("%s/zone/%s_%s_%s/output.log", app_path, app_name, NodeType, Zone), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer outfile.Close()
// 重定向标准输出和标准错误到文件
cmd.Stdout = outfile
cmd.Stderr = outfile
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
// 打印进程号
fmt.Printf("进程 %d 已启动\n", cmd.Process.Pid)
// 发送命令到子进程
go func() {
time.Sleep(2 * time.Second) // 等待子进程启动
_, err := stdin.Write([]byte("your_command\n"))
if err != nil {
log.Fatal(err)
}
stdin.Close()
}()
// 释放与子进程相关的资源
err = cmd.Process.Release()
if err != nil {
log.Fatal(err)
}
return nil
}
func stop() error {
fmt.Println("stop")
err := status()
if err != nil {
return err
}
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
processName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
// 示例进程名称
// 获取进程号
pid, err := getPidByArgs(processName)
if err != nil {
log.Fatal(err)
}
// 查找进程
process, err := os.FindProcess(pid)
if err != nil {
log.Fatal(err)
}
// 关闭进程
err = process.Kill()
if err != nil {
log.Fatal(err)
}
// // 等待子进程退出
// _, err = process.Wait()
// if err != nil {
// log.Fatal(err)
// }
fmt.Printf("进程 %d 已关闭\n", pid)
return nil
}
// func getPidByName(name string) (int, error) {
// cmd := exec.Command("pgrep", name)
// output, err := cmd.Output()
// if err != nil {
// return 0, err
// }
// // 解析输出,获取第一个匹配的进程号
// outputStr := strings.TrimSpace(string(output))
// pidStr := strings.Split(outputStr, "\n")[0]
// pid, err := strconv.Atoi(pidStr)
// if err != nil {
// return 0, err
// }
// return pid, nil
// }
func getPidByArgs(args string) (int, error) {
cmd := exec.Command("pgrep", "-f", args)
output, err := cmd.Output()
if err != nil {
return 0, err
}
// 解析输出,获取第一个匹配的进程号
outputStr := strings.TrimSpace(string(output))
pidStr := strings.Split(outputStr, "\n")[0]
pid, err := strconv.Atoi(pidStr)
if err != nil {
return 0, err
}
return pid, nil
}
func status() error {
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
processName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
// 示例进程名称
// 获取进程号
pid, err := getPidByArgs(processName)
if err != nil {
return fmt.Errorf("进程 %s_%s 未启动", NodeType, Zone)
}
// 查找进程
_, err = os.FindProcess(pid)
if err != nil {
return fmt.Errorf("进程 %s_%s 未启动", NodeType, Zone)
}
fmt.Printf("节点 %s_%s 启动中, 进程号 %d\n", NodeType, Zone, pid)
return nil
}
func restart() error {
fmt.Println("restart")
err := stop()
if err != nil {
return err
}
for status() == nil {
time.Sleep(1 * time.Second)
}
err = start()
if err != nil {
return err
}
return nil
}

BIN
tool/tool Normal file

Binary file not shown.

102
tool/tool.py Normal file
View File

@ -0,0 +1,102 @@
import os
import sys
import subprocess
import configparser
help_message = """
Usage: app.ini [options]
start start the server
stop stop the server
restart restart the server
status get the server status
"""
cfg = None
FuncMap = {}
dir_path = ""
app_path = ""
def main():
global cfg, dir_path, app_path
if len(sys.argv) < 2:
print(help_message)
sys.exit(1)
# 获取当前文件的绝对路径
exec_path = os.path.abspath(sys.argv[0])
dir_path = os.path.dirname(exec_path)
# print(f"当前文件的绝对路径的文件夹路径: {dir_path}")
# 加载 app.ini 文件
cfg = configparser.ConfigParser()
cfg.read(os.path.join(dir_path, "app.ini"))
app_path = cfg.get("app", "app_path")
register("start", start)
register("stop", stop)
func_name = sys.argv[1]
if func_name in FuncMap:
FuncMap[func_name]()
else:
print(help_message)
sys.exit(1)
def register(name, func):
FuncMap[name] = func
def start():
print("start")
NodeType = sys.argv[2]
Zone = sys.argv[3]
app_name = cfg.get("app", "app_name")
cmd_name = app_path + "/main"
cmd_args = [f"{app_path}/zone/{app_name}_{NodeType}_{Zone}/server.json"]
# 创建命令
cmd = [cmd_name] + cmd_args
print(cmd)
# 启动命令
process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, start_new_session=True)
print(f"p {process.pid} s")
# 获取命令输出
stdout, stderr = process.communicate()
print("e:", stdout.decode('utf-8', errors='ignore'))
print("e2:", stderr.decode('utf-8', errors='ignore'))
def stop():
print("stop")
NodeType = sys.argv[2]
Zone = sys.argv[3]
app_name = cfg.get("app", "app_name")
process_args = f"{app_path}/zone/{app_name}_{NodeType}_{Zone}/server.json"
# 获取进程号
pid = get_pid_by_args(process_args)
if pid is None:
print("未找到进程")
sys.exit(1)
# 关闭进程
try:
os.kill(pid, 9)
print(f"进程 {pid} 已关闭")
except OSError as e:
print(f"关闭进程失败: {e}")
sys.exit(1)
def get_pid_by_args(args):
try:
output = subprocess.check_output(["pgrep", "-f", args])
pid_str = output.decode().strip().split("\n")[0]
return int(pid_str)
except subprocess.CalledProcessError:
return None
if __name__ == "__main__":
main()