From 8e41b2084e715a8e536afdd2cd06c7bdc6a6057f Mon Sep 17 00:00:00 2001 From: xc Date: Fri, 26 Sep 2025 09:55:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BF=AE=E6=94=B9=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mblog/app/config.go | 12 ++ mblog/app/myserver.go | 414 ++++++++++++++++++++++++++++++++++++++++++ mblog/go.mod | 21 +++ mblog/go.sum | 73 ++++++++ mblog/mbmain.go | 49 +++++ 5 files changed, 569 insertions(+) create mode 100644 mblog/app/config.go create mode 100644 mblog/app/myserver.go create mode 100644 mblog/go.mod create mode 100644 mblog/go.sum create mode 100644 mblog/mbmain.go diff --git a/mblog/app/config.go b/mblog/app/config.go new file mode 100644 index 0000000..920021b --- /dev/null +++ b/mblog/app/config.go @@ -0,0 +1,12 @@ +package app + +type Config struct { + Host string + Port int + User string + Pass string + ServerId int + + LogFile string + Position int +} diff --git a/mblog/app/myserver.go b/mblog/app/myserver.go new file mode 100644 index 0000000..0885d30 --- /dev/null +++ b/mblog/app/myserver.go @@ -0,0 +1,414 @@ +package app + +import ( + "bufio" + "bytes" + "context" + "crypto/sha1" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "os" + "time" + + "github.com/go-mysql-org/go-mysql/replication" +) + +const ( + MinProtocolVersion byte = 10 + + OK_HEADER byte = 0x00 + ERR_HEADER byte = 0xff + EOF_HEADER byte = 0xfe + LocalInFile_HEADER byte = 0xfb +) + +const MaxPayloadLength = 1<<24 - 1 + +type Server struct { + Cfg *Config + Ctx context.Context + conn net.Conn + io *PacketIo + registerSucc bool +} + +func (s *Server) Run() { + defer func() { + s.Quit() + }() + + s.dump() +} + +func (s *Server) dump() { + err := s.handshake() + if err != nil { + panic(err) + } + s.invalidChecksum() + fmt.Println("dump ...") + s.register() + s.writeDumpCommand() + parser := replication.NewBinlogParser() + for { + //time.Sleep(2 * time.Second) + //s.query("select 1") + + data, err := s.io.readPacket() + if err != nil || len(data) == 0 { + continue + } + + //s.Quit() + + if data[0] == OK_HEADER { + //skip ok + data = data[1:] + if e, err := parser.Parse(data); err == nil { + e.Dump(os.Stdout) + } else { + fmt.Println(err) + } + } else { + s.io.HandleError(data) + } + } +} + +func (s *Server) invalidChecksum() { + sql := `SET @master_binlog_checksum='NONE'` + if err := s.query(sql); err != nil { + fmt.Println(err) + } + //must read from tcp connection , either will be blocked + _, _ = s.io.readPacket() +} + +func (s *Server) handshake() error { + conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", s.Cfg.Host, s.Cfg.Port), 10*time.Second) + if err != nil { + return err + } + + tc := conn.(*net.TCPConn) + tc.SetKeepAlive(true) + tc.SetNoDelay(true) + s.conn = tc + + s.io = &PacketIo{} + s.io.r = bufio.NewReaderSize(s.conn, 16*1024) + s.io.w = tc + + data, err := s.io.readPacket() + if err != nil { + return err + } + + if data[0] == ERR_HEADER { + return errors.New("error packet") + } + + if data[0] < MinProtocolVersion { + return fmt.Errorf("version is too lower, current:%d", data[0]) + } + + pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + connId := uint32(binary.LittleEndian.Uint32(data[pos : pos+4])) + pos += 4 + salt := data[pos : pos+8] + + pos += 8 + 1 + capability := uint32(binary.LittleEndian.Uint16(data[pos : pos+2])) + + pos += 2 + + var status uint16 + var pluginName string + if len(data) > pos { + //skip charset + pos++ + status = binary.LittleEndian.Uint16(data[pos : pos+2]) + pos += 2 + capability = uint32(binary.LittleEndian.Uint16(data[pos:pos+2]))<<16 | capability + pos += 2 + + pos += 10 + 1 + salt = append(salt, data[pos:pos+12]...) + pos += 13 + + if end := bytes.IndexByte(data[pos:], 0x00); end != -1 { + pluginName = string(data[pos : pos+end]) + } else { + pluginName = string(data[pos:]) + } + } + + fmt.Printf("conn_id:%v, status:%d, plugin:%v\n", connId, status, pluginName) + + //write + capability = 500357 + length := 4 + 4 + 1 + 23 + length += len(s.Cfg.User) + 1 + + pass := []byte(s.Cfg.Pass) + auth := calPassword(salt[:20], pass) + length += 1 + len(auth) + data = make([]byte, length+4) + + data[4] = byte(capability) + data[5] = byte(capability >> 8) + data[6] = byte(capability >> 16) + data[7] = byte(capability >> 24) + + //utf8 + data[12] = byte(33) + pos = 13 + 23 + if len(s.Cfg.User) > 0 { + pos += copy(data[pos:], s.Cfg.User) + } + + pos++ + data[pos] = byte(len(auth)) + pos += 1 + copy(data[pos+1:], auth) + + err = s.io.writePacket(data) + if err != nil { + return fmt.Errorf("write auth packet error") + } + + pk, err := s.io.readPacket() + if err != nil { + return err + } + + if pk[0] == OK_HEADER { + fmt.Println("handshake ok ") + return nil + } else if pk[0] == ERR_HEADER { + s.io.HandleError(pk) + return errors.New("handshake error ") + } + + return nil +} + +func (s *Server) writeDumpCommand() { + s.io.seq = 0 + data := make([]byte, 4+1+4+2+4+len(s.Cfg.LogFile)) + pos := 4 + data[pos] = 18 //dump binlog + pos++ + binary.LittleEndian.PutUint32(data[pos:], uint32(s.Cfg.Position)) + pos += 4 + + //dump command flag + binary.LittleEndian.PutUint16(data[pos:], 0) + pos += 2 + + binary.LittleEndian.PutUint32(data[pos:], uint32(s.Cfg.ServerId)) + pos += 4 + + copy(data[pos:], s.Cfg.LogFile) + + s.io.writePacket(data) + //ok + res, _ := s.io.readPacket() + if res[0] == OK_HEADER { + fmt.Println("send dump command return ok.") + } else { + s.io.HandleError(res) + } +} + +func (s *Server) register() { + s.io.seq = 0 + hostname, _ := os.Hostname() + data := make([]byte, 4+1+4+1+len(hostname)+1+len(s.Cfg.User)+1+len(s.Cfg.Pass)+2+4+4) + pos := 4 + data[pos] = 21 //register slave command + pos++ + binary.LittleEndian.PutUint32(data[pos:], uint32(s.Cfg.ServerId)) + pos += 4 + + data[pos] = uint8(len(hostname)) + pos++ + n := copy(data[pos:], hostname) + pos += n + + data[pos] = uint8(len(s.Cfg.User)) + pos++ + n = copy(data[pos:], s.Cfg.User) + pos += n + + data[pos] = uint8(len(s.Cfg.Pass)) + pos++ + n = copy(data[pos:], s.Cfg.Pass) + pos += n + + binary.LittleEndian.PutUint16(data[pos:], uint16(s.Cfg.Port)) + pos += 2 + + binary.LittleEndian.PutUint32(data[pos:], 0) + pos += 4 + + //master id = 0 + binary.LittleEndian.PutUint32(data[pos:], 0) + + s.io.writePacket(data) + + //ok + res, _ := s.io.readPacket() + if res[0] == OK_HEADER { + fmt.Println("register success.") + s.registerSucc = true + } else { + s.io.HandleError(data) + } +} + +func (s *Server) writeCommand(command byte) { + s.io.seq = 0 + _ = s.io.writePacket([]byte{ + 0x01, //1 byte long + 0x00, + 0x00, + 0x00, //seq + command, + }) +} + +func (s *Server) query(q string) error { + s.io.seq = 0 + length := len(q) + 1 + data := make([]byte, length+4) + data[4] = 3 + copy(data[5:], q) + return s.io.writePacket(data) +} + +func (s *Server) Quit() { + //quit + s.writeCommand(byte(1)) + //maybe only close + if err := s.conn.Close(); nil != err { + fmt.Printf("error in close :%v\n", err) + } +} + +type PacketIo struct { + r *bufio.Reader + w io.Writer + seq uint8 +} + +func (p *PacketIo) readPacket() ([]byte, error) { + //to read header + header := []byte{0, 0, 0, 0} + if _, err := io.ReadFull(p.r, header); err != nil { + return nil, err + } + + length := int(uint32(header[0]) | uint32(header[1])<<8 | uint32(header[2])<<16) + if length == 0 { + p.seq++ + return []byte{}, nil + } + + if length == 1 { + return nil, fmt.Errorf("invalid payload") + } + + seq := uint8(header[3]) + if p.seq != seq { + return nil, fmt.Errorf("invalid seq %d", seq) + } + + p.seq++ + data := make([]byte, length) + if _, err := io.ReadFull(p.r, data); err != nil { + return nil, err + } else { + if length < MaxPayloadLength { + return data, nil + } + var buf []byte + buf, err = p.readPacket() + if err != nil { + return nil, err + } + if len(buf) == 0 { + return data, nil + } else { + return append(data, buf...), nil + } + } +} + +func (p *PacketIo) writePacket(data []byte) error { + length := len(data) - 4 + if length >= MaxPayloadLength { + data[0] = 0xff + data[1] = 0xff + data[2] = 0xff + data[3] = p.seq + + if n, err := p.w.Write(data[:4+MaxPayloadLength]); err != nil { + return fmt.Errorf("write find error") + } else if n != 4+MaxPayloadLength { + return fmt.Errorf("not equal max pay load length") + } else { + p.seq++ + length -= MaxPayloadLength + data = data[MaxPayloadLength:] + } + } + + data[0] = byte(length) + data[1] = byte(length >> 8) + data[2] = byte(length >> 16) + data[3] = p.seq + + if n, err := p.w.Write(data); err != nil { + return errors.New("write find error") + } else if n != len(data) { + return errors.New("not equal length") + } else { + p.seq++ + return nil + } +} + +func calPassword(scramble, password []byte) []byte { + crypt := sha1.New() + crypt.Write(password) + stage1 := crypt.Sum(nil) + + crypt.Reset() + crypt.Write(stage1) + hash := crypt.Sum(nil) + + crypt.Reset() + crypt.Write(scramble) + crypt.Write(hash) + scramble = crypt.Sum(nil) + + for i := range scramble { + scramble[i] ^= stage1[i] + } + + return scramble +} + +func (p *PacketIo) HandleError(data []byte) { + pos := 1 + code := binary.LittleEndian.Uint16(data[pos:]) + pos += 2 + pos++ + state := string(data[pos : pos+5]) + pos += 5 + msg := string(data[pos:]) + fmt.Printf("code:%d, state:%s, msg:%s\n", code, state, msg) +} diff --git a/mblog/go.mod b/mblog/go.mod new file mode 100644 index 0000000..214261a --- /dev/null +++ b/mblog/go.mod @@ -0,0 +1,21 @@ +module mblog + +go 1.24.6 + +require github.com/go-mysql-org/go-mysql v1.13.0 + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/pingcap/errors v0.11.5-0.20250318082626-8f80e5cb09ec // indirect + github.com/pingcap/log v1.1.1-0.20241212030209-7e3ff8601a2a // indirect + github.com/pingcap/tidb/pkg/parser v0.0.0-20250421232622-526b2c79173d // indirect + github.com/shopspring/decimal v1.2.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/text v0.24.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect +) diff --git a/mblog/go.sum b/mblog/go.sum new file mode 100644 index 0000000..f3853a6 --- /dev/null +++ b/mblog/go.sum @@ -0,0 +1,73 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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-mysql-org/go-mysql v1.13.0 h1:Hlsa5x1bX/wBFtMbdIOmb6YzyaVNBWnwrb8gSIEPMDc= +github.com/go-mysql-org/go-mysql v1.13.0/go.mod h1:FQxw17uRbFvMZFK+dPtIPufbU46nBdrGaxOw0ac9MFs= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pingcap/errors v0.11.5-0.20250318082626-8f80e5cb09ec h1:3EiGmeJWoNixU+EwllIn26x6s4njiWRXewdx2zlYa84= +github.com/pingcap/errors v0.11.5-0.20250318082626-8f80e5cb09ec/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= +github.com/pingcap/log v1.1.1-0.20241212030209-7e3ff8601a2a h1:WIhmJBlNGmnCWH6TLMdZfNEDaiU8cFpZe3iaqDbQ0M8= +github.com/pingcap/log v1.1.1-0.20241212030209-7e3ff8601a2a/go.mod h1:ORfBOFp1eteu2odzsyaxI+b8TzJwgjwyQcGhI+9SfEA= +github.com/pingcap/tidb/pkg/parser v0.0.0-20250421232622-526b2c79173d h1:3Ej6eTuLZp25p3aH/EXdReRHY12hjZYs3RrGp7iLdag= +github.com/pingcap/tidb/pkg/parser v0.0.0-20250421232622-526b2c79173d/go.mod h1:+8feuexTKcXHZF/dkDfvCwEyBAmgb4paFc3/WeYV2eE= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +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/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= diff --git a/mblog/mbmain.go b/mblog/mbmain.go new file mode 100644 index 0000000..7146a82 --- /dev/null +++ b/mblog/mbmain.go @@ -0,0 +1,49 @@ +package main + +import ( + "flag" + "fmt" + "mblog/app" + "os" + "os/signal" + "runtime" + "syscall" +) + +var myHost = flag.String("host", "127.0.0.1", "MySQL replication host") +var myPort = flag.Int("port", 3306, "MySQL replication port") +var myUser = flag.String("user", "root", "MySQL replication user") +var myPass = flag.String("pass", "****", "MySQL replication pass") +var serverId = flag.Int("server_id", 1111, "MySQL replication server id") + +func main() { + sc := make(chan os.Signal, 1) + signal.Notify(sc, + os.Kill, + os.Interrupt, + syscall.SIGHUP, + syscall.SIGQUIT, + syscall.SIGINT, + syscall.SIGTERM, + ) + + runtime.GOMAXPROCS(runtime.NumCPU()/4 + 1) + flag.Parse() + cfg := &app.Config{ + *myHost, + *myPort, + *myUser, + *myPass, + *serverId, + "mysql-bin.000032", + 3070, + } + srv := &app.Server{Cfg: cfg} + go srv.Run() + + select { + case n := <-sc: + srv.Quit() + fmt.Printf("receive signal %v, closing", n) + } +}