├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── assets ├── 668104-20180925182815646-1209020640.png ├── 668104-20180925182816462-2110152563.png └── ys.gif ├── client ├── canal_connector.go ├── cluster_canal_connector.go ├── cluster_canal_node.go ├── doc.go ├── security_util.go └── simple_canal_connector.go ├── docker ├── docker-compose.yml ├── example │ └── instance.properties └── mysql │ ├── init │ └── init.sql │ └── mysqld.cnf ├── go.mod ├── go.sum ├── protocol ├── client_identity.go ├── doc.go ├── entry │ ├── entry_protocol.pb.go │ └── entry_protocol.proto ├── exception │ ├── canal_client_error.go │ └── doc.go ├── message.go ├── packet │ ├── canal_protocol.pb.go │ └── canal_protocol.proto └── position │ ├── doc.go │ ├── entry_position.go │ ├── log_identity.go │ ├── log_position.go │ ├── metaq_position.go │ ├── position.go │ └── time_position.go └── samples ├── cluster └── cluster_main.go ├── doc.go └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Go template 3 | # Binaries for programs and plugins 4 | *.exe 5 | *.exe~ 6 | *.dll 7 | *.so 8 | *.dylib 9 | 10 | # Test binary, built with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # Dependency directories (remove the comment below to include it) 17 | # vendor/ 18 | 19 | .vscode 20 | .idea 21 | 22 | vendor 23 | 24 | docker/var 25 | docker/canal-server-logs 26 | docker/example/meta.dat -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.14.x" 5 | 6 | go_import_path: github.com/withlin/canal-go 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # canal-go 3 | 4 | [![Build Status](https://travis-ci.org/withlin/canal-go.svg?branch=master)](https://travis-ci.org/withlin/canal-go) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/withlin/canal-go)](https://goreportcard.com/badge/github.com/withlin/canal-go) 6 | -------------------------------------------------------------------------------- /assets/668104-20180925182815646-1209020640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withlin/canal-go/3a96268e97b5dfc9ad798eeb6d44d2d20ada6d76/assets/668104-20180925182815646-1209020640.png -------------------------------------------------------------------------------- /assets/668104-20180925182816462-2110152563.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withlin/canal-go/3a96268e97b5dfc9ad798eeb6d44d2d20ada6d76/assets/668104-20180925182816462-2110152563.png -------------------------------------------------------------------------------- /assets/ys.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withlin/canal-go/3a96268e97b5dfc9ad798eeb6d44d2d20ada6d76/assets/ys.gif -------------------------------------------------------------------------------- /client/canal_connector.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package client 18 | 19 | import pb "github.com/withlin/canal-go/protocol" 20 | 21 | type CanalConnector interface { 22 | Connect() error 23 | DisConnection() error 24 | Subscribe(filter string) error 25 | UnSubscribe() error 26 | Get(batchSize int32, timeOut *int64, units *int32) (msg *pb.Message, err error) 27 | GetWithOutAck(batchSize int32, timeOut *int64, units *int32) (msg *pb.Message, err error) 28 | Ack(batchId int64) error 29 | RollBack(batchId int64) error 30 | } 31 | -------------------------------------------------------------------------------- /client/cluster_canal_connector.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "sort" 8 | "strings" 9 | "time" 10 | 11 | "github.com/go-zookeeper/zk" 12 | 13 | pb "github.com/withlin/canal-go/protocol" 14 | ) 15 | 16 | type ClusterCanalConnector struct { 17 | conn *SimpleCanalConnector 18 | canalNode *CanalClusterNode 19 | username, password, destination string 20 | soTimeOut, idleTimeOut int32 21 | filter string 22 | 23 | RetryTimes int32 24 | currentSequence string 25 | zkVersion int32 26 | 27 | Path string 28 | } 29 | 30 | const ( 31 | path = "/canal-consumer" 32 | runningFlag = byte(0) 33 | notRunningFlag = byte(0) 34 | ) 35 | 36 | func NewClusterCanalConnector(canalNode *CanalClusterNode, username string, password string, destination string, 37 | soTimeOut int32, idleTimeOut int32) (*ClusterCanalConnector, error) { 38 | 39 | destinationPath := fmt.Sprintf("%s/%s", path, destination) 40 | 41 | err := checkRootPath(canalNode.zkClient, destinationPath) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | currentSequence, err := createEphemeralSequence(canalNode.zkClient, destinationPath) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | cluster := &ClusterCanalConnector{ 52 | canalNode: canalNode, 53 | username: username, 54 | password: password, 55 | destination: destination, 56 | soTimeOut: soTimeOut, 57 | idleTimeOut: idleTimeOut, 58 | RetryTimes: 0, 59 | currentSequence: currentSequence, 60 | zkVersion: 0, 61 | Path: destinationPath, 62 | } 63 | 64 | return cluster, nil 65 | } 66 | 67 | func (cc *ClusterCanalConnector) Connect() error { 68 | log.Println("connecting canal server...") 69 | err := cc.reconnect() 70 | return err 71 | } 72 | 73 | func (cc *ClusterCanalConnector) reconnect() error { 74 | err := cc.doConnect() 75 | if err != nil { 76 | log.Println("connect canal-server failed ", err) 77 | cc.RetryTimes++ 78 | if cc.RetryTimes < 5 { 79 | time.Sleep(5 * time.Second) 80 | return cc.reconnect() 81 | } 82 | return err 83 | } 84 | cc.RetryTimes = 0 85 | 86 | return nil 87 | } 88 | 89 | func (cc *ClusterCanalConnector) doConnect() error { 90 | 91 | log.Println("connecting...") 92 | 93 | //等待成为最小的节点,最小的节点去运行 94 | err := cc.waitBecomeFirst() 95 | if err != nil { 96 | return fmt.Errorf("error wait become first zk node %s", err.Error()) 97 | } 98 | 99 | _, err = cc.canalNode.zkClient.Set(cc.Path+"/"+cc.currentSequence, []byte{runningFlag}, cc.zkVersion) 100 | if err != nil { 101 | return fmt.Errorf("error set running flag %s", err.Error()) 102 | } 103 | cc.zkVersion++ 104 | 105 | addr, port, err := cc.canalNode.GetNode() 106 | if err != nil { 107 | return fmt.Errorf("error get zk current node path %s", err.Error()) 108 | } 109 | 110 | connector := NewSimpleCanalConnector(addr, port, cc.username, cc.password, cc.destination, cc.soTimeOut, cc.idleTimeOut) 111 | cc.conn = connector 112 | 113 | err = connector.Connect() 114 | if err != nil { 115 | return err 116 | } 117 | 118 | log.Println("connected to ", addr, " success") 119 | 120 | return nil 121 | } 122 | 123 | func (cc *ClusterCanalConnector) DisConnection() error { 124 | if cc.conn != nil { 125 | cc.conn.DisConnection() 126 | _, stat, _ := cc.canalNode.zkClient.Get(cc.Path + "/" + cc.currentSequence) 127 | err := cc.canalNode.zkClient.Delete(cc.Path+"/"+cc.currentSequence, stat.Version) 128 | if err != nil { 129 | return fmt.Errorf("error delete temp consumer path %s", err.Error()) 130 | } 131 | cc.conn = nil 132 | } 133 | 134 | return nil 135 | } 136 | 137 | func (cc *ClusterCanalConnector) Subscribe(filter string) error { 138 | err := cc.conn.Subscribe(filter) 139 | if err != nil { 140 | err = cc.reconnect() 141 | if err != nil { 142 | return err 143 | } 144 | return cc.Subscribe(filter) 145 | } 146 | 147 | return nil 148 | } 149 | 150 | func (cc *ClusterCanalConnector) UnSubscribe() error { 151 | err := cc.conn.UnSubscribe() 152 | if err != nil { 153 | err = cc.reconnect() 154 | if err != nil { 155 | return err 156 | } 157 | return cc.UnSubscribe() 158 | } 159 | 160 | return nil 161 | } 162 | 163 | func (cc *ClusterCanalConnector) GetWithOutAck(batchSize int32, timeOut *int64, units *int32) (msg *pb.Message, err error) { 164 | msg, err = cc.conn.GetWithOutAck(batchSize, timeOut, units) 165 | if err != nil { 166 | err = cc.reconnect() 167 | if err != nil { 168 | return nil, err 169 | } 170 | return cc.conn.GetWithOutAck(batchSize, timeOut, units) 171 | } 172 | 173 | return 174 | } 175 | 176 | func (cc *ClusterCanalConnector) Get(batchSize int32, timeOut *int64, units *int32) (msg *pb.Message, err error) { 177 | msg, err = cc.conn.Get(batchSize, timeOut, units) 178 | if err != nil { 179 | err = cc.reconnect() 180 | if err != nil { 181 | return nil, err 182 | } 183 | return cc.conn.Get(batchSize, timeOut, units) 184 | } 185 | 186 | return 187 | } 188 | 189 | func (cc *ClusterCanalConnector) Ack(batchId int64) error { 190 | err := cc.conn.Ack(batchId) 191 | if err != nil { 192 | err = cc.reconnect() 193 | if err != nil { 194 | return err 195 | } 196 | return cc.Ack(batchId) 197 | } 198 | 199 | return nil 200 | } 201 | 202 | func (cc *ClusterCanalConnector) RollBack(batchId int64) error { 203 | err := cc.conn.RollBack(batchId) 204 | if err != nil { 205 | err = cc.reconnect() 206 | if err != nil { 207 | return err 208 | } 209 | return cc.RollBack(batchId) 210 | } 211 | 212 | return nil 213 | } 214 | 215 | func createEphemeralSequence(zkClient *zk.Conn, destinationPath string) (string, error) { 216 | node, err := zkClient.Create(destinationPath+"/", []byte{notRunningFlag}, zk.FlagEphemeral|zk.FlagSequence, 217 | zk.WorldACL(zk.PermAll)) 218 | if err != nil { 219 | return "", err 220 | } 221 | split := strings.Split(node, "/") 222 | currentSequence := split[len(split)-1] 223 | return currentSequence, nil 224 | } 225 | 226 | func checkRootPath(zkClient *zk.Conn, destinationPath string) error { 227 | rootExists, _, err := zkClient.Exists(path) 228 | if err != nil { 229 | return err 230 | } 231 | if !rootExists { 232 | _, err := zkClient.Create(path, []byte{}, 0, zk.WorldACL(zk.PermAll)) 233 | if err != nil { 234 | return err 235 | } 236 | } 237 | exists, _, err := zkClient.Exists(destinationPath) 238 | if err != nil { 239 | return err 240 | } 241 | if !exists { 242 | _, err := zkClient.Create(destinationPath, []byte{}, 0, zk.WorldACL(zk.PermAll)) 243 | if err != nil { 244 | return err 245 | } 246 | } 247 | return nil 248 | } 249 | 250 | func (cc *ClusterCanalConnector) waitBecomeFirst() error { 251 | zkClient := cc.canalNode.zkClient 252 | children, _, err := zkClient.Children(cc.Path) 253 | if err != nil { 254 | return err 255 | } 256 | 257 | if len(children) == 0 { 258 | return errors.New("没有子节点") 259 | } 260 | 261 | sort.Strings(children) 262 | 263 | if cc.currentSequence != children[0] { 264 | noSelf := true 265 | 266 | for i, child := range children { 267 | if cc.currentSequence == child { 268 | noSelf = false 269 | previousPath := cc.Path + "/" + children[i-1] 270 | //阻塞等待上一个比他小的节点删除 271 | log.Println("waiting") 272 | err := waitDelete(zkClient, previousPath) 273 | if err != nil { 274 | return err 275 | } 276 | log.Println("waited") 277 | 278 | return cc.waitBecomeFirst() 279 | } 280 | } 281 | 282 | if noSelf { 283 | //以防万一 284 | cc.currentSequence, err = createEphemeralSequence(zkClient, cc.Path) 285 | if err != nil { 286 | return err 287 | } 288 | // 再次创建临时节点成功后将版本设置为0,不然后续更新节点会出现版本冲突 289 | cc.zkVersion = 0 290 | return cc.waitBecomeFirst() 291 | } 292 | } 293 | 294 | return nil 295 | } 296 | 297 | // 等待上一个比他小的节点失联,失联后等待10秒,10秒后还没恢复则确认已被删除 298 | func waitDelete(zkClient *zk.Conn, previousPath string) error { 299 | existsW, _, events, err := zkClient.ExistsW(previousPath) 300 | if err != nil { 301 | return err 302 | } 303 | 304 | if existsW { 305 | event := <-events 306 | if event.Type != zk.EventNodeDeleted { 307 | return waitDelete(zkClient, previousPath) 308 | } else { 309 | //等待10秒再查看监听的节点是否确实不存在了,以防只是网络延迟造成的掉线 310 | time.Sleep(10 * time.Second) 311 | return waitDelete(zkClient, previousPath) 312 | } 313 | } 314 | 315 | return nil 316 | } 317 | -------------------------------------------------------------------------------- /client/cluster_canal_node.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "math/rand" 8 | "strconv" 9 | "strings" 10 | "time" 11 | 12 | "github.com/go-zookeeper/zk" 13 | ) 14 | 15 | /** 16 | 修改说明:去掉CanalClusterNode里的ServerRunningData和Event,不再监听,改为随用随取,因为不能确定取到值后就进行链接,会造成数据不一致, 17 | 如果当前Server挂了,连接会断开,到时候直接重连就可以了 18 | */ 19 | 20 | type ServerRunningData struct { 21 | Cid int64 22 | Address string 23 | Active bool 24 | } 25 | 26 | type CanalClusterNode struct { 27 | zkClient *zk.Conn 28 | destination string 29 | clusterAddress []string 30 | clusterEvent <-chan zk.Event 31 | } 32 | 33 | const ( 34 | cluster_path = "/otter/canal/destinations/%s/cluster" 35 | running_path = "/otter/canal/destinations/%s/running" 36 | ) 37 | 38 | func NewCanalClusterNode(destination string, zkServer []string, timeout time.Duration) (canalNode *CanalClusterNode, err error) { 39 | var ( 40 | zkClient *zk.Conn 41 | cluster []string 42 | clusterEV <-chan zk.Event 43 | ) 44 | 45 | if zkClient, _, err = zk.Connect(zkServer, timeout); err != nil { 46 | log.Printf("zk.Connect err:%v", err) 47 | return 48 | } 49 | if cluster, _, clusterEV, err = zkClient.ChildrenW(fmt.Sprintf(cluster_path, destination)); err != nil { 50 | log.Printf("zkClient.ChildrenW err:%v", err) 51 | return 52 | } 53 | 54 | canalNode = &CanalClusterNode{ 55 | zkClient: zkClient, 56 | destination: destination, 57 | clusterEvent: clusterEV, 58 | } 59 | 60 | canalNode.InitClusters(cluster) 61 | 62 | return 63 | } 64 | 65 | func (canalNode *CanalClusterNode) InitClusters(addressList []string) { 66 | rand.Shuffle(len(addressList), func(a, b int) { 67 | addressList[a], addressList[b] = addressList[b], addressList[a] 68 | }) 69 | canalNode.clusterAddress = addressList 70 | } 71 | 72 | func (canalNode *CanalClusterNode) GetNode() (addr string, port int, err error) { 73 | 74 | serverRunningData, err := canalNode.getRunningServer() 75 | if err != nil { 76 | return "", 0, err 77 | } 78 | 79 | s := strings.Split(serverRunningData.Address, ":") 80 | if len(s) == 2 && s[0] != "" { 81 | port, err = strconv.Atoi(s[1]) 82 | if err != nil { 83 | return "", 0, fmt.Errorf("error canal cluster server %s", serverRunningData.Address) 84 | } 85 | 86 | addr = s[0] 87 | return 88 | } else { 89 | return "", 0, fmt.Errorf("error canal cluster server %s", serverRunningData.Address) 90 | } 91 | } 92 | 93 | func (canalNode *CanalClusterNode) getRunningServer() (ServerRunningData, error) { 94 | serverInfo := ServerRunningData{} 95 | 96 | body, _, err := canalNode.zkClient.Get(fmt.Sprintf(running_path, canalNode.destination)) 97 | if err != nil { 98 | log.Printf("zkClient.GetW err:%v", err) 99 | return serverInfo, err 100 | } 101 | 102 | err = json.Unmarshal(body, &serverInfo) 103 | if err != nil { 104 | log.Printf("json.Unmarshal err:%v", err) 105 | return serverInfo, err 106 | } 107 | 108 | return serverInfo, nil 109 | } 110 | -------------------------------------------------------------------------------- /client/doc.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package client 18 | -------------------------------------------------------------------------------- /client/security_util.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/hex" 6 | ) 7 | 8 | func Scramble411(data *[]byte,seed *[]byte) []byte { 9 | crypt := sha1.New() 10 | 11 | //stage1 12 | crypt.Write(*data) 13 | stage1 := crypt.Sum(nil) 14 | 15 | //stage2 16 | crypt.Reset() 17 | crypt.Write(stage1) 18 | stage2 := crypt.Sum(nil) 19 | 20 | //stage3 21 | crypt.Reset() 22 | crypt.Write(*seed) 23 | crypt.Write(stage2) 24 | stage3 := crypt.Sum(nil) 25 | for i := range stage3 { 26 | stage3[i] ^= stage1[i] 27 | } 28 | 29 | return stage3 30 | } 31 | 32 | func ByteSliceToHexString(data []byte) string { 33 | return hex.EncodeToString(data) 34 | } 35 | -------------------------------------------------------------------------------- /client/simple_canal_connector.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package client 18 | 19 | import ( 20 | "bufio" 21 | "bytes" 22 | "encoding/binary" 23 | "fmt" 24 | pb "github.com/withlin/canal-go/protocol" 25 | "io" 26 | "net" 27 | "strconv" 28 | "sync" 29 | 30 | pbp "github.com/withlin/canal-go/protocol/packet" 31 | 32 | "google.golang.org/protobuf/proto" 33 | ) 34 | 35 | type SimpleCanalConnector struct { 36 | Address string 37 | Port int 38 | UserName string 39 | PassWord string 40 | SoTime int32 41 | IdleTimeOut int32 42 | ClientIdentity pb.ClientIdentity 43 | Connected bool 44 | Running bool 45 | Filter string 46 | RollbackOnConnect bool 47 | LazyParseEntry bool 48 | conn net.Conn 49 | mutex sync.Mutex 50 | } 51 | 52 | const ( 53 | versionErr string = "unsupported version at this client." 54 | handshakeErr = "expect handshake but found other type." 55 | packetAckErr = "unexpected packet type when ack is expected" 56 | ) 57 | 58 | // NewSimpleCanalConnector 创建SimpleCanalConnector实例 59 | func NewSimpleCanalConnector(address string, port int, username string, password string, destination string, soTimeOut int32, idleTimeOut int32) *SimpleCanalConnector { 60 | s := &SimpleCanalConnector{ 61 | Address: address, 62 | Port: port, 63 | UserName: username, 64 | PassWord: password, 65 | ClientIdentity: pb.ClientIdentity{Destination: destination, ClientId: 1001}, 66 | SoTime: soTimeOut, 67 | IdleTimeOut: idleTimeOut, 68 | RollbackOnConnect: true, 69 | } 70 | return s 71 | 72 | } 73 | 74 | // Connect 连接Canal-server 75 | func (c *SimpleCanalConnector) Connect() error { 76 | if c.Connected { 77 | return nil 78 | } 79 | 80 | if c.Running { 81 | return nil 82 | } 83 | 84 | err := c.doConnect() 85 | if err != nil { 86 | return err 87 | } 88 | if c.Filter != "" { 89 | c.Subscribe(c.Filter) 90 | } 91 | 92 | if c.RollbackOnConnect { 93 | c.waitClientRunning() 94 | 95 | c.RollBack(0) 96 | } 97 | 98 | c.Connected = true 99 | return nil 100 | 101 | } 102 | 103 | // quitelyClose 优雅关闭 104 | func (c *SimpleCanalConnector) quitelyClose() { 105 | if c.conn != nil { 106 | c.conn.Close() 107 | } 108 | } 109 | 110 | // DisConnection 关闭连接 111 | func (c *SimpleCanalConnector) DisConnection() error { 112 | if c.RollbackOnConnect && c.Connected == true { 113 | c.RollBack(0) 114 | } 115 | c.Connected = false 116 | c.quitelyClose() 117 | return nil 118 | } 119 | 120 | // doConnect 去连接Canal-Server 121 | func (c *SimpleCanalConnector) doConnect() error { 122 | address := c.Address + ":" + fmt.Sprintf("%d", c.Port) 123 | con, err := net.Dial("tcp", address) 124 | if err != nil { 125 | return err 126 | } 127 | c.conn = con 128 | 129 | p := new(pbp.Packet) 130 | data, err := c.readNextPacket() 131 | if err != nil { 132 | return err 133 | } 134 | err = proto.Unmarshal(data, p) 135 | if err != nil { 136 | return err 137 | } 138 | if p != nil { 139 | if p.GetVersion() != 1 { 140 | return fmt.Errorf(versionErr) 141 | } 142 | 143 | if p.GetType() != pbp.PacketType_HANDSHAKE { 144 | return fmt.Errorf(handshakeErr) 145 | } 146 | 147 | handshake := &pbp.Handshake{} 148 | seed := &handshake.Seeds 149 | err = proto.Unmarshal(p.GetBody(), handshake) 150 | if err != nil { 151 | return err 152 | } 153 | bytePas := []byte(c.PassWord) 154 | pas := []byte(ByteSliceToHexString(Scramble411(&bytePas, seed))) 155 | ca := &pbp.ClientAuth{ 156 | Username: c.UserName, 157 | Password: pas, 158 | NetReadTimeoutPresent: &pbp.ClientAuth_NetReadTimeout{NetReadTimeout: c.IdleTimeOut}, 159 | NetWriteTimeoutPresent: &pbp.ClientAuth_NetWriteTimeout{NetWriteTimeout: c.IdleTimeOut}, 160 | } 161 | caByteArray, _ := proto.Marshal(ca) 162 | packet := &pbp.Packet{ 163 | Type: pbp.PacketType_CLIENTAUTHENTICATION, 164 | Body: caByteArray, 165 | } 166 | 167 | packArray, _ := proto.Marshal(packet) 168 | 169 | c.WriteWithHeader(packArray) 170 | 171 | pp, err := c.readNextPacket() 172 | if err != nil { 173 | return err 174 | } 175 | pk := &pbp.Packet{} 176 | 177 | err = proto.Unmarshal(pp, pk) 178 | if err != nil { 179 | return err 180 | } 181 | 182 | if pk.Type != pbp.PacketType_ACK { 183 | return fmt.Errorf(packetAckErr) 184 | } 185 | 186 | ackBody := &pbp.Ack{} 187 | err = proto.Unmarshal(pk.GetBody(), ackBody) 188 | if err != nil { 189 | return err 190 | } 191 | if ackBody.GetErrorCode() > 0 { 192 | 193 | return fmt.Errorf("something goes wrong when doing authentication:%s", ackBody.GetErrorMessage()) 194 | } 195 | 196 | c.Connected = true 197 | 198 | } 199 | return nil 200 | 201 | } 202 | 203 | // GetWithOutAck 获取数据不Ack 204 | func (c *SimpleCanalConnector) GetWithOutAck(batchSize int32, timeOut *int64, units *int32) (*pb.Message, error) { 205 | c.waitClientRunning() 206 | if !c.Running { 207 | return nil, nil 208 | } 209 | var size int32 210 | 211 | if batchSize < 0 { 212 | size = 1000 213 | } else { 214 | size = batchSize 215 | } 216 | var time *int64 217 | var t int64 218 | t = -1 219 | if timeOut == nil { 220 | time = &t 221 | } else { 222 | time = timeOut 223 | } 224 | var i int32 225 | i = -1 226 | if units == nil { 227 | units = &i 228 | } 229 | get := new(pbp.Get) 230 | get.AutoAckPresent = &pbp.Get_AutoAck{AutoAck: false} 231 | get.Destination = c.ClientIdentity.Destination 232 | get.ClientId = strconv.Itoa(c.ClientIdentity.ClientId) 233 | get.FetchSize = size 234 | get.TimeoutPresent = &pbp.Get_Timeout{Timeout: *time} 235 | get.UnitPresent = &pbp.Get_Unit{Unit: *units} 236 | 237 | getBody, err := proto.Marshal(get) 238 | if err != nil { 239 | return nil, err 240 | } 241 | packet := new(pbp.Packet) 242 | packet.Type = pbp.PacketType_GET 243 | packet.Body = getBody 244 | pa, err := proto.Marshal(packet) 245 | if err != nil { 246 | return nil, err 247 | } 248 | c.WriteWithHeader(pa) 249 | message, err := c.receiveMessages() 250 | if err != nil { 251 | return nil, err 252 | } 253 | return message, nil 254 | } 255 | 256 | // Get 获取数据并且Ack数据 257 | func (c *SimpleCanalConnector) Get(batchSize int32, timeOut *int64, units *int32) (*pb.Message, error) { 258 | message, err := c.GetWithOutAck(batchSize, timeOut, units) 259 | if err != nil { 260 | return nil, err 261 | } 262 | err = c.Ack(message.Id) 263 | if err != nil { 264 | return nil, err 265 | } 266 | return message, nil 267 | } 268 | 269 | // UnSubscribe 取消订阅 270 | func (c *SimpleCanalConnector) UnSubscribe() error { 271 | c.waitClientRunning() 272 | if c.Running { 273 | return nil 274 | } 275 | 276 | us := new(pbp.Unsub) 277 | us.Destination = c.ClientIdentity.Destination 278 | us.ClientId = strconv.Itoa(c.ClientIdentity.ClientId) 279 | 280 | unSub, err := proto.Marshal(us) 281 | if err != nil { 282 | return err 283 | } 284 | 285 | pa := new(pbp.Packet) 286 | pa.Type = pbp.PacketType_UNSUBSCRIPTION 287 | pa.Body = unSub 288 | 289 | pack, err := proto.Marshal(pa) 290 | c.WriteWithHeader(pack) 291 | 292 | p, err := c.readNextPacket() 293 | if err != nil { 294 | return err 295 | } 296 | pa = nil 297 | err = proto.Unmarshal(p, pa) 298 | if err != nil { 299 | return err 300 | } 301 | ack := new(pbp.Ack) 302 | err = proto.Unmarshal(pa.Body, ack) 303 | if err != nil { 304 | return err 305 | } 306 | if ack.GetErrorCode() > 0 { 307 | errMsg := ack.GetErrorMessage() 308 | return fmt.Errorf("failed to unSubscribe with reason:%s", errMsg) 309 | } 310 | return nil 311 | } 312 | 313 | // receiveMessages 接收Canal-Server返回的消息体 314 | func (c *SimpleCanalConnector) receiveMessages() (*pb.Message, error) { 315 | data, err := c.readNextPacket() 316 | if err != nil { 317 | return nil, err 318 | } 319 | return pb.Decode(data, c.LazyParseEntry) 320 | } 321 | 322 | // Ack Ack Canal-server的数据(就是昨晚某些逻辑操作后删除canal-server端的数据) 323 | func (c *SimpleCanalConnector) Ack(batchId int64) error { 324 | c.waitClientRunning() 325 | if !c.Running { 326 | return nil 327 | } 328 | 329 | ca := new(pbp.ClientAck) 330 | ca.Destination = c.ClientIdentity.Destination 331 | ca.ClientId = strconv.Itoa(c.ClientIdentity.ClientId) 332 | ca.BatchId = batchId 333 | 334 | clientAck, err := proto.Marshal(ca) 335 | if err != nil { 336 | return err 337 | } 338 | pa := new(pbp.Packet) 339 | pa.Type = pbp.PacketType_CLIENTACK 340 | pa.Body = clientAck 341 | pack, err := proto.Marshal(pa) 342 | if err != nil { 343 | return err 344 | } 345 | c.WriteWithHeader(pack) 346 | return nil 347 | 348 | } 349 | 350 | // RollBack 回滚操作 351 | func (c *SimpleCanalConnector) RollBack(batchId int64) error { 352 | c.waitClientRunning() 353 | cb := new(pbp.ClientRollback) 354 | cb.Destination = c.ClientIdentity.Destination 355 | cb.ClientId = strconv.Itoa(c.ClientIdentity.ClientId) 356 | cb.BatchId = batchId 357 | 358 | clientBollBack, err := proto.Marshal(cb) 359 | if err != nil { 360 | return err 361 | } 362 | 363 | pa := new(pbp.Packet) 364 | pa.Type = pbp.PacketType_CLIENTROLLBACK 365 | pa.Body = clientBollBack 366 | pack, err := proto.Marshal(pa) 367 | if err != nil { 368 | return err 369 | } 370 | c.WriteWithHeader(pack) 371 | return nil 372 | } 373 | 374 | // readHeaderLength 读取protobuf的header字节,该字节存取了你要读的package的长度 375 | func (c *SimpleCanalConnector) readHeaderLength() int { 376 | buf := make([]byte, 4) 377 | c.conn.Read(buf) 378 | bytesBuffer := bytes.NewBuffer(buf) 379 | var x int32 380 | binary.Read(bytesBuffer, binary.BigEndian, &x) 381 | return int(x) 382 | } 383 | 384 | // readNextPacket 通过长度去读取数据包 385 | func (c *SimpleCanalConnector) readNextPacket() ([]byte, error) { 386 | c.mutex.Lock() 387 | defer func() { 388 | c.mutex.Unlock() 389 | }() 390 | rdr := bufio.NewReader(c.conn) 391 | data := make([]byte, 0, 4*1024) 392 | n, err := io.ReadFull(rdr, data[:4]) 393 | if err != nil { 394 | return nil, err 395 | } 396 | data = data[:n] 397 | dataLen := binary.BigEndian.Uint32(data) 398 | if uint64(dataLen) > uint64(cap(data)) { 399 | data = make([]byte, 0, dataLen) 400 | } 401 | n, err = io.ReadFull(rdr, data[:dataLen]) 402 | if err != nil { 403 | return nil, err 404 | } 405 | data = data[:n] 406 | return data, nil 407 | } 408 | 409 | // WriteWithHeader 写数据包的header+body 410 | func (c *SimpleCanalConnector) WriteWithHeader(body []byte) { 411 | c.mutex.Lock() 412 | lenth := len(body) 413 | bytes := getWriteHeaderBytes(lenth) 414 | c.conn.Write(bytes) 415 | c.conn.Write(body) 416 | c.mutex.Unlock() 417 | } 418 | 419 | // getWriteHeaderBytes 获取要写数据的长度 420 | func getWriteHeaderBytes(lenth int) []byte { 421 | x := int32(lenth) 422 | bytesBuffer := bytes.NewBuffer([]byte{}) 423 | binary.Write(bytesBuffer, binary.BigEndian, x) 424 | return bytesBuffer.Bytes() 425 | } 426 | 427 | // Subscribe 订阅 428 | func (c *SimpleCanalConnector) Subscribe(filter string) error { 429 | c.waitClientRunning() 430 | if !c.Running { 431 | return nil 432 | } 433 | body, _ := proto.Marshal(&pbp.Sub{Destination: c.ClientIdentity.Destination, ClientId: strconv.Itoa(c.ClientIdentity.ClientId), Filter: filter}) 434 | pack := new(pbp.Packet) 435 | pack.Type = pbp.PacketType_SUBSCRIPTION 436 | pack.Body = body 437 | 438 | packet, _ := proto.Marshal(pack) 439 | c.WriteWithHeader(packet) 440 | 441 | p := new(pbp.Packet) 442 | 443 | paBytes, err := c.readNextPacket() 444 | if err != nil { 445 | return err 446 | } 447 | err = proto.Unmarshal(paBytes, p) 448 | if err != nil { 449 | return err 450 | } 451 | ack := new(pbp.Ack) 452 | err = proto.Unmarshal(p.Body, ack) 453 | if err != nil { 454 | return err 455 | } 456 | 457 | if ack.GetErrorCode() > 0 { 458 | return fmt.Errorf("failed to subscribe with reason:%s", ack.GetErrorMessage()) 459 | } 460 | 461 | c.Filter = filter 462 | 463 | return nil 464 | } 465 | 466 | // waitClientRunning 等待客户端跑 467 | func (c *SimpleCanalConnector) waitClientRunning() { 468 | c.Running = true 469 | } 470 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3.1' 3 | 4 | services: 5 | mysql: 6 | image: mysql:8.0 7 | container_name: mysql-8.0 8 | ports: 9 | - "4406:3306" 10 | environment: 11 | - MYSQL_ROOT_PASSWORD=000000 12 | networks: 13 | - canalsharp 14 | volumes: 15 | - ./mysql/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf 16 | - ./var/lib/mysql:/var/lib/mysql 17 | - ./mysql/init/:/docker-entrypoint-initdb.d/ 18 | 19 | 20 | canal-server: 21 | image: canal/canal-server:v1.1.7 22 | container_name: canal-server 23 | ports: 24 | - "11111:11111" 25 | networks: 26 | - canalsharp 27 | volumes: 28 | - ./example/:/home/admin/canal-server/conf/example/ 29 | - ./canal-server-logs/:/home/admin/canal-server/logs/ 30 | depends_on: 31 | - mysql 32 | 33 | networks: 34 | 35 | canalsharp: 36 | driver: bridge 37 | 38 | -------------------------------------------------------------------------------- /docker/example/instance.properties: -------------------------------------------------------------------------------- 1 | 2 | ################################################# 3 | ## mysql serverId , v1.0.26+ will autoGen 4 | # canal.instance.mysql.slaveId=0 5 | 6 | # enable gtid use true/false 7 | canal.instance.gtidon=false 8 | 9 | # position info 10 | canal.instance.master.address=mysql:3306 11 | canal.instance.master.journal.name= 12 | canal.instance.master.position= 13 | canal.instance.master.timestamp= 14 | canal.instance.master.gtid= 15 | 16 | # rds oss binlog 17 | canal.instance.rds.accesskey= 18 | canal.instance.rds.secretkey= 19 | canal.instance.rds.instanceId= 20 | 21 | # table meta tsdb info 22 | canal.instance.tsdb.enable=false 23 | #canal.instance.tsdb.url=jdbc:mysql://127.0.0.1:3306/canal_tsdb 24 | #canal.instance.tsdb.dbUsername=canal 25 | #canal.instance.tsdb.dbPassword=canal 26 | 27 | #canal.instance.standby.address = 28 | #canal.instance.standby.journal.name = 29 | #canal.instance.standby.position = 30 | #canal.instance.standby.timestamp = 31 | #canal.instance.standby.gtid= 32 | 33 | # username/password 34 | canal.instance.dbUsername=canal 35 | canal.instance.dbPassword=canal 36 | canal.instance.connectionCharset=UTF-8 37 | 38 | # table regex 39 | canal.instance.filter.regex=.*\\..* 40 | # table black regex 41 | canal.instance.filter.black.regex= 42 | ################################################# 43 | -------------------------------------------------------------------------------- /docker/mysql/init/init.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE USER canal IDENTIFIED BY 'canal'; 3 | GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ; 4 | FLUSH PRIVILEGES; 5 | 6 | CREATE DATABASE `test`; 7 | 8 | USE test; 9 | 10 | 11 | CREATE TABLE `test` ( 12 | `id` INT(11) NOT NULL, 13 | `name` VARCHAR(50) NOT NULL 14 | ) 15 | ENGINE=InnoDB 16 | ; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docker/mysql/mysqld.cnf: -------------------------------------------------------------------------------- 1 | # 2 | # The MySQL database server configuration file. 3 | # 4 | # You can copy this to one of: 5 | # - "/etc/mysql/my.cnf" to set global options, 6 | # - "~/.my.cnf" to set user-specific options. 7 | # 8 | # One can use all long options that the program supports. 9 | # Run program with --help to get a list of available options and with 10 | # --print-defaults to see which it would actually understand and use. 11 | # 12 | # For explanations see 13 | # http://dev.mysql.com/doc/mysql/en/server-system-variables.html 14 | 15 | # This will be passed to all mysql clients 16 | # It has been reported that passwords should be enclosed with ticks/quotes 17 | # escpecially if they contain "#" chars... 18 | # Remember to edit /etc/mysql/debian.cnf when changing the socket location. 19 | 20 | # Here is entries for some specific programs 21 | # The following values assume you have at least 32M ram 22 | 23 | [mysqld_safe] 24 | socket = /var/run/mysqld/mysqld.sock 25 | nice = 0 26 | 27 | [mysqld] 28 | # 29 | # * Basic Settings 30 | # 31 | user = mysql 32 | pid-file = /var/run/mysqld/mysqld.pid 33 | socket = /var/run/mysqld/mysqld.sock 34 | port = 3306 35 | basedir = /usr 36 | datadir = /var/lib/mysql 37 | tmpdir = /tmp 38 | lc-messages-dir = /usr/share/mysql 39 | skip-external-locking 40 | # 41 | # Instead of skip-networking the default is now to listen only on 42 | # localhost which is more compatible and is not less secure. 43 | bind-address = 0.0.0.0 44 | # 45 | # * Fine Tuning 46 | # 47 | key_buffer_size = 16M 48 | max_allowed_packet = 16M 49 | thread_stack = 192K 50 | thread_cache_size = 8 51 | # This replaces the startup script and checks MyISAM tables if needed 52 | # the first time they are touched 53 | myisam-recover-options = BACKUP 54 | #max_connections = 100 55 | #table_cache = 64 56 | #thread_concurrency = 10 57 | # 58 | # * Query Cache Configuration 59 | # 60 | query_cache_limit = 1M 61 | query_cache_size = 16M 62 | # 63 | # * Logging and Replication 64 | # 65 | # Both location gets rotated by the cronjob. 66 | # Be aware that this log type is a performance killer. 67 | # As of 5.1 you can enable the log at runtime! 68 | #general_log_file = /var/log/mysql/mysql.log 69 | #general_log = 1 70 | # 71 | # Error log - should be very few entries. 72 | # 73 | log_error = /var/log/mysql/error.log 74 | # 75 | # Here you can see queries with especially long duration 76 | #log_slow_queries = /var/log/mysql/mysql-slow.log 77 | #long_query_time = 2 78 | #log-queries-not-using-indexes 79 | # 80 | # The following can be used as easy to replay backup logs or for replication. 81 | # note: if you are setting up a replication slave, see README.Debian about 82 | # other settings you may need to change. 83 | server-id = 1 84 | log_bin = /var/log/mysql/mysql-bin 85 | binlog-format=ROW 86 | expire_logs_days = 10 87 | max_binlog_size = 100M 88 | #binlog_do_db = include_database_name 89 | #binlog_ignore_db = include_database_name 90 | # 91 | # * InnoDB 92 | # 93 | # InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. 94 | # Read the manual for more InnoDB related options. There are many! 95 | # 96 | # * Security Features 97 | # 98 | # Read the manual, too, if you want chroot! 99 | # chroot = /var/lib/mysql/ 100 | # 101 | # For generating SSL certificates I recommend the OpenSSL GUI "tinyca". 102 | # 103 | # ssl-ca=/etc/mysql/cacert.pem 104 | # ssl-cert=/etc/mysql/server-cert.pem 105 | # ssl-key=/etc/mysql/server-key.pem 106 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/withlin/canal-go 2 | 3 | require ( 4 | github.com/go-zookeeper/zk v1.0.3 5 | google.golang.org/protobuf v1.33.0 6 | ) 7 | 8 | require github.com/google/go-cmp v0.6.0 // indirect 9 | 10 | go 1.21 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= 2 | github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= 3 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 4 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 5 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 6 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 7 | -------------------------------------------------------------------------------- /protocol/client_identity.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package protocol 18 | 19 | type ClientIdentity struct { 20 | Destination string 21 | ClientId int 22 | Filter string 23 | } 24 | 25 | func (c *ClientIdentity) ClientIdentity(destination string, clientId int) *ClientIdentity { 26 | c.ClientId = clientId 27 | c.Destination = destination 28 | return c 29 | } 30 | -------------------------------------------------------------------------------- /protocol/doc.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package protocol 18 | -------------------------------------------------------------------------------- /protocol/entry/entry_protocol.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.31.0 4 | // protoc v4.24.4 5 | // source: entry_protocol.proto 6 | 7 | package entry 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | // *打散后的事件类型,主要用于标识事务的开始,变更数据,结束* 24 | type EntryType int32 25 | 26 | const ( 27 | EntryType_ENTRYTYPECOMPATIBLEPROTO2 EntryType = 0 28 | EntryType_TRANSACTIONBEGIN EntryType = 1 29 | EntryType_ROWDATA EntryType = 2 30 | EntryType_TRANSACTIONEND EntryType = 3 31 | // * 心跳类型,内部使用,外部暂不可见,可忽略 * 32 | EntryType_HEARTBEAT EntryType = 4 33 | EntryType_GTIDLOG EntryType = 5 34 | ) 35 | 36 | // Enum value maps for EntryType. 37 | var ( 38 | EntryType_name = map[int32]string{ 39 | 0: "ENTRYTYPECOMPATIBLEPROTO2", 40 | 1: "TRANSACTIONBEGIN", 41 | 2: "ROWDATA", 42 | 3: "TRANSACTIONEND", 43 | 4: "HEARTBEAT", 44 | 5: "GTIDLOG", 45 | } 46 | EntryType_value = map[string]int32{ 47 | "ENTRYTYPECOMPATIBLEPROTO2": 0, 48 | "TRANSACTIONBEGIN": 1, 49 | "ROWDATA": 2, 50 | "TRANSACTIONEND": 3, 51 | "HEARTBEAT": 4, 52 | "GTIDLOG": 5, 53 | } 54 | ) 55 | 56 | func (x EntryType) Enum() *EntryType { 57 | p := new(EntryType) 58 | *p = x 59 | return p 60 | } 61 | 62 | func (x EntryType) String() string { 63 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 64 | } 65 | 66 | func (EntryType) Descriptor() protoreflect.EnumDescriptor { 67 | return file_entry_protocol_proto_enumTypes[0].Descriptor() 68 | } 69 | 70 | func (EntryType) Type() protoreflect.EnumType { 71 | return &file_entry_protocol_proto_enumTypes[0] 72 | } 73 | 74 | func (x EntryType) Number() protoreflect.EnumNumber { 75 | return protoreflect.EnumNumber(x) 76 | } 77 | 78 | // Deprecated: Use EntryType.Descriptor instead. 79 | func (EntryType) EnumDescriptor() ([]byte, []int) { 80 | return file_entry_protocol_proto_rawDescGZIP(), []int{0} 81 | } 82 | 83 | // * 事件类型 * 84 | type EventType int32 85 | 86 | const ( 87 | EventType_EVENTTYPECOMPATIBLEPROTO2 EventType = 0 88 | EventType_INSERT EventType = 1 89 | EventType_UPDATE EventType = 2 90 | EventType_DELETE EventType = 3 91 | EventType_CREATE EventType = 4 92 | EventType_ALTER EventType = 5 93 | EventType_ERASE EventType = 6 94 | EventType_QUERY EventType = 7 95 | EventType_TRUNCATE EventType = 8 96 | EventType_RENAME EventType = 9 97 | // *CREATE INDEX* 98 | EventType_CINDEX EventType = 10 99 | EventType_DINDEX EventType = 11 100 | EventType_GTID EventType = 12 101 | // * XA * 102 | EventType_XACOMMIT EventType = 13 103 | EventType_XAROLLBACK EventType = 14 104 | // * MASTER HEARTBEAT * 105 | EventType_MHEARTBEAT EventType = 15 106 | ) 107 | 108 | // Enum value maps for EventType. 109 | var ( 110 | EventType_name = map[int32]string{ 111 | 0: "EVENTTYPECOMPATIBLEPROTO2", 112 | 1: "INSERT", 113 | 2: "UPDATE", 114 | 3: "DELETE", 115 | 4: "CREATE", 116 | 5: "ALTER", 117 | 6: "ERASE", 118 | 7: "QUERY", 119 | 8: "TRUNCATE", 120 | 9: "RENAME", 121 | 10: "CINDEX", 122 | 11: "DINDEX", 123 | 12: "GTID", 124 | 13: "XACOMMIT", 125 | 14: "XAROLLBACK", 126 | 15: "MHEARTBEAT", 127 | } 128 | EventType_value = map[string]int32{ 129 | "EVENTTYPECOMPATIBLEPROTO2": 0, 130 | "INSERT": 1, 131 | "UPDATE": 2, 132 | "DELETE": 3, 133 | "CREATE": 4, 134 | "ALTER": 5, 135 | "ERASE": 6, 136 | "QUERY": 7, 137 | "TRUNCATE": 8, 138 | "RENAME": 9, 139 | "CINDEX": 10, 140 | "DINDEX": 11, 141 | "GTID": 12, 142 | "XACOMMIT": 13, 143 | "XAROLLBACK": 14, 144 | "MHEARTBEAT": 15, 145 | } 146 | ) 147 | 148 | func (x EventType) Enum() *EventType { 149 | p := new(EventType) 150 | *p = x 151 | return p 152 | } 153 | 154 | func (x EventType) String() string { 155 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 156 | } 157 | 158 | func (EventType) Descriptor() protoreflect.EnumDescriptor { 159 | return file_entry_protocol_proto_enumTypes[1].Descriptor() 160 | } 161 | 162 | func (EventType) Type() protoreflect.EnumType { 163 | return &file_entry_protocol_proto_enumTypes[1] 164 | } 165 | 166 | func (x EventType) Number() protoreflect.EnumNumber { 167 | return protoreflect.EnumNumber(x) 168 | } 169 | 170 | // Deprecated: Use EventType.Descriptor instead. 171 | func (EventType) EnumDescriptor() ([]byte, []int) { 172 | return file_entry_protocol_proto_rawDescGZIP(), []int{1} 173 | } 174 | 175 | // *数据库类型* 176 | type Type int32 177 | 178 | const ( 179 | Type_TYPECOMPATIBLEPROTO2 Type = 0 180 | Type_ORACLE Type = 1 181 | Type_MYSQL Type = 2 182 | Type_PGSQL Type = 3 183 | ) 184 | 185 | // Enum value maps for Type. 186 | var ( 187 | Type_name = map[int32]string{ 188 | 0: "TYPECOMPATIBLEPROTO2", 189 | 1: "ORACLE", 190 | 2: "MYSQL", 191 | 3: "PGSQL", 192 | } 193 | Type_value = map[string]int32{ 194 | "TYPECOMPATIBLEPROTO2": 0, 195 | "ORACLE": 1, 196 | "MYSQL": 2, 197 | "PGSQL": 3, 198 | } 199 | ) 200 | 201 | func (x Type) Enum() *Type { 202 | p := new(Type) 203 | *p = x 204 | return p 205 | } 206 | 207 | func (x Type) String() string { 208 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 209 | } 210 | 211 | func (Type) Descriptor() protoreflect.EnumDescriptor { 212 | return file_entry_protocol_proto_enumTypes[2].Descriptor() 213 | } 214 | 215 | func (Type) Type() protoreflect.EnumType { 216 | return &file_entry_protocol_proto_enumTypes[2] 217 | } 218 | 219 | func (x Type) Number() protoreflect.EnumNumber { 220 | return protoreflect.EnumNumber(x) 221 | } 222 | 223 | // Deprecated: Use Type.Descriptor instead. 224 | func (Type) EnumDescriptor() ([]byte, []int) { 225 | return file_entry_protocol_proto_rawDescGZIP(), []int{2} 226 | } 227 | 228 | // *************************************************************** 229 | // message model 230 | // 如果要在Enum中新增类型,确保以前的类型的下标值不变. 231 | // ************************************************************** 232 | type Entry struct { 233 | state protoimpl.MessageState 234 | sizeCache protoimpl.SizeCache 235 | unknownFields protoimpl.UnknownFields 236 | 237 | // *协议头部信息* 238 | Header *Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` 239 | // /**打散后的事件类型**/ [default = ROWDATA] 240 | // 241 | // Types that are assignable to EntryTypePresent: 242 | // 243 | // *Entry_EntryType 244 | EntryTypePresent isEntry_EntryTypePresent `protobuf_oneof:"entryType_present"` 245 | // *传输的二进制数组* 246 | StoreValue []byte `protobuf:"bytes,3,opt,name=storeValue,proto3" json:"storeValue,omitempty"` 247 | } 248 | 249 | func (x *Entry) Reset() { 250 | *x = Entry{} 251 | if protoimpl.UnsafeEnabled { 252 | mi := &file_entry_protocol_proto_msgTypes[0] 253 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 254 | ms.StoreMessageInfo(mi) 255 | } 256 | } 257 | 258 | func (x *Entry) String() string { 259 | return protoimpl.X.MessageStringOf(x) 260 | } 261 | 262 | func (*Entry) ProtoMessage() {} 263 | 264 | func (x *Entry) ProtoReflect() protoreflect.Message { 265 | mi := &file_entry_protocol_proto_msgTypes[0] 266 | if protoimpl.UnsafeEnabled && x != nil { 267 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 268 | if ms.LoadMessageInfo() == nil { 269 | ms.StoreMessageInfo(mi) 270 | } 271 | return ms 272 | } 273 | return mi.MessageOf(x) 274 | } 275 | 276 | // Deprecated: Use Entry.ProtoReflect.Descriptor instead. 277 | func (*Entry) Descriptor() ([]byte, []int) { 278 | return file_entry_protocol_proto_rawDescGZIP(), []int{0} 279 | } 280 | 281 | func (x *Entry) GetHeader() *Header { 282 | if x != nil { 283 | return x.Header 284 | } 285 | return nil 286 | } 287 | 288 | func (m *Entry) GetEntryTypePresent() isEntry_EntryTypePresent { 289 | if m != nil { 290 | return m.EntryTypePresent 291 | } 292 | return nil 293 | } 294 | 295 | func (x *Entry) GetEntryType() EntryType { 296 | if x, ok := x.GetEntryTypePresent().(*Entry_EntryType); ok { 297 | return x.EntryType 298 | } 299 | return EntryType_ENTRYTYPECOMPATIBLEPROTO2 300 | } 301 | 302 | func (x *Entry) GetStoreValue() []byte { 303 | if x != nil { 304 | return x.StoreValue 305 | } 306 | return nil 307 | } 308 | 309 | type isEntry_EntryTypePresent interface { 310 | isEntry_EntryTypePresent() 311 | } 312 | 313 | type Entry_EntryType struct { 314 | EntryType EntryType `protobuf:"varint,2,opt,name=entryType,proto3,enum=com.alibaba.otter.canal.protocol.EntryType,oneof"` 315 | } 316 | 317 | func (*Entry_EntryType) isEntry_EntryTypePresent() {} 318 | 319 | // *message Header* 320 | type Header struct { 321 | state protoimpl.MessageState 322 | sizeCache protoimpl.SizeCache 323 | unknownFields protoimpl.UnknownFields 324 | 325 | // [default = 1] 326 | // 327 | // Types that are assignable to VersionPresent: 328 | // 329 | // *Header_Version 330 | VersionPresent isHeader_VersionPresent `protobuf_oneof:"version_present"` 331 | // *binlog/redolog 文件名* 332 | LogfileName string `protobuf:"bytes,2,opt,name=logfileName,proto3" json:"logfileName,omitempty"` 333 | // *binlog/redolog 文件的偏移位置* 334 | LogfileOffset int64 `protobuf:"varint,3,opt,name=logfileOffset,proto3" json:"logfileOffset,omitempty"` 335 | // *服务端serverId* 336 | ServerId int64 `protobuf:"varint,4,opt,name=serverId,proto3" json:"serverId,omitempty"` 337 | // * 变更数据的编码 * 338 | ServerenCode string `protobuf:"bytes,5,opt,name=serverenCode,proto3" json:"serverenCode,omitempty"` 339 | // *变更数据的执行时间 * 340 | ExecuteTime int64 `protobuf:"varint,6,opt,name=executeTime,proto3" json:"executeTime,omitempty"` 341 | // [default = MYSQL] 342 | // 343 | // Types that are assignable to SourceTypePresent: 344 | // 345 | // *Header_SourceType 346 | SourceTypePresent isHeader_SourceTypePresent `protobuf_oneof:"sourceType_present"` 347 | // * 变更数据的schemaname* 348 | SchemaName string `protobuf:"bytes,8,opt,name=schemaName,proto3" json:"schemaName,omitempty"` 349 | // *变更数据的tablename* 350 | TableName string `protobuf:"bytes,9,opt,name=tableName,proto3" json:"tableName,omitempty"` 351 | // *每个event的长度* 352 | EventLength int64 `protobuf:"varint,10,opt,name=eventLength,proto3" json:"eventLength,omitempty"` 353 | // [default = UPDATE] 354 | // 355 | // Types that are assignable to EventTypePresent: 356 | // 357 | // *Header_EventType 358 | EventTypePresent isHeader_EventTypePresent `protobuf_oneof:"eventType_present"` 359 | // *预留扩展* 360 | Props []*Pair `protobuf:"bytes,12,rep,name=props,proto3" json:"props,omitempty"` 361 | // *当前事务的gitd* 362 | Gtid string `protobuf:"bytes,13,opt,name=gtid,proto3" json:"gtid,omitempty"` 363 | } 364 | 365 | func (x *Header) Reset() { 366 | *x = Header{} 367 | if protoimpl.UnsafeEnabled { 368 | mi := &file_entry_protocol_proto_msgTypes[1] 369 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 370 | ms.StoreMessageInfo(mi) 371 | } 372 | } 373 | 374 | func (x *Header) String() string { 375 | return protoimpl.X.MessageStringOf(x) 376 | } 377 | 378 | func (*Header) ProtoMessage() {} 379 | 380 | func (x *Header) ProtoReflect() protoreflect.Message { 381 | mi := &file_entry_protocol_proto_msgTypes[1] 382 | if protoimpl.UnsafeEnabled && x != nil { 383 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 384 | if ms.LoadMessageInfo() == nil { 385 | ms.StoreMessageInfo(mi) 386 | } 387 | return ms 388 | } 389 | return mi.MessageOf(x) 390 | } 391 | 392 | // Deprecated: Use Header.ProtoReflect.Descriptor instead. 393 | func (*Header) Descriptor() ([]byte, []int) { 394 | return file_entry_protocol_proto_rawDescGZIP(), []int{1} 395 | } 396 | 397 | func (m *Header) GetVersionPresent() isHeader_VersionPresent { 398 | if m != nil { 399 | return m.VersionPresent 400 | } 401 | return nil 402 | } 403 | 404 | func (x *Header) GetVersion() int32 { 405 | if x, ok := x.GetVersionPresent().(*Header_Version); ok { 406 | return x.Version 407 | } 408 | return 0 409 | } 410 | 411 | func (x *Header) GetLogfileName() string { 412 | if x != nil { 413 | return x.LogfileName 414 | } 415 | return "" 416 | } 417 | 418 | func (x *Header) GetLogfileOffset() int64 { 419 | if x != nil { 420 | return x.LogfileOffset 421 | } 422 | return 0 423 | } 424 | 425 | func (x *Header) GetServerId() int64 { 426 | if x != nil { 427 | return x.ServerId 428 | } 429 | return 0 430 | } 431 | 432 | func (x *Header) GetServerenCode() string { 433 | if x != nil { 434 | return x.ServerenCode 435 | } 436 | return "" 437 | } 438 | 439 | func (x *Header) GetExecuteTime() int64 { 440 | if x != nil { 441 | return x.ExecuteTime 442 | } 443 | return 0 444 | } 445 | 446 | func (m *Header) GetSourceTypePresent() isHeader_SourceTypePresent { 447 | if m != nil { 448 | return m.SourceTypePresent 449 | } 450 | return nil 451 | } 452 | 453 | func (x *Header) GetSourceType() Type { 454 | if x, ok := x.GetSourceTypePresent().(*Header_SourceType); ok { 455 | return x.SourceType 456 | } 457 | return Type_TYPECOMPATIBLEPROTO2 458 | } 459 | 460 | func (x *Header) GetSchemaName() string { 461 | if x != nil { 462 | return x.SchemaName 463 | } 464 | return "" 465 | } 466 | 467 | func (x *Header) GetTableName() string { 468 | if x != nil { 469 | return x.TableName 470 | } 471 | return "" 472 | } 473 | 474 | func (x *Header) GetEventLength() int64 { 475 | if x != nil { 476 | return x.EventLength 477 | } 478 | return 0 479 | } 480 | 481 | func (m *Header) GetEventTypePresent() isHeader_EventTypePresent { 482 | if m != nil { 483 | return m.EventTypePresent 484 | } 485 | return nil 486 | } 487 | 488 | func (x *Header) GetEventType() EventType { 489 | if x, ok := x.GetEventTypePresent().(*Header_EventType); ok { 490 | return x.EventType 491 | } 492 | return EventType_EVENTTYPECOMPATIBLEPROTO2 493 | } 494 | 495 | func (x *Header) GetProps() []*Pair { 496 | if x != nil { 497 | return x.Props 498 | } 499 | return nil 500 | } 501 | 502 | func (x *Header) GetGtid() string { 503 | if x != nil { 504 | return x.Gtid 505 | } 506 | return "" 507 | } 508 | 509 | type isHeader_VersionPresent interface { 510 | isHeader_VersionPresent() 511 | } 512 | 513 | type Header_Version struct { 514 | Version int32 `protobuf:"varint,1,opt,name=version,proto3,oneof"` 515 | } 516 | 517 | func (*Header_Version) isHeader_VersionPresent() {} 518 | 519 | type isHeader_SourceTypePresent interface { 520 | isHeader_SourceTypePresent() 521 | } 522 | 523 | type Header_SourceType struct { 524 | SourceType Type `protobuf:"varint,7,opt,name=sourceType,proto3,enum=com.alibaba.otter.canal.protocol.Type,oneof"` 525 | } 526 | 527 | func (*Header_SourceType) isHeader_SourceTypePresent() {} 528 | 529 | type isHeader_EventTypePresent interface { 530 | isHeader_EventTypePresent() 531 | } 532 | 533 | type Header_EventType struct { 534 | EventType EventType `protobuf:"varint,11,opt,name=eventType,proto3,enum=com.alibaba.otter.canal.protocol.EventType,oneof"` 535 | } 536 | 537 | func (*Header_EventType) isHeader_EventTypePresent() {} 538 | 539 | // *每个字段的数据结构* 540 | type Column struct { 541 | state protoimpl.MessageState 542 | sizeCache protoimpl.SizeCache 543 | unknownFields protoimpl.UnknownFields 544 | 545 | // *字段下标* 546 | Index int32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` 547 | // *字段java中类型* 548 | SqlType int32 `protobuf:"varint,2,opt,name=sqlType,proto3" json:"sqlType,omitempty"` 549 | // *字段名称(忽略大小写),在mysql中是没有的* 550 | Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` 551 | // *是否是主键* 552 | IsKey bool `protobuf:"varint,4,opt,name=isKey,proto3" json:"isKey,omitempty"` 553 | // *如果EventType=UPDATE,用于标识这个字段值是否有修改* 554 | Updated bool `protobuf:"varint,5,opt,name=updated,proto3" json:"updated,omitempty"` 555 | // [default = false] 556 | // 557 | // Types that are assignable to IsNullPresent: 558 | // 559 | // *Column_IsNull 560 | IsNullPresent isColumn_IsNullPresent `protobuf_oneof:"isNull_present"` 561 | // *预留扩展* 562 | Props []*Pair `protobuf:"bytes,7,rep,name=props,proto3" json:"props,omitempty"` 563 | // * 字段值,timestamp,Datetime是一个时间格式的文本 * 564 | Value string `protobuf:"bytes,8,opt,name=value,proto3" json:"value,omitempty"` 565 | // * 对应数据对象原始长度 * 566 | Length int32 `protobuf:"varint,9,opt,name=length,proto3" json:"length,omitempty"` 567 | // *字段mysql类型* 568 | MysqlType string `protobuf:"bytes,10,opt,name=mysqlType,proto3" json:"mysqlType,omitempty"` 569 | } 570 | 571 | func (x *Column) Reset() { 572 | *x = Column{} 573 | if protoimpl.UnsafeEnabled { 574 | mi := &file_entry_protocol_proto_msgTypes[2] 575 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 576 | ms.StoreMessageInfo(mi) 577 | } 578 | } 579 | 580 | func (x *Column) String() string { 581 | return protoimpl.X.MessageStringOf(x) 582 | } 583 | 584 | func (*Column) ProtoMessage() {} 585 | 586 | func (x *Column) ProtoReflect() protoreflect.Message { 587 | mi := &file_entry_protocol_proto_msgTypes[2] 588 | if protoimpl.UnsafeEnabled && x != nil { 589 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 590 | if ms.LoadMessageInfo() == nil { 591 | ms.StoreMessageInfo(mi) 592 | } 593 | return ms 594 | } 595 | return mi.MessageOf(x) 596 | } 597 | 598 | // Deprecated: Use Column.ProtoReflect.Descriptor instead. 599 | func (*Column) Descriptor() ([]byte, []int) { 600 | return file_entry_protocol_proto_rawDescGZIP(), []int{2} 601 | } 602 | 603 | func (x *Column) GetIndex() int32 { 604 | if x != nil { 605 | return x.Index 606 | } 607 | return 0 608 | } 609 | 610 | func (x *Column) GetSqlType() int32 { 611 | if x != nil { 612 | return x.SqlType 613 | } 614 | return 0 615 | } 616 | 617 | func (x *Column) GetName() string { 618 | if x != nil { 619 | return x.Name 620 | } 621 | return "" 622 | } 623 | 624 | func (x *Column) GetIsKey() bool { 625 | if x != nil { 626 | return x.IsKey 627 | } 628 | return false 629 | } 630 | 631 | func (x *Column) GetUpdated() bool { 632 | if x != nil { 633 | return x.Updated 634 | } 635 | return false 636 | } 637 | 638 | func (m *Column) GetIsNullPresent() isColumn_IsNullPresent { 639 | if m != nil { 640 | return m.IsNullPresent 641 | } 642 | return nil 643 | } 644 | 645 | func (x *Column) GetIsNull() bool { 646 | if x, ok := x.GetIsNullPresent().(*Column_IsNull); ok { 647 | return x.IsNull 648 | } 649 | return false 650 | } 651 | 652 | func (x *Column) GetProps() []*Pair { 653 | if x != nil { 654 | return x.Props 655 | } 656 | return nil 657 | } 658 | 659 | func (x *Column) GetValue() string { 660 | if x != nil { 661 | return x.Value 662 | } 663 | return "" 664 | } 665 | 666 | func (x *Column) GetLength() int32 { 667 | if x != nil { 668 | return x.Length 669 | } 670 | return 0 671 | } 672 | 673 | func (x *Column) GetMysqlType() string { 674 | if x != nil { 675 | return x.MysqlType 676 | } 677 | return "" 678 | } 679 | 680 | type isColumn_IsNullPresent interface { 681 | isColumn_IsNullPresent() 682 | } 683 | 684 | type Column_IsNull struct { 685 | IsNull bool `protobuf:"varint,6,opt,name=isNull,proto3,oneof"` 686 | } 687 | 688 | func (*Column_IsNull) isColumn_IsNullPresent() {} 689 | 690 | type RowData struct { 691 | state protoimpl.MessageState 692 | sizeCache protoimpl.SizeCache 693 | unknownFields protoimpl.UnknownFields 694 | 695 | // * 字段信息,增量数据(修改前,删除前) * 696 | BeforeColumns []*Column `protobuf:"bytes,1,rep,name=beforeColumns,proto3" json:"beforeColumns,omitempty"` 697 | // * 字段信息,增量数据(修改后,新增后) * 698 | AfterColumns []*Column `protobuf:"bytes,2,rep,name=afterColumns,proto3" json:"afterColumns,omitempty"` 699 | // *预留扩展* 700 | Props []*Pair `protobuf:"bytes,3,rep,name=props,proto3" json:"props,omitempty"` 701 | } 702 | 703 | func (x *RowData) Reset() { 704 | *x = RowData{} 705 | if protoimpl.UnsafeEnabled { 706 | mi := &file_entry_protocol_proto_msgTypes[3] 707 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 708 | ms.StoreMessageInfo(mi) 709 | } 710 | } 711 | 712 | func (x *RowData) String() string { 713 | return protoimpl.X.MessageStringOf(x) 714 | } 715 | 716 | func (*RowData) ProtoMessage() {} 717 | 718 | func (x *RowData) ProtoReflect() protoreflect.Message { 719 | mi := &file_entry_protocol_proto_msgTypes[3] 720 | if protoimpl.UnsafeEnabled && x != nil { 721 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 722 | if ms.LoadMessageInfo() == nil { 723 | ms.StoreMessageInfo(mi) 724 | } 725 | return ms 726 | } 727 | return mi.MessageOf(x) 728 | } 729 | 730 | // Deprecated: Use RowData.ProtoReflect.Descriptor instead. 731 | func (*RowData) Descriptor() ([]byte, []int) { 732 | return file_entry_protocol_proto_rawDescGZIP(), []int{3} 733 | } 734 | 735 | func (x *RowData) GetBeforeColumns() []*Column { 736 | if x != nil { 737 | return x.BeforeColumns 738 | } 739 | return nil 740 | } 741 | 742 | func (x *RowData) GetAfterColumns() []*Column { 743 | if x != nil { 744 | return x.AfterColumns 745 | } 746 | return nil 747 | } 748 | 749 | func (x *RowData) GetProps() []*Pair { 750 | if x != nil { 751 | return x.Props 752 | } 753 | return nil 754 | } 755 | 756 | // *message row 每行变更数据的数据结构* 757 | type RowChange struct { 758 | state protoimpl.MessageState 759 | sizeCache protoimpl.SizeCache 760 | unknownFields protoimpl.UnknownFields 761 | 762 | // *tableId,由数据库产生* 763 | TableId int64 `protobuf:"varint,1,opt,name=tableId,proto3" json:"tableId,omitempty"` 764 | // [default = UPDATE] 765 | // 766 | // Types that are assignable to EventTypePresent: 767 | // 768 | // *RowChange_EventType 769 | EventTypePresent isRowChange_EventTypePresent `protobuf_oneof:"eventType_present"` 770 | // [default = false] 771 | // 772 | // Types that are assignable to IsDdlPresent: 773 | // 774 | // *RowChange_IsDdl 775 | IsDdlPresent isRowChange_IsDdlPresent `protobuf_oneof:"isDdl_present"` 776 | // * ddl/query的sql语句 * 777 | Sql string `protobuf:"bytes,11,opt,name=sql,proto3" json:"sql,omitempty"` 778 | // * 一次数据库变更可能存在多行 * 779 | RowDatas []*RowData `protobuf:"bytes,12,rep,name=rowDatas,proto3" json:"rowDatas,omitempty"` 780 | // *预留扩展* 781 | Props []*Pair `protobuf:"bytes,13,rep,name=props,proto3" json:"props,omitempty"` 782 | // * ddl/query的schemaName,会存在跨库ddl,需要保留执行ddl的当前schemaName * 783 | DdlSchemaName string `protobuf:"bytes,14,opt,name=ddlSchemaName,proto3" json:"ddlSchemaName,omitempty"` 784 | } 785 | 786 | func (x *RowChange) Reset() { 787 | *x = RowChange{} 788 | if protoimpl.UnsafeEnabled { 789 | mi := &file_entry_protocol_proto_msgTypes[4] 790 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 791 | ms.StoreMessageInfo(mi) 792 | } 793 | } 794 | 795 | func (x *RowChange) String() string { 796 | return protoimpl.X.MessageStringOf(x) 797 | } 798 | 799 | func (*RowChange) ProtoMessage() {} 800 | 801 | func (x *RowChange) ProtoReflect() protoreflect.Message { 802 | mi := &file_entry_protocol_proto_msgTypes[4] 803 | if protoimpl.UnsafeEnabled && x != nil { 804 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 805 | if ms.LoadMessageInfo() == nil { 806 | ms.StoreMessageInfo(mi) 807 | } 808 | return ms 809 | } 810 | return mi.MessageOf(x) 811 | } 812 | 813 | // Deprecated: Use RowChange.ProtoReflect.Descriptor instead. 814 | func (*RowChange) Descriptor() ([]byte, []int) { 815 | return file_entry_protocol_proto_rawDescGZIP(), []int{4} 816 | } 817 | 818 | func (x *RowChange) GetTableId() int64 { 819 | if x != nil { 820 | return x.TableId 821 | } 822 | return 0 823 | } 824 | 825 | func (m *RowChange) GetEventTypePresent() isRowChange_EventTypePresent { 826 | if m != nil { 827 | return m.EventTypePresent 828 | } 829 | return nil 830 | } 831 | 832 | func (x *RowChange) GetEventType() EventType { 833 | if x, ok := x.GetEventTypePresent().(*RowChange_EventType); ok { 834 | return x.EventType 835 | } 836 | return EventType_EVENTTYPECOMPATIBLEPROTO2 837 | } 838 | 839 | func (m *RowChange) GetIsDdlPresent() isRowChange_IsDdlPresent { 840 | if m != nil { 841 | return m.IsDdlPresent 842 | } 843 | return nil 844 | } 845 | 846 | func (x *RowChange) GetIsDdl() bool { 847 | if x, ok := x.GetIsDdlPresent().(*RowChange_IsDdl); ok { 848 | return x.IsDdl 849 | } 850 | return false 851 | } 852 | 853 | func (x *RowChange) GetSql() string { 854 | if x != nil { 855 | return x.Sql 856 | } 857 | return "" 858 | } 859 | 860 | func (x *RowChange) GetRowDatas() []*RowData { 861 | if x != nil { 862 | return x.RowDatas 863 | } 864 | return nil 865 | } 866 | 867 | func (x *RowChange) GetProps() []*Pair { 868 | if x != nil { 869 | return x.Props 870 | } 871 | return nil 872 | } 873 | 874 | func (x *RowChange) GetDdlSchemaName() string { 875 | if x != nil { 876 | return x.DdlSchemaName 877 | } 878 | return "" 879 | } 880 | 881 | type isRowChange_EventTypePresent interface { 882 | isRowChange_EventTypePresent() 883 | } 884 | 885 | type RowChange_EventType struct { 886 | EventType EventType `protobuf:"varint,2,opt,name=eventType,proto3,enum=com.alibaba.otter.canal.protocol.EventType,oneof"` 887 | } 888 | 889 | func (*RowChange_EventType) isRowChange_EventTypePresent() {} 890 | 891 | type isRowChange_IsDdlPresent interface { 892 | isRowChange_IsDdlPresent() 893 | } 894 | 895 | type RowChange_IsDdl struct { 896 | IsDdl bool `protobuf:"varint,10,opt,name=isDdl,proto3,oneof"` 897 | } 898 | 899 | func (*RowChange_IsDdl) isRowChange_IsDdlPresent() {} 900 | 901 | // *开始事务的一些信息* 902 | type TransactionBegin struct { 903 | state protoimpl.MessageState 904 | sizeCache protoimpl.SizeCache 905 | unknownFields protoimpl.UnknownFields 906 | 907 | // *已废弃,请使用header里的executeTime* 908 | ExecuteTime int64 `protobuf:"varint,1,opt,name=executeTime,proto3" json:"executeTime,omitempty"` 909 | // *已废弃,Begin里不提供事务id* 910 | TransactionId string `protobuf:"bytes,2,opt,name=transactionId,proto3" json:"transactionId,omitempty"` 911 | // *预留扩展* 912 | Props []*Pair `protobuf:"bytes,3,rep,name=props,proto3" json:"props,omitempty"` 913 | // *执行的thread Id* 914 | ThreadId int64 `protobuf:"varint,4,opt,name=threadId,proto3" json:"threadId,omitempty"` 915 | } 916 | 917 | func (x *TransactionBegin) Reset() { 918 | *x = TransactionBegin{} 919 | if protoimpl.UnsafeEnabled { 920 | mi := &file_entry_protocol_proto_msgTypes[5] 921 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 922 | ms.StoreMessageInfo(mi) 923 | } 924 | } 925 | 926 | func (x *TransactionBegin) String() string { 927 | return protoimpl.X.MessageStringOf(x) 928 | } 929 | 930 | func (*TransactionBegin) ProtoMessage() {} 931 | 932 | func (x *TransactionBegin) ProtoReflect() protoreflect.Message { 933 | mi := &file_entry_protocol_proto_msgTypes[5] 934 | if protoimpl.UnsafeEnabled && x != nil { 935 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 936 | if ms.LoadMessageInfo() == nil { 937 | ms.StoreMessageInfo(mi) 938 | } 939 | return ms 940 | } 941 | return mi.MessageOf(x) 942 | } 943 | 944 | // Deprecated: Use TransactionBegin.ProtoReflect.Descriptor instead. 945 | func (*TransactionBegin) Descriptor() ([]byte, []int) { 946 | return file_entry_protocol_proto_rawDescGZIP(), []int{5} 947 | } 948 | 949 | func (x *TransactionBegin) GetExecuteTime() int64 { 950 | if x != nil { 951 | return x.ExecuteTime 952 | } 953 | return 0 954 | } 955 | 956 | func (x *TransactionBegin) GetTransactionId() string { 957 | if x != nil { 958 | return x.TransactionId 959 | } 960 | return "" 961 | } 962 | 963 | func (x *TransactionBegin) GetProps() []*Pair { 964 | if x != nil { 965 | return x.Props 966 | } 967 | return nil 968 | } 969 | 970 | func (x *TransactionBegin) GetThreadId() int64 { 971 | if x != nil { 972 | return x.ThreadId 973 | } 974 | return 0 975 | } 976 | 977 | // *结束事务的一些信息* 978 | type TransactionEnd struct { 979 | state protoimpl.MessageState 980 | sizeCache protoimpl.SizeCache 981 | unknownFields protoimpl.UnknownFields 982 | 983 | // *已废弃,请使用header里的executeTime* 984 | ExecuteTime int64 `protobuf:"varint,1,opt,name=executeTime,proto3" json:"executeTime,omitempty"` 985 | // *事务号* 986 | TransactionId string `protobuf:"bytes,2,opt,name=transactionId,proto3" json:"transactionId,omitempty"` 987 | // *预留扩展* 988 | Props []*Pair `protobuf:"bytes,3,rep,name=props,proto3" json:"props,omitempty"` 989 | } 990 | 991 | func (x *TransactionEnd) Reset() { 992 | *x = TransactionEnd{} 993 | if protoimpl.UnsafeEnabled { 994 | mi := &file_entry_protocol_proto_msgTypes[6] 995 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 996 | ms.StoreMessageInfo(mi) 997 | } 998 | } 999 | 1000 | func (x *TransactionEnd) String() string { 1001 | return protoimpl.X.MessageStringOf(x) 1002 | } 1003 | 1004 | func (*TransactionEnd) ProtoMessage() {} 1005 | 1006 | func (x *TransactionEnd) ProtoReflect() protoreflect.Message { 1007 | mi := &file_entry_protocol_proto_msgTypes[6] 1008 | if protoimpl.UnsafeEnabled && x != nil { 1009 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1010 | if ms.LoadMessageInfo() == nil { 1011 | ms.StoreMessageInfo(mi) 1012 | } 1013 | return ms 1014 | } 1015 | return mi.MessageOf(x) 1016 | } 1017 | 1018 | // Deprecated: Use TransactionEnd.ProtoReflect.Descriptor instead. 1019 | func (*TransactionEnd) Descriptor() ([]byte, []int) { 1020 | return file_entry_protocol_proto_rawDescGZIP(), []int{6} 1021 | } 1022 | 1023 | func (x *TransactionEnd) GetExecuteTime() int64 { 1024 | if x != nil { 1025 | return x.ExecuteTime 1026 | } 1027 | return 0 1028 | } 1029 | 1030 | func (x *TransactionEnd) GetTransactionId() string { 1031 | if x != nil { 1032 | return x.TransactionId 1033 | } 1034 | return "" 1035 | } 1036 | 1037 | func (x *TransactionEnd) GetProps() []*Pair { 1038 | if x != nil { 1039 | return x.Props 1040 | } 1041 | return nil 1042 | } 1043 | 1044 | // *预留扩展* 1045 | type Pair struct { 1046 | state protoimpl.MessageState 1047 | sizeCache protoimpl.SizeCache 1048 | unknownFields protoimpl.UnknownFields 1049 | 1050 | Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` 1051 | Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` 1052 | } 1053 | 1054 | func (x *Pair) Reset() { 1055 | *x = Pair{} 1056 | if protoimpl.UnsafeEnabled { 1057 | mi := &file_entry_protocol_proto_msgTypes[7] 1058 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1059 | ms.StoreMessageInfo(mi) 1060 | } 1061 | } 1062 | 1063 | func (x *Pair) String() string { 1064 | return protoimpl.X.MessageStringOf(x) 1065 | } 1066 | 1067 | func (*Pair) ProtoMessage() {} 1068 | 1069 | func (x *Pair) ProtoReflect() protoreflect.Message { 1070 | mi := &file_entry_protocol_proto_msgTypes[7] 1071 | if protoimpl.UnsafeEnabled && x != nil { 1072 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1073 | if ms.LoadMessageInfo() == nil { 1074 | ms.StoreMessageInfo(mi) 1075 | } 1076 | return ms 1077 | } 1078 | return mi.MessageOf(x) 1079 | } 1080 | 1081 | // Deprecated: Use Pair.ProtoReflect.Descriptor instead. 1082 | func (*Pair) Descriptor() ([]byte, []int) { 1083 | return file_entry_protocol_proto_rawDescGZIP(), []int{7} 1084 | } 1085 | 1086 | func (x *Pair) GetKey() string { 1087 | if x != nil { 1088 | return x.Key 1089 | } 1090 | return "" 1091 | } 1092 | 1093 | func (x *Pair) GetValue() string { 1094 | if x != nil { 1095 | return x.Value 1096 | } 1097 | return "" 1098 | } 1099 | 1100 | var File_entry_protocol_proto protoreflect.FileDescriptor 1101 | 1102 | var file_entry_protocol_proto_rawDesc = []byte{ 1103 | 0x0a, 0x14, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 1104 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 1105 | 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 1106 | 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0xcb, 0x01, 0x0a, 0x05, 0x45, 0x6e, 0x74, 1107 | 0x72, 0x79, 0x12, 0x40, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 1108 | 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 1109 | 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 1110 | 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 1111 | 0x61, 0x64, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 1112 | 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 1113 | 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 1114 | 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, 1115 | 0x54, 0x79, 0x70, 0x65, 0x48, 0x00, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 1116 | 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 1117 | 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 1118 | 0x65, 0x42, 0x13, 0x0a, 0x11, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x70, 1119 | 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0xd5, 0x04, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 1120 | 0x72, 0x12, 0x1a, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 1121 | 0x28, 0x05, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 1122 | 0x0b, 0x6c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 1123 | 0x28, 0x09, 0x52, 0x0b, 0x6c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 1124 | 0x24, 0x0a, 0x0d, 0x6c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 1125 | 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x4f, 1126 | 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 1127 | 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 1128 | 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x65, 0x6e, 0x43, 0x6f, 0x64, 1129 | 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x65, 1130 | 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 1131 | 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 1132 | 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x48, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 1133 | 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x63, 0x6f, 1134 | 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 1135 | 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x54, 1136 | 0x79, 0x70, 0x65, 0x48, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 1137 | 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4e, 0x61, 0x6d, 0x65, 0x18, 1138 | 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4e, 0x61, 0x6d, 1139 | 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x09, 1140 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 1141 | 0x20, 0x0a, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0a, 1142 | 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 1143 | 0x68, 0x12, 0x4b, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0b, 1144 | 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 1145 | 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 1146 | 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 1147 | 0x65, 0x48, 0x02, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3c, 1148 | 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 1149 | 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 1150 | 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 1151 | 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x12, 0x0a, 0x04, 1152 | 0x67, 0x74, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x74, 0x69, 0x64, 1153 | 0x42, 0x11, 0x0a, 0x0f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x73, 1154 | 0x65, 0x6e, 0x74, 0x42, 0x14, 0x0a, 0x12, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 1155 | 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x65, 0x76, 0x65, 1156 | 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0xb2, 1157 | 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 1158 | 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 1159 | 0x18, 0x0a, 0x07, 0x73, 0x71, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 1160 | 0x52, 0x07, 0x73, 0x71, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 1161 | 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 1162 | 0x05, 0x69, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 1163 | 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 1164 | 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 1165 | 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 1166 | 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x3c, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 1167 | 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 1168 | 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 1169 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 1170 | 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 1171 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 1172 | 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 1173 | 0x67, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x54, 0x79, 0x70, 0x65, 1174 | 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x54, 0x79, 0x70, 1175 | 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x5f, 0x70, 0x72, 0x65, 0x73, 1176 | 0x65, 0x6e, 0x74, 0x22, 0xe5, 0x01, 0x0a, 0x07, 0x52, 0x6f, 0x77, 0x44, 0x61, 0x74, 0x61, 0x12, 1177 | 0x4e, 0x0a, 0x0d, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 1178 | 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 1179 | 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 1180 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 1181 | 0x52, 0x0d, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 1182 | 0x4c, 0x0a, 0x0c, 0x61, 0x66, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 1183 | 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 1184 | 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 1185 | 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 1186 | 0x0c, 0x61, 0x66, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 1187 | 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 1188 | 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 1189 | 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 1190 | 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x22, 0xed, 0x02, 0x0a, 0x09, 1191 | 0x52, 0x6f, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x62, 1192 | 0x6c, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x61, 0x62, 0x6c, 1193 | 0x65, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 1194 | 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 1195 | 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 1196 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 1197 | 0x79, 0x70, 0x65, 0x48, 0x00, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 1198 | 0x12, 0x16, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x64, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x48, 1199 | 0x01, 0x52, 0x05, 0x69, 0x73, 0x44, 0x64, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x71, 0x6c, 0x18, 1200 | 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x71, 0x6c, 0x12, 0x45, 0x0a, 0x08, 0x72, 0x6f, 1201 | 0x77, 0x44, 0x61, 0x74, 0x61, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 1202 | 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 1203 | 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 1204 | 0x52, 0x6f, 0x77, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x72, 0x6f, 0x77, 0x44, 0x61, 0x74, 0x61, 1205 | 0x73, 0x12, 0x3c, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 1206 | 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 1207 | 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 1208 | 0x63, 0x6f, 0x6c, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 1209 | 0x24, 0x0a, 0x0d, 0x64, 0x64, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4e, 0x61, 0x6d, 0x65, 1210 | 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x64, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 1211 | 0x61, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 1212 | 0x70, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x69, 0x73, 1213 | 0x44, 0x64, 0x6c, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0xb4, 0x01, 0x0a, 0x10, 1214 | 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x67, 0x69, 0x6e, 1215 | 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 1216 | 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x54, 0x69, 1217 | 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 1218 | 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 1219 | 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 1220 | 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 1221 | 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 1222 | 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 1223 | 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 1224 | 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 1225 | 0x49, 0x64, 0x22, 0x96, 0x01, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 1226 | 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 1227 | 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 1228 | 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 1229 | 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 1230 | 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x3c, 0x0a, 1231 | 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 1232 | 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 1233 | 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 1234 | 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x22, 0x2e, 0x0a, 0x04, 0x50, 1235 | 0x61, 0x69, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 1236 | 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 1237 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x7d, 0x0a, 0x09, 0x45, 1238 | 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x4e, 0x54, 0x52, 1239 | 0x59, 0x54, 0x59, 0x50, 0x45, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x50, 1240 | 0x52, 0x4f, 0x54, 0x4f, 0x32, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x52, 0x41, 0x4e, 0x53, 1241 | 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 1242 | 0x07, 0x52, 0x4f, 0x57, 0x44, 0x41, 0x54, 0x41, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x52, 1243 | 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x45, 0x4e, 0x44, 0x10, 0x03, 0x12, 0x0d, 1244 | 0x0a, 0x09, 0x48, 0x45, 0x41, 0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x04, 0x12, 0x0b, 0x0a, 1245 | 0x07, 0x47, 0x54, 0x49, 0x44, 0x4c, 0x4f, 0x47, 0x10, 0x05, 0x2a, 0xe5, 0x01, 0x0a, 0x09, 0x45, 1246 | 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x56, 0x45, 0x4e, 1247 | 0x54, 0x54, 0x59, 0x50, 0x45, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x50, 1248 | 0x52, 0x4f, 0x54, 0x4f, 0x32, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4e, 0x53, 0x45, 0x52, 1249 | 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 1250 | 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 1251 | 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x4c, 0x54, 0x45, 0x52, 1252 | 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x41, 0x53, 0x45, 0x10, 0x06, 0x12, 0x09, 0x0a, 1253 | 0x05, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x52, 0x55, 0x4e, 1254 | 0x43, 0x41, 0x54, 0x45, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4e, 0x41, 0x4d, 0x45, 1255 | 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x0a, 0x12, 0x0a, 1256 | 0x0a, 0x06, 0x44, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x0b, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x54, 1257 | 0x49, 0x44, 0x10, 0x0c, 0x12, 0x0c, 0x0a, 0x08, 0x58, 0x41, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 1258 | 0x10, 0x0d, 0x12, 0x0e, 0x0a, 0x0a, 0x58, 0x41, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43, 0x4b, 1259 | 0x10, 0x0e, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x48, 0x45, 0x41, 0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 1260 | 0x10, 0x0f, 0x2a, 0x42, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x59, 1261 | 0x50, 0x45, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x50, 0x52, 0x4f, 0x54, 1262 | 0x4f, 0x32, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x52, 0x41, 0x43, 0x4c, 0x45, 0x10, 0x01, 1263 | 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x50, 1264 | 0x47, 0x53, 0x51, 0x4c, 0x10, 0x03, 0x42, 0x3a, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 1265 | 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 1266 | 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x0a, 0x43, 0x61, 0x6e, 0x61, 1267 | 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x01, 0x5a, 0x08, 0x2e, 0x2f, 0x3b, 0x65, 0x6e, 0x74, 1268 | 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 1269 | } 1270 | 1271 | var ( 1272 | file_entry_protocol_proto_rawDescOnce sync.Once 1273 | file_entry_protocol_proto_rawDescData = file_entry_protocol_proto_rawDesc 1274 | ) 1275 | 1276 | func file_entry_protocol_proto_rawDescGZIP() []byte { 1277 | file_entry_protocol_proto_rawDescOnce.Do(func() { 1278 | file_entry_protocol_proto_rawDescData = protoimpl.X.CompressGZIP(file_entry_protocol_proto_rawDescData) 1279 | }) 1280 | return file_entry_protocol_proto_rawDescData 1281 | } 1282 | 1283 | var file_entry_protocol_proto_enumTypes = make([]protoimpl.EnumInfo, 3) 1284 | var file_entry_protocol_proto_msgTypes = make([]protoimpl.MessageInfo, 8) 1285 | var file_entry_protocol_proto_goTypes = []interface{}{ 1286 | (EntryType)(0), // 0: com.alibaba.otter.canal.protocol.EntryType 1287 | (EventType)(0), // 1: com.alibaba.otter.canal.protocol.EventType 1288 | (Type)(0), // 2: com.alibaba.otter.canal.protocol.Type 1289 | (*Entry)(nil), // 3: com.alibaba.otter.canal.protocol.Entry 1290 | (*Header)(nil), // 4: com.alibaba.otter.canal.protocol.Header 1291 | (*Column)(nil), // 5: com.alibaba.otter.canal.protocol.Column 1292 | (*RowData)(nil), // 6: com.alibaba.otter.canal.protocol.RowData 1293 | (*RowChange)(nil), // 7: com.alibaba.otter.canal.protocol.RowChange 1294 | (*TransactionBegin)(nil), // 8: com.alibaba.otter.canal.protocol.TransactionBegin 1295 | (*TransactionEnd)(nil), // 9: com.alibaba.otter.canal.protocol.TransactionEnd 1296 | (*Pair)(nil), // 10: com.alibaba.otter.canal.protocol.Pair 1297 | } 1298 | var file_entry_protocol_proto_depIdxs = []int32{ 1299 | 4, // 0: com.alibaba.otter.canal.protocol.Entry.header:type_name -> com.alibaba.otter.canal.protocol.Header 1300 | 0, // 1: com.alibaba.otter.canal.protocol.Entry.entryType:type_name -> com.alibaba.otter.canal.protocol.EntryType 1301 | 2, // 2: com.alibaba.otter.canal.protocol.Header.sourceType:type_name -> com.alibaba.otter.canal.protocol.Type 1302 | 1, // 3: com.alibaba.otter.canal.protocol.Header.eventType:type_name -> com.alibaba.otter.canal.protocol.EventType 1303 | 10, // 4: com.alibaba.otter.canal.protocol.Header.props:type_name -> com.alibaba.otter.canal.protocol.Pair 1304 | 10, // 5: com.alibaba.otter.canal.protocol.Column.props:type_name -> com.alibaba.otter.canal.protocol.Pair 1305 | 5, // 6: com.alibaba.otter.canal.protocol.RowData.beforeColumns:type_name -> com.alibaba.otter.canal.protocol.Column 1306 | 5, // 7: com.alibaba.otter.canal.protocol.RowData.afterColumns:type_name -> com.alibaba.otter.canal.protocol.Column 1307 | 10, // 8: com.alibaba.otter.canal.protocol.RowData.props:type_name -> com.alibaba.otter.canal.protocol.Pair 1308 | 1, // 9: com.alibaba.otter.canal.protocol.RowChange.eventType:type_name -> com.alibaba.otter.canal.protocol.EventType 1309 | 6, // 10: com.alibaba.otter.canal.protocol.RowChange.rowDatas:type_name -> com.alibaba.otter.canal.protocol.RowData 1310 | 10, // 11: com.alibaba.otter.canal.protocol.RowChange.props:type_name -> com.alibaba.otter.canal.protocol.Pair 1311 | 10, // 12: com.alibaba.otter.canal.protocol.TransactionBegin.props:type_name -> com.alibaba.otter.canal.protocol.Pair 1312 | 10, // 13: com.alibaba.otter.canal.protocol.TransactionEnd.props:type_name -> com.alibaba.otter.canal.protocol.Pair 1313 | 14, // [14:14] is the sub-list for method output_type 1314 | 14, // [14:14] is the sub-list for method input_type 1315 | 14, // [14:14] is the sub-list for extension type_name 1316 | 14, // [14:14] is the sub-list for extension extendee 1317 | 0, // [0:14] is the sub-list for field type_name 1318 | } 1319 | 1320 | func init() { file_entry_protocol_proto_init() } 1321 | func file_entry_protocol_proto_init() { 1322 | if File_entry_protocol_proto != nil { 1323 | return 1324 | } 1325 | if !protoimpl.UnsafeEnabled { 1326 | file_entry_protocol_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 1327 | switch v := v.(*Entry); i { 1328 | case 0: 1329 | return &v.state 1330 | case 1: 1331 | return &v.sizeCache 1332 | case 2: 1333 | return &v.unknownFields 1334 | default: 1335 | return nil 1336 | } 1337 | } 1338 | file_entry_protocol_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 1339 | switch v := v.(*Header); i { 1340 | case 0: 1341 | return &v.state 1342 | case 1: 1343 | return &v.sizeCache 1344 | case 2: 1345 | return &v.unknownFields 1346 | default: 1347 | return nil 1348 | } 1349 | } 1350 | file_entry_protocol_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 1351 | switch v := v.(*Column); i { 1352 | case 0: 1353 | return &v.state 1354 | case 1: 1355 | return &v.sizeCache 1356 | case 2: 1357 | return &v.unknownFields 1358 | default: 1359 | return nil 1360 | } 1361 | } 1362 | file_entry_protocol_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 1363 | switch v := v.(*RowData); i { 1364 | case 0: 1365 | return &v.state 1366 | case 1: 1367 | return &v.sizeCache 1368 | case 2: 1369 | return &v.unknownFields 1370 | default: 1371 | return nil 1372 | } 1373 | } 1374 | file_entry_protocol_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 1375 | switch v := v.(*RowChange); i { 1376 | case 0: 1377 | return &v.state 1378 | case 1: 1379 | return &v.sizeCache 1380 | case 2: 1381 | return &v.unknownFields 1382 | default: 1383 | return nil 1384 | } 1385 | } 1386 | file_entry_protocol_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { 1387 | switch v := v.(*TransactionBegin); i { 1388 | case 0: 1389 | return &v.state 1390 | case 1: 1391 | return &v.sizeCache 1392 | case 2: 1393 | return &v.unknownFields 1394 | default: 1395 | return nil 1396 | } 1397 | } 1398 | file_entry_protocol_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { 1399 | switch v := v.(*TransactionEnd); i { 1400 | case 0: 1401 | return &v.state 1402 | case 1: 1403 | return &v.sizeCache 1404 | case 2: 1405 | return &v.unknownFields 1406 | default: 1407 | return nil 1408 | } 1409 | } 1410 | file_entry_protocol_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { 1411 | switch v := v.(*Pair); i { 1412 | case 0: 1413 | return &v.state 1414 | case 1: 1415 | return &v.sizeCache 1416 | case 2: 1417 | return &v.unknownFields 1418 | default: 1419 | return nil 1420 | } 1421 | } 1422 | } 1423 | file_entry_protocol_proto_msgTypes[0].OneofWrappers = []interface{}{ 1424 | (*Entry_EntryType)(nil), 1425 | } 1426 | file_entry_protocol_proto_msgTypes[1].OneofWrappers = []interface{}{ 1427 | (*Header_Version)(nil), 1428 | (*Header_SourceType)(nil), 1429 | (*Header_EventType)(nil), 1430 | } 1431 | file_entry_protocol_proto_msgTypes[2].OneofWrappers = []interface{}{ 1432 | (*Column_IsNull)(nil), 1433 | } 1434 | file_entry_protocol_proto_msgTypes[4].OneofWrappers = []interface{}{ 1435 | (*RowChange_EventType)(nil), 1436 | (*RowChange_IsDdl)(nil), 1437 | } 1438 | type x struct{} 1439 | out := protoimpl.TypeBuilder{ 1440 | File: protoimpl.DescBuilder{ 1441 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 1442 | RawDescriptor: file_entry_protocol_proto_rawDesc, 1443 | NumEnums: 3, 1444 | NumMessages: 8, 1445 | NumExtensions: 0, 1446 | NumServices: 0, 1447 | }, 1448 | GoTypes: file_entry_protocol_proto_goTypes, 1449 | DependencyIndexes: file_entry_protocol_proto_depIdxs, 1450 | EnumInfos: file_entry_protocol_proto_enumTypes, 1451 | MessageInfos: file_entry_protocol_proto_msgTypes, 1452 | }.Build() 1453 | File_entry_protocol_proto = out.File 1454 | file_entry_protocol_proto_rawDesc = nil 1455 | file_entry_protocol_proto_goTypes = nil 1456 | file_entry_protocol_proto_depIdxs = nil 1457 | } 1458 | -------------------------------------------------------------------------------- /protocol/entry/entry_protocol.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package com.alibaba.otter.canal.protocol.entry; 3 | 4 | option java_package = "com.alibaba.otter.canal.protocol"; 5 | option java_outer_classname = "CanalEntry"; 6 | option optimize_for = SPEED; 7 | 8 | option go_package = "./;entry"; 9 | /**************************************************************** 10 | * message model 11 | *如果要在Enum中新增类型,确保以前的类型的下标值不变. 12 | ****************************************************************/ 13 | message Entry { 14 | /**协议头部信息**/ 15 | Header header = 1; 16 | ///**打散后的事件类型**/ [default = ROWDATA] 17 | oneof entryType_present{ 18 | EntryType entryType = 2; 19 | } 20 | 21 | /**传输的二进制数组**/ 22 | bytes storeValue = 3; 23 | } 24 | 25 | /**message Header**/ 26 | message Header { 27 | /**协议的版本号**/ //[default = 1] 28 | oneof version_present { 29 | int32 version = 1; 30 | } 31 | 32 | 33 | /**binlog/redolog 文件名**/ 34 | string logfileName = 2; 35 | 36 | /**binlog/redolog 文件的偏移位置**/ 37 | int64 logfileOffset = 3; 38 | 39 | /**服务端serverId**/ 40 | int64 serverId = 4; 41 | 42 | /** 变更数据的编码 **/ 43 | string serverenCode = 5; 44 | 45 | /**变更数据的执行时间 **/ 46 | int64 executeTime = 6; 47 | 48 | /** 变更数据的来源**/ //[default = MYSQL] 49 | oneof sourceType_present { 50 | Type sourceType = 7; 51 | } 52 | 53 | 54 | /** 变更数据的schemaname**/ 55 | string schemaName = 8; 56 | 57 | /**变更数据的tablename**/ 58 | string tableName = 9; 59 | 60 | /**每个event的长度**/ 61 | int64 eventLength = 10; 62 | 63 | /**数据变更类型**/ // [default = UPDATE] 64 | oneof eventType_present { 65 | EventType eventType = 11; 66 | } 67 | 68 | 69 | /**预留扩展**/ 70 | repeated Pair props = 12; 71 | 72 | /**当前事务的gitd**/ 73 | string gtid = 13; 74 | } 75 | 76 | /**每个字段的数据结构**/ 77 | message Column { 78 | /**字段下标**/ 79 | int32 index = 1; 80 | 81 | /**字段java中类型**/ 82 | int32 sqlType = 2; 83 | 84 | /**字段名称(忽略大小写),在mysql中是没有的**/ 85 | string name = 3; 86 | 87 | /**是否是主键**/ 88 | bool isKey = 4; 89 | 90 | /**如果EventType=UPDATE,用于标识这个字段值是否有修改**/ 91 | bool updated = 5; 92 | 93 | /** 标识是否为空 **/ //[default = false] 94 | oneof isNull_present { 95 | bool isNull = 6; 96 | } 97 | 98 | 99 | /**预留扩展**/ 100 | repeated Pair props = 7; 101 | 102 | /** 字段值,timestamp,Datetime是一个时间格式的文本 **/ 103 | string value = 8; 104 | 105 | /** 对应数据对象原始长度 **/ 106 | int32 length = 9; 107 | 108 | /**字段mysql类型**/ 109 | string mysqlType = 10; 110 | } 111 | 112 | message RowData { 113 | 114 | /** 字段信息,增量数据(修改前,删除前) **/ 115 | repeated Column beforeColumns = 1; 116 | 117 | /** 字段信息,增量数据(修改后,新增后) **/ 118 | repeated Column afterColumns = 2; 119 | 120 | /**预留扩展**/ 121 | repeated Pair props = 3; 122 | } 123 | 124 | /**message row 每行变更数据的数据结构**/ 125 | message RowChange { 126 | 127 | /**tableId,由数据库产生**/ 128 | int64 tableId = 1; 129 | 130 | 131 | /**数据变更类型**/ //[default = UPDATE] 132 | oneof eventType_present { 133 | EventType eventType = 2; 134 | } 135 | 136 | 137 | /** 标识是否是ddl语句 **/ // [default = false] 138 | oneof isDdl_present { 139 | bool isDdl = 10; 140 | } 141 | 142 | 143 | /** ddl/query的sql语句 **/ 144 | string sql = 11; 145 | 146 | /** 一次数据库变更可能存在多行 **/ 147 | repeated RowData rowDatas = 12; 148 | 149 | /**预留扩展**/ 150 | repeated Pair props = 13; 151 | 152 | /** ddl/query的schemaName,会存在跨库ddl,需要保留执行ddl的当前schemaName **/ 153 | string ddlSchemaName = 14; 154 | } 155 | 156 | /**开始事务的一些信息**/ 157 | message TransactionBegin{ 158 | 159 | /**已废弃,请使用header里的executeTime**/ 160 | int64 executeTime = 1; 161 | 162 | /**已废弃,Begin里不提供事务id**/ 163 | string transactionId = 2; 164 | 165 | /**预留扩展**/ 166 | repeated Pair props = 3; 167 | 168 | /**执行的thread Id**/ 169 | int64 threadId = 4; 170 | } 171 | 172 | /**结束事务的一些信息**/ 173 | message TransactionEnd{ 174 | 175 | /**已废弃,请使用header里的executeTime**/ 176 | int64 executeTime = 1; 177 | 178 | /**事务号**/ 179 | string transactionId = 2; 180 | 181 | /**预留扩展**/ 182 | repeated Pair props = 3; 183 | } 184 | 185 | /**预留扩展**/ 186 | message Pair{ 187 | string key = 1; 188 | string value = 2; 189 | } 190 | 191 | /**打散后的事件类型,主要用于标识事务的开始,变更数据,结束**/ 192 | enum EntryType{ 193 | ENTRYTYPECOMPATIBLEPROTO2 = 0; 194 | TRANSACTIONBEGIN = 1; 195 | ROWDATA = 2; 196 | TRANSACTIONEND = 3; 197 | /** 心跳类型,内部使用,外部暂不可见,可忽略 **/ 198 | HEARTBEAT = 4; 199 | GTIDLOG = 5; 200 | } 201 | 202 | /** 事件类型 **/ 203 | enum EventType { 204 | EVENTTYPECOMPATIBLEPROTO2 = 0; 205 | INSERT = 1; 206 | UPDATE = 2; 207 | DELETE = 3; 208 | CREATE = 4; 209 | ALTER = 5; 210 | ERASE = 6; 211 | QUERY = 7; 212 | TRUNCATE = 8; 213 | RENAME = 9; 214 | /**CREATE INDEX**/ 215 | CINDEX = 10; 216 | DINDEX = 11; 217 | GTID = 12; 218 | /** XA **/ 219 | XACOMMIT = 13; 220 | XAROLLBACK = 14; 221 | /** MASTER HEARTBEAT **/ 222 | MHEARTBEAT = 15; 223 | } 224 | 225 | /**数据库类型**/ 226 | enum Type { 227 | TYPECOMPATIBLEPROTO2 = 0; 228 | ORACLE = 1; 229 | MYSQL = 2; 230 | PGSQL = 3; 231 | } 232 | -------------------------------------------------------------------------------- /protocol/exception/canal_client_error.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package exception 18 | 19 | type CanalClientError struct { 20 | msg string 21 | } 22 | 23 | func (e *CanalClientError) Error() string { 24 | return e.msg 25 | } 26 | -------------------------------------------------------------------------------- /protocol/exception/doc.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package exception 18 | -------------------------------------------------------------------------------- /protocol/message.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package protocol 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | pbe "github.com/withlin/canal-go/protocol/entry" 23 | pbp "github.com/withlin/canal-go/protocol/packet" 24 | proto "google.golang.org/protobuf/proto" 25 | ) 26 | 27 | type Message struct { 28 | Id int64 29 | Entries []pbe.Entry 30 | Raw bool 31 | RawEntries interface{} 32 | } 33 | 34 | func NewMessage(id int64) *Message { 35 | message := &Message{Id: id, Entries: nil, Raw: false, RawEntries: nil} 36 | return message 37 | } 38 | 39 | func Decode(data []byte, lazyParseEntry bool) (*Message, error) { 40 | p := new(pbp.Packet) 41 | err := proto.Unmarshal(data, p) 42 | if err != nil { 43 | return nil, err 44 | } 45 | messages := new(pbp.Messages) 46 | message := new(Message) 47 | 48 | length := len(messages.Messages) 49 | message.Entries = make([]pbe.Entry, length) 50 | ack := new(pbp.Ack) 51 | var items []pbe.Entry 52 | var entry pbe.Entry 53 | switch p.Type { 54 | case pbp.PacketType_MESSAGES: 55 | if !(p.GetCompression() == pbp.Compression_NONE) && !(p.GetCompression() == pbp.Compression_COMPRESSIONCOMPATIBLEPROTO2) { // NONE和兼容pb2的处理方式相同 56 | panic("compression is not supported in this connector") 57 | } 58 | err := proto.Unmarshal(p.Body, messages) 59 | if err != nil { 60 | return nil, err 61 | } 62 | if lazyParseEntry { 63 | message.RawEntries = messages.Messages 64 | message.Raw = true 65 | } else { 66 | 67 | for _, value := range messages.Messages { 68 | err := proto.Unmarshal(value, &entry) 69 | if err != nil { 70 | return nil, err 71 | } 72 | items = append(items, entry) 73 | } 74 | } 75 | message.Entries = items 76 | message.Id = messages.GetBatchId() 77 | return message, nil 78 | 79 | case pbp.PacketType_ACK: 80 | err := proto.Unmarshal(p.Body, ack) 81 | if err != nil { 82 | return nil, err 83 | } 84 | panic(errors.New(fmt.Sprintf("something goes wrong with reason:%s", ack.GetErrorMessage()))) 85 | default: 86 | panic(errors.New(fmt.Sprintf("unexpected packet type:%s", p.Type))) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /protocol/packet/canal_protocol.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.31.0 4 | // protoc v4.24.4 5 | // source: canal_protocol.proto 6 | 7 | package packet 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Compression int32 24 | 25 | const ( 26 | Compression_COMPRESSIONCOMPATIBLEPROTO2 Compression = 0 27 | Compression_NONE Compression = 1 28 | Compression_ZLIB Compression = 2 29 | Compression_GZIP Compression = 3 30 | Compression_LZF Compression = 4 31 | ) 32 | 33 | // Enum value maps for Compression. 34 | var ( 35 | Compression_name = map[int32]string{ 36 | 0: "COMPRESSIONCOMPATIBLEPROTO2", 37 | 1: "NONE", 38 | 2: "ZLIB", 39 | 3: "GZIP", 40 | 4: "LZF", 41 | } 42 | Compression_value = map[string]int32{ 43 | "COMPRESSIONCOMPATIBLEPROTO2": 0, 44 | "NONE": 1, 45 | "ZLIB": 2, 46 | "GZIP": 3, 47 | "LZF": 4, 48 | } 49 | ) 50 | 51 | func (x Compression) Enum() *Compression { 52 | p := new(Compression) 53 | *p = x 54 | return p 55 | } 56 | 57 | func (x Compression) String() string { 58 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 59 | } 60 | 61 | func (Compression) Descriptor() protoreflect.EnumDescriptor { 62 | return file_canal_protocol_proto_enumTypes[0].Descriptor() 63 | } 64 | 65 | func (Compression) Type() protoreflect.EnumType { 66 | return &file_canal_protocol_proto_enumTypes[0] 67 | } 68 | 69 | func (x Compression) Number() protoreflect.EnumNumber { 70 | return protoreflect.EnumNumber(x) 71 | } 72 | 73 | // Deprecated: Use Compression.Descriptor instead. 74 | func (Compression) EnumDescriptor() ([]byte, []int) { 75 | return file_canal_protocol_proto_rawDescGZIP(), []int{0} 76 | } 77 | 78 | type PacketType int32 79 | 80 | const ( 81 | // compatible 82 | PacketType_PACKAGETYPECOMPATIBLEPROTO2 PacketType = 0 83 | PacketType_HANDSHAKE PacketType = 1 84 | PacketType_CLIENTAUTHENTICATION PacketType = 2 85 | PacketType_ACK PacketType = 3 86 | PacketType_SUBSCRIPTION PacketType = 4 87 | PacketType_UNSUBSCRIPTION PacketType = 5 88 | PacketType_GET PacketType = 6 89 | PacketType_MESSAGES PacketType = 7 90 | PacketType_CLIENTACK PacketType = 8 91 | // management part 92 | PacketType_SHUTDOWN PacketType = 9 93 | // integration 94 | PacketType_DUMP PacketType = 10 95 | PacketType_HEARTBEAT PacketType = 11 96 | PacketType_CLIENTROLLBACK PacketType = 12 97 | ) 98 | 99 | // Enum value maps for PacketType. 100 | var ( 101 | PacketType_name = map[int32]string{ 102 | 0: "PACKAGETYPECOMPATIBLEPROTO2", 103 | 1: "HANDSHAKE", 104 | 2: "CLIENTAUTHENTICATION", 105 | 3: "ACK", 106 | 4: "SUBSCRIPTION", 107 | 5: "UNSUBSCRIPTION", 108 | 6: "GET", 109 | 7: "MESSAGES", 110 | 8: "CLIENTACK", 111 | 9: "SHUTDOWN", 112 | 10: "DUMP", 113 | 11: "HEARTBEAT", 114 | 12: "CLIENTROLLBACK", 115 | } 116 | PacketType_value = map[string]int32{ 117 | "PACKAGETYPECOMPATIBLEPROTO2": 0, 118 | "HANDSHAKE": 1, 119 | "CLIENTAUTHENTICATION": 2, 120 | "ACK": 3, 121 | "SUBSCRIPTION": 4, 122 | "UNSUBSCRIPTION": 5, 123 | "GET": 6, 124 | "MESSAGES": 7, 125 | "CLIENTACK": 8, 126 | "SHUTDOWN": 9, 127 | "DUMP": 10, 128 | "HEARTBEAT": 11, 129 | "CLIENTROLLBACK": 12, 130 | } 131 | ) 132 | 133 | func (x PacketType) Enum() *PacketType { 134 | p := new(PacketType) 135 | *p = x 136 | return p 137 | } 138 | 139 | func (x PacketType) String() string { 140 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 141 | } 142 | 143 | func (PacketType) Descriptor() protoreflect.EnumDescriptor { 144 | return file_canal_protocol_proto_enumTypes[1].Descriptor() 145 | } 146 | 147 | func (PacketType) Type() protoreflect.EnumType { 148 | return &file_canal_protocol_proto_enumTypes[1] 149 | } 150 | 151 | func (x PacketType) Number() protoreflect.EnumNumber { 152 | return protoreflect.EnumNumber(x) 153 | } 154 | 155 | // Deprecated: Use PacketType.Descriptor instead. 156 | func (PacketType) EnumDescriptor() ([]byte, []int) { 157 | return file_canal_protocol_proto_rawDescGZIP(), []int{1} 158 | } 159 | 160 | type Packet struct { 161 | state protoimpl.MessageState 162 | sizeCache protoimpl.SizeCache 163 | unknownFields protoimpl.UnknownFields 164 | 165 | // [default = 17]; 166 | // 167 | // Types that are assignable to MagicNumberPresent: 168 | // 169 | // *Packet_MagicNumber 170 | MagicNumberPresent isPacket_MagicNumberPresent `protobuf_oneof:"magic_number_present"` 171 | // [default = 1]; 172 | // 173 | // Types that are assignable to VersionPresent: 174 | // 175 | // *Packet_Version 176 | VersionPresent isPacket_VersionPresent `protobuf_oneof:"version_present"` 177 | Type PacketType `protobuf:"varint,3,opt,name=type,proto3,enum=com.alibaba.otter.canal.protocol.packet.PacketType" json:"type,omitempty"` 178 | // [default = NONE]; 179 | // 180 | // Types that are assignable to CompressionPresent: 181 | // 182 | // *Packet_Compression 183 | CompressionPresent isPacket_CompressionPresent `protobuf_oneof:"compression_present"` 184 | Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` 185 | } 186 | 187 | func (x *Packet) Reset() { 188 | *x = Packet{} 189 | if protoimpl.UnsafeEnabled { 190 | mi := &file_canal_protocol_proto_msgTypes[0] 191 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 192 | ms.StoreMessageInfo(mi) 193 | } 194 | } 195 | 196 | func (x *Packet) String() string { 197 | return protoimpl.X.MessageStringOf(x) 198 | } 199 | 200 | func (*Packet) ProtoMessage() {} 201 | 202 | func (x *Packet) ProtoReflect() protoreflect.Message { 203 | mi := &file_canal_protocol_proto_msgTypes[0] 204 | if protoimpl.UnsafeEnabled && x != nil { 205 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 206 | if ms.LoadMessageInfo() == nil { 207 | ms.StoreMessageInfo(mi) 208 | } 209 | return ms 210 | } 211 | return mi.MessageOf(x) 212 | } 213 | 214 | // Deprecated: Use Packet.ProtoReflect.Descriptor instead. 215 | func (*Packet) Descriptor() ([]byte, []int) { 216 | return file_canal_protocol_proto_rawDescGZIP(), []int{0} 217 | } 218 | 219 | func (m *Packet) GetMagicNumberPresent() isPacket_MagicNumberPresent { 220 | if m != nil { 221 | return m.MagicNumberPresent 222 | } 223 | return nil 224 | } 225 | 226 | func (x *Packet) GetMagicNumber() int32 { 227 | if x, ok := x.GetMagicNumberPresent().(*Packet_MagicNumber); ok { 228 | return x.MagicNumber 229 | } 230 | return 0 231 | } 232 | 233 | func (m *Packet) GetVersionPresent() isPacket_VersionPresent { 234 | if m != nil { 235 | return m.VersionPresent 236 | } 237 | return nil 238 | } 239 | 240 | func (x *Packet) GetVersion() int32 { 241 | if x, ok := x.GetVersionPresent().(*Packet_Version); ok { 242 | return x.Version 243 | } 244 | return 0 245 | } 246 | 247 | func (x *Packet) GetType() PacketType { 248 | if x != nil { 249 | return x.Type 250 | } 251 | return PacketType_PACKAGETYPECOMPATIBLEPROTO2 252 | } 253 | 254 | func (m *Packet) GetCompressionPresent() isPacket_CompressionPresent { 255 | if m != nil { 256 | return m.CompressionPresent 257 | } 258 | return nil 259 | } 260 | 261 | func (x *Packet) GetCompression() Compression { 262 | if x, ok := x.GetCompressionPresent().(*Packet_Compression); ok { 263 | return x.Compression 264 | } 265 | return Compression_COMPRESSIONCOMPATIBLEPROTO2 266 | } 267 | 268 | func (x *Packet) GetBody() []byte { 269 | if x != nil { 270 | return x.Body 271 | } 272 | return nil 273 | } 274 | 275 | type isPacket_MagicNumberPresent interface { 276 | isPacket_MagicNumberPresent() 277 | } 278 | 279 | type Packet_MagicNumber struct { 280 | MagicNumber int32 `protobuf:"varint,1,opt,name=magic_number,json=magicNumber,proto3,oneof"` 281 | } 282 | 283 | func (*Packet_MagicNumber) isPacket_MagicNumberPresent() {} 284 | 285 | type isPacket_VersionPresent interface { 286 | isPacket_VersionPresent() 287 | } 288 | 289 | type Packet_Version struct { 290 | Version int32 `protobuf:"varint,2,opt,name=version,proto3,oneof"` 291 | } 292 | 293 | func (*Packet_Version) isPacket_VersionPresent() {} 294 | 295 | type isPacket_CompressionPresent interface { 296 | isPacket_CompressionPresent() 297 | } 298 | 299 | type Packet_Compression struct { 300 | Compression Compression `protobuf:"varint,4,opt,name=compression,proto3,enum=com.alibaba.otter.canal.protocol.packet.Compression,oneof"` 301 | } 302 | 303 | func (*Packet_Compression) isPacket_CompressionPresent() {} 304 | 305 | type HeartBeat struct { 306 | state protoimpl.MessageState 307 | sizeCache protoimpl.SizeCache 308 | unknownFields protoimpl.UnknownFields 309 | 310 | SendTimestamp int64 `protobuf:"varint,1,opt,name=send_timestamp,json=sendTimestamp,proto3" json:"send_timestamp,omitempty"` 311 | StartTimestamp int64 `protobuf:"varint,2,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"` 312 | } 313 | 314 | func (x *HeartBeat) Reset() { 315 | *x = HeartBeat{} 316 | if protoimpl.UnsafeEnabled { 317 | mi := &file_canal_protocol_proto_msgTypes[1] 318 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 319 | ms.StoreMessageInfo(mi) 320 | } 321 | } 322 | 323 | func (x *HeartBeat) String() string { 324 | return protoimpl.X.MessageStringOf(x) 325 | } 326 | 327 | func (*HeartBeat) ProtoMessage() {} 328 | 329 | func (x *HeartBeat) ProtoReflect() protoreflect.Message { 330 | mi := &file_canal_protocol_proto_msgTypes[1] 331 | if protoimpl.UnsafeEnabled && x != nil { 332 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 333 | if ms.LoadMessageInfo() == nil { 334 | ms.StoreMessageInfo(mi) 335 | } 336 | return ms 337 | } 338 | return mi.MessageOf(x) 339 | } 340 | 341 | // Deprecated: Use HeartBeat.ProtoReflect.Descriptor instead. 342 | func (*HeartBeat) Descriptor() ([]byte, []int) { 343 | return file_canal_protocol_proto_rawDescGZIP(), []int{1} 344 | } 345 | 346 | func (x *HeartBeat) GetSendTimestamp() int64 { 347 | if x != nil { 348 | return x.SendTimestamp 349 | } 350 | return 0 351 | } 352 | 353 | func (x *HeartBeat) GetStartTimestamp() int64 { 354 | if x != nil { 355 | return x.StartTimestamp 356 | } 357 | return 0 358 | } 359 | 360 | type Handshake struct { 361 | state protoimpl.MessageState 362 | sizeCache protoimpl.SizeCache 363 | unknownFields protoimpl.UnknownFields 364 | 365 | // [default = "utf8"]; 366 | // 367 | // Types that are assignable to CommunicationEncodingPresent: 368 | // 369 | // *Handshake_CommunicationEncoding 370 | CommunicationEncodingPresent isHandshake_CommunicationEncodingPresent `protobuf_oneof:"communication_encoding_present"` 371 | Seeds []byte `protobuf:"bytes,2,opt,name=seeds,proto3" json:"seeds,omitempty"` 372 | SupportedCompressions Compression `protobuf:"varint,3,opt,name=supported_compressions,json=supportedCompressions,proto3,enum=com.alibaba.otter.canal.protocol.packet.Compression" json:"supported_compressions,omitempty"` 373 | } 374 | 375 | func (x *Handshake) Reset() { 376 | *x = Handshake{} 377 | if protoimpl.UnsafeEnabled { 378 | mi := &file_canal_protocol_proto_msgTypes[2] 379 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 380 | ms.StoreMessageInfo(mi) 381 | } 382 | } 383 | 384 | func (x *Handshake) String() string { 385 | return protoimpl.X.MessageStringOf(x) 386 | } 387 | 388 | func (*Handshake) ProtoMessage() {} 389 | 390 | func (x *Handshake) ProtoReflect() protoreflect.Message { 391 | mi := &file_canal_protocol_proto_msgTypes[2] 392 | if protoimpl.UnsafeEnabled && x != nil { 393 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 394 | if ms.LoadMessageInfo() == nil { 395 | ms.StoreMessageInfo(mi) 396 | } 397 | return ms 398 | } 399 | return mi.MessageOf(x) 400 | } 401 | 402 | // Deprecated: Use Handshake.ProtoReflect.Descriptor instead. 403 | func (*Handshake) Descriptor() ([]byte, []int) { 404 | return file_canal_protocol_proto_rawDescGZIP(), []int{2} 405 | } 406 | 407 | func (m *Handshake) GetCommunicationEncodingPresent() isHandshake_CommunicationEncodingPresent { 408 | if m != nil { 409 | return m.CommunicationEncodingPresent 410 | } 411 | return nil 412 | } 413 | 414 | func (x *Handshake) GetCommunicationEncoding() string { 415 | if x, ok := x.GetCommunicationEncodingPresent().(*Handshake_CommunicationEncoding); ok { 416 | return x.CommunicationEncoding 417 | } 418 | return "" 419 | } 420 | 421 | func (x *Handshake) GetSeeds() []byte { 422 | if x != nil { 423 | return x.Seeds 424 | } 425 | return nil 426 | } 427 | 428 | func (x *Handshake) GetSupportedCompressions() Compression { 429 | if x != nil { 430 | return x.SupportedCompressions 431 | } 432 | return Compression_COMPRESSIONCOMPATIBLEPROTO2 433 | } 434 | 435 | type isHandshake_CommunicationEncodingPresent interface { 436 | isHandshake_CommunicationEncodingPresent() 437 | } 438 | 439 | type Handshake_CommunicationEncoding struct { 440 | CommunicationEncoding string `protobuf:"bytes,1,opt,name=communication_encoding,json=communicationEncoding,proto3,oneof"` 441 | } 442 | 443 | func (*Handshake_CommunicationEncoding) isHandshake_CommunicationEncodingPresent() {} 444 | 445 | // client authentication 446 | type ClientAuth struct { 447 | state protoimpl.MessageState 448 | sizeCache protoimpl.SizeCache 449 | unknownFields protoimpl.UnknownFields 450 | 451 | Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` 452 | Password []byte `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // hashed password with seeds from Handshake message 453 | // [default = 0] 454 | // 455 | // Types that are assignable to NetReadTimeoutPresent: 456 | // 457 | // *ClientAuth_NetReadTimeout 458 | NetReadTimeoutPresent isClientAuth_NetReadTimeoutPresent `protobuf_oneof:"net_read_timeout_present"` 459 | // [default = 0]; 460 | // 461 | // Types that are assignable to NetWriteTimeoutPresent: 462 | // 463 | // *ClientAuth_NetWriteTimeout 464 | NetWriteTimeoutPresent isClientAuth_NetWriteTimeoutPresent `protobuf_oneof:"net_write_timeout_present"` 465 | Destination string `protobuf:"bytes,5,opt,name=destination,proto3" json:"destination,omitempty"` 466 | ClientId string `protobuf:"bytes,6,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` 467 | Filter string `protobuf:"bytes,7,opt,name=filter,proto3" json:"filter,omitempty"` 468 | StartTimestamp int64 `protobuf:"varint,8,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"` 469 | } 470 | 471 | func (x *ClientAuth) Reset() { 472 | *x = ClientAuth{} 473 | if protoimpl.UnsafeEnabled { 474 | mi := &file_canal_protocol_proto_msgTypes[3] 475 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 476 | ms.StoreMessageInfo(mi) 477 | } 478 | } 479 | 480 | func (x *ClientAuth) String() string { 481 | return protoimpl.X.MessageStringOf(x) 482 | } 483 | 484 | func (*ClientAuth) ProtoMessage() {} 485 | 486 | func (x *ClientAuth) ProtoReflect() protoreflect.Message { 487 | mi := &file_canal_protocol_proto_msgTypes[3] 488 | if protoimpl.UnsafeEnabled && x != nil { 489 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 490 | if ms.LoadMessageInfo() == nil { 491 | ms.StoreMessageInfo(mi) 492 | } 493 | return ms 494 | } 495 | return mi.MessageOf(x) 496 | } 497 | 498 | // Deprecated: Use ClientAuth.ProtoReflect.Descriptor instead. 499 | func (*ClientAuth) Descriptor() ([]byte, []int) { 500 | return file_canal_protocol_proto_rawDescGZIP(), []int{3} 501 | } 502 | 503 | func (x *ClientAuth) GetUsername() string { 504 | if x != nil { 505 | return x.Username 506 | } 507 | return "" 508 | } 509 | 510 | func (x *ClientAuth) GetPassword() []byte { 511 | if x != nil { 512 | return x.Password 513 | } 514 | return nil 515 | } 516 | 517 | func (m *ClientAuth) GetNetReadTimeoutPresent() isClientAuth_NetReadTimeoutPresent { 518 | if m != nil { 519 | return m.NetReadTimeoutPresent 520 | } 521 | return nil 522 | } 523 | 524 | func (x *ClientAuth) GetNetReadTimeout() int32 { 525 | if x, ok := x.GetNetReadTimeoutPresent().(*ClientAuth_NetReadTimeout); ok { 526 | return x.NetReadTimeout 527 | } 528 | return 0 529 | } 530 | 531 | func (m *ClientAuth) GetNetWriteTimeoutPresent() isClientAuth_NetWriteTimeoutPresent { 532 | if m != nil { 533 | return m.NetWriteTimeoutPresent 534 | } 535 | return nil 536 | } 537 | 538 | func (x *ClientAuth) GetNetWriteTimeout() int32 { 539 | if x, ok := x.GetNetWriteTimeoutPresent().(*ClientAuth_NetWriteTimeout); ok { 540 | return x.NetWriteTimeout 541 | } 542 | return 0 543 | } 544 | 545 | func (x *ClientAuth) GetDestination() string { 546 | if x != nil { 547 | return x.Destination 548 | } 549 | return "" 550 | } 551 | 552 | func (x *ClientAuth) GetClientId() string { 553 | if x != nil { 554 | return x.ClientId 555 | } 556 | return "" 557 | } 558 | 559 | func (x *ClientAuth) GetFilter() string { 560 | if x != nil { 561 | return x.Filter 562 | } 563 | return "" 564 | } 565 | 566 | func (x *ClientAuth) GetStartTimestamp() int64 { 567 | if x != nil { 568 | return x.StartTimestamp 569 | } 570 | return 0 571 | } 572 | 573 | type isClientAuth_NetReadTimeoutPresent interface { 574 | isClientAuth_NetReadTimeoutPresent() 575 | } 576 | 577 | type ClientAuth_NetReadTimeout struct { 578 | NetReadTimeout int32 `protobuf:"varint,3,opt,name=net_read_timeout,json=netReadTimeout,proto3,oneof"` // in seconds 579 | } 580 | 581 | func (*ClientAuth_NetReadTimeout) isClientAuth_NetReadTimeoutPresent() {} 582 | 583 | type isClientAuth_NetWriteTimeoutPresent interface { 584 | isClientAuth_NetWriteTimeoutPresent() 585 | } 586 | 587 | type ClientAuth_NetWriteTimeout struct { 588 | NetWriteTimeout int32 `protobuf:"varint,4,opt,name=net_write_timeout,json=netWriteTimeout,proto3,oneof"` // in seconds 589 | } 590 | 591 | func (*ClientAuth_NetWriteTimeout) isClientAuth_NetWriteTimeoutPresent() {} 592 | 593 | type Ack struct { 594 | state protoimpl.MessageState 595 | sizeCache protoimpl.SizeCache 596 | unknownFields protoimpl.UnknownFields 597 | 598 | // [default = 0] 599 | // 600 | // Types that are assignable to ErrorCodePresent: 601 | // 602 | // *Ack_ErrorCode 603 | ErrorCodePresent isAck_ErrorCodePresent `protobuf_oneof:"error_code_present"` 604 | ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` // if something like compression is not supported, erorr_message will tell about it. 605 | } 606 | 607 | func (x *Ack) Reset() { 608 | *x = Ack{} 609 | if protoimpl.UnsafeEnabled { 610 | mi := &file_canal_protocol_proto_msgTypes[4] 611 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 612 | ms.StoreMessageInfo(mi) 613 | } 614 | } 615 | 616 | func (x *Ack) String() string { 617 | return protoimpl.X.MessageStringOf(x) 618 | } 619 | 620 | func (*Ack) ProtoMessage() {} 621 | 622 | func (x *Ack) ProtoReflect() protoreflect.Message { 623 | mi := &file_canal_protocol_proto_msgTypes[4] 624 | if protoimpl.UnsafeEnabled && x != nil { 625 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 626 | if ms.LoadMessageInfo() == nil { 627 | ms.StoreMessageInfo(mi) 628 | } 629 | return ms 630 | } 631 | return mi.MessageOf(x) 632 | } 633 | 634 | // Deprecated: Use Ack.ProtoReflect.Descriptor instead. 635 | func (*Ack) Descriptor() ([]byte, []int) { 636 | return file_canal_protocol_proto_rawDescGZIP(), []int{4} 637 | } 638 | 639 | func (m *Ack) GetErrorCodePresent() isAck_ErrorCodePresent { 640 | if m != nil { 641 | return m.ErrorCodePresent 642 | } 643 | return nil 644 | } 645 | 646 | func (x *Ack) GetErrorCode() int32 { 647 | if x, ok := x.GetErrorCodePresent().(*Ack_ErrorCode); ok { 648 | return x.ErrorCode 649 | } 650 | return 0 651 | } 652 | 653 | func (x *Ack) GetErrorMessage() string { 654 | if x != nil { 655 | return x.ErrorMessage 656 | } 657 | return "" 658 | } 659 | 660 | type isAck_ErrorCodePresent interface { 661 | isAck_ErrorCodePresent() 662 | } 663 | 664 | type Ack_ErrorCode struct { 665 | ErrorCode int32 `protobuf:"varint,1,opt,name=error_code,json=errorCode,proto3,oneof"` 666 | } 667 | 668 | func (*Ack_ErrorCode) isAck_ErrorCodePresent() {} 669 | 670 | type ClientAck struct { 671 | state protoimpl.MessageState 672 | sizeCache protoimpl.SizeCache 673 | unknownFields protoimpl.UnknownFields 674 | 675 | Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` 676 | ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` 677 | BatchId int64 `protobuf:"varint,3,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` 678 | } 679 | 680 | func (x *ClientAck) Reset() { 681 | *x = ClientAck{} 682 | if protoimpl.UnsafeEnabled { 683 | mi := &file_canal_protocol_proto_msgTypes[5] 684 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 685 | ms.StoreMessageInfo(mi) 686 | } 687 | } 688 | 689 | func (x *ClientAck) String() string { 690 | return protoimpl.X.MessageStringOf(x) 691 | } 692 | 693 | func (*ClientAck) ProtoMessage() {} 694 | 695 | func (x *ClientAck) ProtoReflect() protoreflect.Message { 696 | mi := &file_canal_protocol_proto_msgTypes[5] 697 | if protoimpl.UnsafeEnabled && x != nil { 698 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 699 | if ms.LoadMessageInfo() == nil { 700 | ms.StoreMessageInfo(mi) 701 | } 702 | return ms 703 | } 704 | return mi.MessageOf(x) 705 | } 706 | 707 | // Deprecated: Use ClientAck.ProtoReflect.Descriptor instead. 708 | func (*ClientAck) Descriptor() ([]byte, []int) { 709 | return file_canal_protocol_proto_rawDescGZIP(), []int{5} 710 | } 711 | 712 | func (x *ClientAck) GetDestination() string { 713 | if x != nil { 714 | return x.Destination 715 | } 716 | return "" 717 | } 718 | 719 | func (x *ClientAck) GetClientId() string { 720 | if x != nil { 721 | return x.ClientId 722 | } 723 | return "" 724 | } 725 | 726 | func (x *ClientAck) GetBatchId() int64 { 727 | if x != nil { 728 | return x.BatchId 729 | } 730 | return 0 731 | } 732 | 733 | // subscription 734 | type Sub struct { 735 | state protoimpl.MessageState 736 | sizeCache protoimpl.SizeCache 737 | unknownFields protoimpl.UnknownFields 738 | 739 | Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` 740 | ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` 741 | Filter string `protobuf:"bytes,7,opt,name=filter,proto3" json:"filter,omitempty"` 742 | } 743 | 744 | func (x *Sub) Reset() { 745 | *x = Sub{} 746 | if protoimpl.UnsafeEnabled { 747 | mi := &file_canal_protocol_proto_msgTypes[6] 748 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 749 | ms.StoreMessageInfo(mi) 750 | } 751 | } 752 | 753 | func (x *Sub) String() string { 754 | return protoimpl.X.MessageStringOf(x) 755 | } 756 | 757 | func (*Sub) ProtoMessage() {} 758 | 759 | func (x *Sub) ProtoReflect() protoreflect.Message { 760 | mi := &file_canal_protocol_proto_msgTypes[6] 761 | if protoimpl.UnsafeEnabled && x != nil { 762 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 763 | if ms.LoadMessageInfo() == nil { 764 | ms.StoreMessageInfo(mi) 765 | } 766 | return ms 767 | } 768 | return mi.MessageOf(x) 769 | } 770 | 771 | // Deprecated: Use Sub.ProtoReflect.Descriptor instead. 772 | func (*Sub) Descriptor() ([]byte, []int) { 773 | return file_canal_protocol_proto_rawDescGZIP(), []int{6} 774 | } 775 | 776 | func (x *Sub) GetDestination() string { 777 | if x != nil { 778 | return x.Destination 779 | } 780 | return "" 781 | } 782 | 783 | func (x *Sub) GetClientId() string { 784 | if x != nil { 785 | return x.ClientId 786 | } 787 | return "" 788 | } 789 | 790 | func (x *Sub) GetFilter() string { 791 | if x != nil { 792 | return x.Filter 793 | } 794 | return "" 795 | } 796 | 797 | // Unsubscription 798 | type Unsub struct { 799 | state protoimpl.MessageState 800 | sizeCache protoimpl.SizeCache 801 | unknownFields protoimpl.UnknownFields 802 | 803 | Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` 804 | ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` 805 | Filter string `protobuf:"bytes,7,opt,name=filter,proto3" json:"filter,omitempty"` 806 | } 807 | 808 | func (x *Unsub) Reset() { 809 | *x = Unsub{} 810 | if protoimpl.UnsafeEnabled { 811 | mi := &file_canal_protocol_proto_msgTypes[7] 812 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 813 | ms.StoreMessageInfo(mi) 814 | } 815 | } 816 | 817 | func (x *Unsub) String() string { 818 | return protoimpl.X.MessageStringOf(x) 819 | } 820 | 821 | func (*Unsub) ProtoMessage() {} 822 | 823 | func (x *Unsub) ProtoReflect() protoreflect.Message { 824 | mi := &file_canal_protocol_proto_msgTypes[7] 825 | if protoimpl.UnsafeEnabled && x != nil { 826 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 827 | if ms.LoadMessageInfo() == nil { 828 | ms.StoreMessageInfo(mi) 829 | } 830 | return ms 831 | } 832 | return mi.MessageOf(x) 833 | } 834 | 835 | // Deprecated: Use Unsub.ProtoReflect.Descriptor instead. 836 | func (*Unsub) Descriptor() ([]byte, []int) { 837 | return file_canal_protocol_proto_rawDescGZIP(), []int{7} 838 | } 839 | 840 | func (x *Unsub) GetDestination() string { 841 | if x != nil { 842 | return x.Destination 843 | } 844 | return "" 845 | } 846 | 847 | func (x *Unsub) GetClientId() string { 848 | if x != nil { 849 | return x.ClientId 850 | } 851 | return "" 852 | } 853 | 854 | func (x *Unsub) GetFilter() string { 855 | if x != nil { 856 | return x.Filter 857 | } 858 | return "" 859 | } 860 | 861 | // PullRequest 862 | type Get struct { 863 | state protoimpl.MessageState 864 | sizeCache protoimpl.SizeCache 865 | unknownFields protoimpl.UnknownFields 866 | 867 | Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` 868 | ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` 869 | FetchSize int32 `protobuf:"varint,3,opt,name=fetch_size,json=fetchSize,proto3" json:"fetch_size,omitempty"` 870 | // [default = -1] 871 | // 872 | // Types that are assignable to TimeoutPresent: 873 | // 874 | // *Get_Timeout 875 | TimeoutPresent isGet_TimeoutPresent `protobuf_oneof:"timeout_present"` 876 | // [default = 2] 877 | // 878 | // Types that are assignable to UnitPresent: 879 | // 880 | // *Get_Unit 881 | UnitPresent isGet_UnitPresent `protobuf_oneof:"unit_present"` 882 | // [default = false] 883 | // 884 | // Types that are assignable to AutoAckPresent: 885 | // 886 | // *Get_AutoAck 887 | AutoAckPresent isGet_AutoAckPresent `protobuf_oneof:"auto_ack_present"` 888 | } 889 | 890 | func (x *Get) Reset() { 891 | *x = Get{} 892 | if protoimpl.UnsafeEnabled { 893 | mi := &file_canal_protocol_proto_msgTypes[8] 894 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 895 | ms.StoreMessageInfo(mi) 896 | } 897 | } 898 | 899 | func (x *Get) String() string { 900 | return protoimpl.X.MessageStringOf(x) 901 | } 902 | 903 | func (*Get) ProtoMessage() {} 904 | 905 | func (x *Get) ProtoReflect() protoreflect.Message { 906 | mi := &file_canal_protocol_proto_msgTypes[8] 907 | if protoimpl.UnsafeEnabled && x != nil { 908 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 909 | if ms.LoadMessageInfo() == nil { 910 | ms.StoreMessageInfo(mi) 911 | } 912 | return ms 913 | } 914 | return mi.MessageOf(x) 915 | } 916 | 917 | // Deprecated: Use Get.ProtoReflect.Descriptor instead. 918 | func (*Get) Descriptor() ([]byte, []int) { 919 | return file_canal_protocol_proto_rawDescGZIP(), []int{8} 920 | } 921 | 922 | func (x *Get) GetDestination() string { 923 | if x != nil { 924 | return x.Destination 925 | } 926 | return "" 927 | } 928 | 929 | func (x *Get) GetClientId() string { 930 | if x != nil { 931 | return x.ClientId 932 | } 933 | return "" 934 | } 935 | 936 | func (x *Get) GetFetchSize() int32 { 937 | if x != nil { 938 | return x.FetchSize 939 | } 940 | return 0 941 | } 942 | 943 | func (m *Get) GetTimeoutPresent() isGet_TimeoutPresent { 944 | if m != nil { 945 | return m.TimeoutPresent 946 | } 947 | return nil 948 | } 949 | 950 | func (x *Get) GetTimeout() int64 { 951 | if x, ok := x.GetTimeoutPresent().(*Get_Timeout); ok { 952 | return x.Timeout 953 | } 954 | return 0 955 | } 956 | 957 | func (m *Get) GetUnitPresent() isGet_UnitPresent { 958 | if m != nil { 959 | return m.UnitPresent 960 | } 961 | return nil 962 | } 963 | 964 | func (x *Get) GetUnit() int32 { 965 | if x, ok := x.GetUnitPresent().(*Get_Unit); ok { 966 | return x.Unit 967 | } 968 | return 0 969 | } 970 | 971 | func (m *Get) GetAutoAckPresent() isGet_AutoAckPresent { 972 | if m != nil { 973 | return m.AutoAckPresent 974 | } 975 | return nil 976 | } 977 | 978 | func (x *Get) GetAutoAck() bool { 979 | if x, ok := x.GetAutoAckPresent().(*Get_AutoAck); ok { 980 | return x.AutoAck 981 | } 982 | return false 983 | } 984 | 985 | type isGet_TimeoutPresent interface { 986 | isGet_TimeoutPresent() 987 | } 988 | 989 | type Get_Timeout struct { 990 | Timeout int64 `protobuf:"varint,4,opt,name=timeout,proto3,oneof"` // 默认-1时代表不控制 991 | } 992 | 993 | func (*Get_Timeout) isGet_TimeoutPresent() {} 994 | 995 | type isGet_UnitPresent interface { 996 | isGet_UnitPresent() 997 | } 998 | 999 | type Get_Unit struct { 1000 | Unit int32 `protobuf:"varint,5,opt,name=unit,proto3,oneof"` // 数字类型,0:纳秒,1:微秒,2:毫秒,3:秒,4:分钟,5:小时,6:天 1001 | } 1002 | 1003 | func (*Get_Unit) isGet_UnitPresent() {} 1004 | 1005 | type isGet_AutoAckPresent interface { 1006 | isGet_AutoAckPresent() 1007 | } 1008 | 1009 | type Get_AutoAck struct { 1010 | AutoAck bool `protobuf:"varint,6,opt,name=auto_ack,json=autoAck,proto3,oneof"` // 是否自动ack 1011 | } 1012 | 1013 | func (*Get_AutoAck) isGet_AutoAckPresent() {} 1014 | 1015 | type Messages struct { 1016 | state protoimpl.MessageState 1017 | sizeCache protoimpl.SizeCache 1018 | unknownFields protoimpl.UnknownFields 1019 | 1020 | BatchId int64 `protobuf:"varint,1,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` 1021 | Messages [][]byte `protobuf:"bytes,2,rep,name=messages,proto3" json:"messages,omitempty"` 1022 | } 1023 | 1024 | func (x *Messages) Reset() { 1025 | *x = Messages{} 1026 | if protoimpl.UnsafeEnabled { 1027 | mi := &file_canal_protocol_proto_msgTypes[9] 1028 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1029 | ms.StoreMessageInfo(mi) 1030 | } 1031 | } 1032 | 1033 | func (x *Messages) String() string { 1034 | return protoimpl.X.MessageStringOf(x) 1035 | } 1036 | 1037 | func (*Messages) ProtoMessage() {} 1038 | 1039 | func (x *Messages) ProtoReflect() protoreflect.Message { 1040 | mi := &file_canal_protocol_proto_msgTypes[9] 1041 | if protoimpl.UnsafeEnabled && x != nil { 1042 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1043 | if ms.LoadMessageInfo() == nil { 1044 | ms.StoreMessageInfo(mi) 1045 | } 1046 | return ms 1047 | } 1048 | return mi.MessageOf(x) 1049 | } 1050 | 1051 | // Deprecated: Use Messages.ProtoReflect.Descriptor instead. 1052 | func (*Messages) Descriptor() ([]byte, []int) { 1053 | return file_canal_protocol_proto_rawDescGZIP(), []int{9} 1054 | } 1055 | 1056 | func (x *Messages) GetBatchId() int64 { 1057 | if x != nil { 1058 | return x.BatchId 1059 | } 1060 | return 0 1061 | } 1062 | 1063 | func (x *Messages) GetMessages() [][]byte { 1064 | if x != nil { 1065 | return x.Messages 1066 | } 1067 | return nil 1068 | } 1069 | 1070 | // TBD when new packets are required 1071 | type Dump struct { 1072 | state protoimpl.MessageState 1073 | sizeCache protoimpl.SizeCache 1074 | unknownFields protoimpl.UnknownFields 1075 | 1076 | Journal string `protobuf:"bytes,1,opt,name=journal,proto3" json:"journal,omitempty"` 1077 | Position int64 `protobuf:"varint,2,opt,name=position,proto3" json:"position,omitempty"` 1078 | // [default = 0] 1079 | // 1080 | // Types that are assignable to TimestampPresent: 1081 | // 1082 | // *Dump_Timestamp 1083 | TimestampPresent isDump_TimestampPresent `protobuf_oneof:"timestamp_present"` 1084 | } 1085 | 1086 | func (x *Dump) Reset() { 1087 | *x = Dump{} 1088 | if protoimpl.UnsafeEnabled { 1089 | mi := &file_canal_protocol_proto_msgTypes[10] 1090 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1091 | ms.StoreMessageInfo(mi) 1092 | } 1093 | } 1094 | 1095 | func (x *Dump) String() string { 1096 | return protoimpl.X.MessageStringOf(x) 1097 | } 1098 | 1099 | func (*Dump) ProtoMessage() {} 1100 | 1101 | func (x *Dump) ProtoReflect() protoreflect.Message { 1102 | mi := &file_canal_protocol_proto_msgTypes[10] 1103 | if protoimpl.UnsafeEnabled && x != nil { 1104 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1105 | if ms.LoadMessageInfo() == nil { 1106 | ms.StoreMessageInfo(mi) 1107 | } 1108 | return ms 1109 | } 1110 | return mi.MessageOf(x) 1111 | } 1112 | 1113 | // Deprecated: Use Dump.ProtoReflect.Descriptor instead. 1114 | func (*Dump) Descriptor() ([]byte, []int) { 1115 | return file_canal_protocol_proto_rawDescGZIP(), []int{10} 1116 | } 1117 | 1118 | func (x *Dump) GetJournal() string { 1119 | if x != nil { 1120 | return x.Journal 1121 | } 1122 | return "" 1123 | } 1124 | 1125 | func (x *Dump) GetPosition() int64 { 1126 | if x != nil { 1127 | return x.Position 1128 | } 1129 | return 0 1130 | } 1131 | 1132 | func (m *Dump) GetTimestampPresent() isDump_TimestampPresent { 1133 | if m != nil { 1134 | return m.TimestampPresent 1135 | } 1136 | return nil 1137 | } 1138 | 1139 | func (x *Dump) GetTimestamp() int64 { 1140 | if x, ok := x.GetTimestampPresent().(*Dump_Timestamp); ok { 1141 | return x.Timestamp 1142 | } 1143 | return 0 1144 | } 1145 | 1146 | type isDump_TimestampPresent interface { 1147 | isDump_TimestampPresent() 1148 | } 1149 | 1150 | type Dump_Timestamp struct { 1151 | Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3,oneof"` 1152 | } 1153 | 1154 | func (*Dump_Timestamp) isDump_TimestampPresent() {} 1155 | 1156 | type ClientRollback struct { 1157 | state protoimpl.MessageState 1158 | sizeCache protoimpl.SizeCache 1159 | unknownFields protoimpl.UnknownFields 1160 | 1161 | Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` 1162 | ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` 1163 | BatchId int64 `protobuf:"varint,3,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` 1164 | } 1165 | 1166 | func (x *ClientRollback) Reset() { 1167 | *x = ClientRollback{} 1168 | if protoimpl.UnsafeEnabled { 1169 | mi := &file_canal_protocol_proto_msgTypes[11] 1170 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1171 | ms.StoreMessageInfo(mi) 1172 | } 1173 | } 1174 | 1175 | func (x *ClientRollback) String() string { 1176 | return protoimpl.X.MessageStringOf(x) 1177 | } 1178 | 1179 | func (*ClientRollback) ProtoMessage() {} 1180 | 1181 | func (x *ClientRollback) ProtoReflect() protoreflect.Message { 1182 | mi := &file_canal_protocol_proto_msgTypes[11] 1183 | if protoimpl.UnsafeEnabled && x != nil { 1184 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 1185 | if ms.LoadMessageInfo() == nil { 1186 | ms.StoreMessageInfo(mi) 1187 | } 1188 | return ms 1189 | } 1190 | return mi.MessageOf(x) 1191 | } 1192 | 1193 | // Deprecated: Use ClientRollback.ProtoReflect.Descriptor instead. 1194 | func (*ClientRollback) Descriptor() ([]byte, []int) { 1195 | return file_canal_protocol_proto_rawDescGZIP(), []int{11} 1196 | } 1197 | 1198 | func (x *ClientRollback) GetDestination() string { 1199 | if x != nil { 1200 | return x.Destination 1201 | } 1202 | return "" 1203 | } 1204 | 1205 | func (x *ClientRollback) GetClientId() string { 1206 | if x != nil { 1207 | return x.ClientId 1208 | } 1209 | return "" 1210 | } 1211 | 1212 | func (x *ClientRollback) GetBatchId() int64 { 1213 | if x != nil { 1214 | return x.BatchId 1215 | } 1216 | return 0 1217 | } 1218 | 1219 | var File_canal_protocol_proto protoreflect.FileDescriptor 1220 | 1221 | var file_canal_protocol_proto_rawDesc = []byte{ 1222 | 0x0a, 0x14, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 1223 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x27, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 1224 | 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 1225 | 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 1226 | 0xc2, 0x02, 0x0a, 0x06, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x23, 0x0a, 0x0c, 0x6d, 0x61, 1227 | 0x67, 0x69, 0x63, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 1228 | 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 1229 | 0x1a, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 1230 | 0x48, 0x01, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x04, 0x74, 1231 | 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 1232 | 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 1233 | 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x70, 0x61, 0x63, 1234 | 0x6b, 0x65, 0x74, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 1235 | 0x74, 0x79, 0x70, 0x65, 0x12, 0x58, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 1236 | 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 1237 | 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x61, 1238 | 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x70, 0x61, 0x63, 1239 | 0x6b, 0x65, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 1240 | 0x02, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 1241 | 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 1242 | 0x64, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 1243 | 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x11, 0x0a, 0x0f, 0x76, 0x65, 1244 | 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x15, 0x0a, 1245 | 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 1246 | 0x73, 0x65, 0x6e, 0x74, 0x22, 0x5b, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x42, 0x65, 0x61, 1247 | 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 1248 | 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x64, 0x54, 1249 | 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 1250 | 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 1251 | 0x03, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 1252 | 0x70, 0x22, 0xe9, 0x01, 0x0a, 0x09, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x12, 1253 | 0x37, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 1254 | 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 1255 | 0x00, 0x52, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 1256 | 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x65, 0x65, 0x64, 1257 | 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x65, 0x65, 0x64, 0x73, 0x12, 0x6b, 1258 | 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 1259 | 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 1260 | 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 1261 | 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 1262 | 0x6c, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 1263 | 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x15, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 1264 | 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x20, 0x0a, 0x1e, 0x63, 1265 | 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x63, 1266 | 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0xd7, 0x02, 1267 | 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 1268 | 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 1269 | 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 1270 | 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 1271 | 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 1272 | 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 1273 | 0x52, 0x0e, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 1274 | 0x12, 0x2c, 0x0a, 0x11, 0x6e, 0x65, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x74, 0x69, 1275 | 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x0f, 0x6e, 1276 | 0x65, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x20, 1277 | 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 1278 | 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 1279 | 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 1280 | 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 1281 | 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 1282 | 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 1283 | 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 1284 | 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x1a, 1285 | 0x0a, 0x18, 0x6e, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 1286 | 0x75, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x1b, 0x0a, 0x19, 0x6e, 0x65, 1287 | 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 1288 | 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0x61, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x1f, 1289 | 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 1290 | 0x28, 0x05, 0x48, 0x00, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 1291 | 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 1292 | 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 1293 | 0x73, 0x61, 0x67, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 1294 | 0x64, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0x65, 0x0a, 0x09, 0x43, 0x6c, 1295 | 0x69, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 1296 | 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 1297 | 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 1298 | 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 1299 | 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 1300 | 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 1301 | 0x64, 0x22, 0x5c, 0x0a, 0x03, 0x53, 0x75, 0x62, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 1302 | 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 1303 | 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 1304 | 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 1305 | 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 1306 | 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 1307 | 0x5e, 0x0a, 0x05, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 1308 | 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 1309 | 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 1310 | 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 1311 | 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 1312 | 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 1313 | 0xe9, 0x01, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 1314 | 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 1315 | 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 1316 | 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 1317 | 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 1318 | 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x66, 0x65, 0x74, 0x63, 1319 | 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 1320 | 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 1321 | 0x74, 0x12, 0x14, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x48, 1322 | 0x01, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x5f, 1323 | 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x48, 0x02, 0x52, 0x07, 0x61, 0x75, 0x74, 1324 | 0x6f, 0x41, 0x63, 0x6b, 0x42, 0x11, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 1325 | 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x0e, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x74, 0x5f, 1326 | 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x61, 0x75, 0x74, 0x6f, 0x5f, 1327 | 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x22, 0x41, 0x0a, 0x08, 0x4d, 1328 | 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 1329 | 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 1330 | 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 1331 | 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x71, 1332 | 0x0a, 0x04, 0x44, 0x75, 0x6d, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x6a, 0x6f, 0x75, 0x72, 0x6e, 0x61, 1333 | 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x75, 0x72, 0x6e, 0x61, 0x6c, 1334 | 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 1335 | 0x28, 0x03, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x09, 1336 | 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 1337 | 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x13, 0x0a, 0x11, 1338 | 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 1339 | 0x74, 0x22, 0x6a, 0x0a, 0x0e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 1340 | 0x61, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 1341 | 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 1342 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 1343 | 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 1344 | 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x03, 1345 | 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x2a, 0x55, 0x0a, 1346 | 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x1b, 1347 | 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, 1348 | 0x54, 0x49, 0x42, 0x4c, 0x45, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x32, 0x10, 0x00, 0x12, 0x08, 0x0a, 1349 | 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x5a, 0x4c, 0x49, 0x42, 0x10, 1350 | 0x02, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x5a, 0x49, 0x50, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4c, 1351 | 0x5a, 0x46, 0x10, 0x04, 0x2a, 0xe6, 0x01, 0x0a, 0x0a, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x54, 1352 | 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x54, 0x59, 1353 | 0x50, 0x45, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x50, 0x52, 0x4f, 0x54, 1354 | 0x4f, 0x32, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x41, 0x4e, 0x44, 0x53, 0x48, 0x41, 0x4b, 1355 | 0x45, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x41, 0x55, 0x54, 1356 | 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x07, 0x0a, 1357 | 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 1358 | 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x53, 0x55, 1359 | 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 1360 | 0x47, 0x45, 0x54, 0x10, 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 1361 | 0x53, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x41, 0x43, 0x4b, 1362 | 0x10, 0x08, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x09, 1363 | 0x12, 0x08, 0x0a, 0x04, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x0a, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 1364 | 0x41, 0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x0b, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x49, 1365 | 0x45, 0x4e, 0x54, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x0c, 0x42, 0x3c, 0x0a, 1366 | 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x2e, 0x6f, 0x74, 0x74, 1367 | 0x65, 0x72, 0x2e, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 1368 | 0x6c, 0x42, 0x0b, 0x43, 0x61, 0x6e, 0x61, 0x6c, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x48, 0x01, 1369 | 0x5a, 0x09, 0x2e, 0x2f, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 1370 | 0x74, 0x6f, 0x33, 1371 | } 1372 | 1373 | var ( 1374 | file_canal_protocol_proto_rawDescOnce sync.Once 1375 | file_canal_protocol_proto_rawDescData = file_canal_protocol_proto_rawDesc 1376 | ) 1377 | 1378 | func file_canal_protocol_proto_rawDescGZIP() []byte { 1379 | file_canal_protocol_proto_rawDescOnce.Do(func() { 1380 | file_canal_protocol_proto_rawDescData = protoimpl.X.CompressGZIP(file_canal_protocol_proto_rawDescData) 1381 | }) 1382 | return file_canal_protocol_proto_rawDescData 1383 | } 1384 | 1385 | var file_canal_protocol_proto_enumTypes = make([]protoimpl.EnumInfo, 2) 1386 | var file_canal_protocol_proto_msgTypes = make([]protoimpl.MessageInfo, 12) 1387 | var file_canal_protocol_proto_goTypes = []interface{}{ 1388 | (Compression)(0), // 0: com.alibaba.otter.canal.protocol.packet.Compression 1389 | (PacketType)(0), // 1: com.alibaba.otter.canal.protocol.packet.PacketType 1390 | (*Packet)(nil), // 2: com.alibaba.otter.canal.protocol.packet.Packet 1391 | (*HeartBeat)(nil), // 3: com.alibaba.otter.canal.protocol.packet.HeartBeat 1392 | (*Handshake)(nil), // 4: com.alibaba.otter.canal.protocol.packet.Handshake 1393 | (*ClientAuth)(nil), // 5: com.alibaba.otter.canal.protocol.packet.ClientAuth 1394 | (*Ack)(nil), // 6: com.alibaba.otter.canal.protocol.packet.Ack 1395 | (*ClientAck)(nil), // 7: com.alibaba.otter.canal.protocol.packet.ClientAck 1396 | (*Sub)(nil), // 8: com.alibaba.otter.canal.protocol.packet.Sub 1397 | (*Unsub)(nil), // 9: com.alibaba.otter.canal.protocol.packet.Unsub 1398 | (*Get)(nil), // 10: com.alibaba.otter.canal.protocol.packet.Get 1399 | (*Messages)(nil), // 11: com.alibaba.otter.canal.protocol.packet.Messages 1400 | (*Dump)(nil), // 12: com.alibaba.otter.canal.protocol.packet.Dump 1401 | (*ClientRollback)(nil), // 13: com.alibaba.otter.canal.protocol.packet.ClientRollback 1402 | } 1403 | var file_canal_protocol_proto_depIdxs = []int32{ 1404 | 1, // 0: com.alibaba.otter.canal.protocol.packet.Packet.type:type_name -> com.alibaba.otter.canal.protocol.packet.PacketType 1405 | 0, // 1: com.alibaba.otter.canal.protocol.packet.Packet.compression:type_name -> com.alibaba.otter.canal.protocol.packet.Compression 1406 | 0, // 2: com.alibaba.otter.canal.protocol.packet.Handshake.supported_compressions:type_name -> com.alibaba.otter.canal.protocol.packet.Compression 1407 | 3, // [3:3] is the sub-list for method output_type 1408 | 3, // [3:3] is the sub-list for method input_type 1409 | 3, // [3:3] is the sub-list for extension type_name 1410 | 3, // [3:3] is the sub-list for extension extendee 1411 | 0, // [0:3] is the sub-list for field type_name 1412 | } 1413 | 1414 | func init() { file_canal_protocol_proto_init() } 1415 | func file_canal_protocol_proto_init() { 1416 | if File_canal_protocol_proto != nil { 1417 | return 1418 | } 1419 | if !protoimpl.UnsafeEnabled { 1420 | file_canal_protocol_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 1421 | switch v := v.(*Packet); i { 1422 | case 0: 1423 | return &v.state 1424 | case 1: 1425 | return &v.sizeCache 1426 | case 2: 1427 | return &v.unknownFields 1428 | default: 1429 | return nil 1430 | } 1431 | } 1432 | file_canal_protocol_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 1433 | switch v := v.(*HeartBeat); i { 1434 | case 0: 1435 | return &v.state 1436 | case 1: 1437 | return &v.sizeCache 1438 | case 2: 1439 | return &v.unknownFields 1440 | default: 1441 | return nil 1442 | } 1443 | } 1444 | file_canal_protocol_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 1445 | switch v := v.(*Handshake); i { 1446 | case 0: 1447 | return &v.state 1448 | case 1: 1449 | return &v.sizeCache 1450 | case 2: 1451 | return &v.unknownFields 1452 | default: 1453 | return nil 1454 | } 1455 | } 1456 | file_canal_protocol_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 1457 | switch v := v.(*ClientAuth); i { 1458 | case 0: 1459 | return &v.state 1460 | case 1: 1461 | return &v.sizeCache 1462 | case 2: 1463 | return &v.unknownFields 1464 | default: 1465 | return nil 1466 | } 1467 | } 1468 | file_canal_protocol_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 1469 | switch v := v.(*Ack); i { 1470 | case 0: 1471 | return &v.state 1472 | case 1: 1473 | return &v.sizeCache 1474 | case 2: 1475 | return &v.unknownFields 1476 | default: 1477 | return nil 1478 | } 1479 | } 1480 | file_canal_protocol_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { 1481 | switch v := v.(*ClientAck); i { 1482 | case 0: 1483 | return &v.state 1484 | case 1: 1485 | return &v.sizeCache 1486 | case 2: 1487 | return &v.unknownFields 1488 | default: 1489 | return nil 1490 | } 1491 | } 1492 | file_canal_protocol_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { 1493 | switch v := v.(*Sub); i { 1494 | case 0: 1495 | return &v.state 1496 | case 1: 1497 | return &v.sizeCache 1498 | case 2: 1499 | return &v.unknownFields 1500 | default: 1501 | return nil 1502 | } 1503 | } 1504 | file_canal_protocol_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { 1505 | switch v := v.(*Unsub); i { 1506 | case 0: 1507 | return &v.state 1508 | case 1: 1509 | return &v.sizeCache 1510 | case 2: 1511 | return &v.unknownFields 1512 | default: 1513 | return nil 1514 | } 1515 | } 1516 | file_canal_protocol_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { 1517 | switch v := v.(*Get); i { 1518 | case 0: 1519 | return &v.state 1520 | case 1: 1521 | return &v.sizeCache 1522 | case 2: 1523 | return &v.unknownFields 1524 | default: 1525 | return nil 1526 | } 1527 | } 1528 | file_canal_protocol_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { 1529 | switch v := v.(*Messages); i { 1530 | case 0: 1531 | return &v.state 1532 | case 1: 1533 | return &v.sizeCache 1534 | case 2: 1535 | return &v.unknownFields 1536 | default: 1537 | return nil 1538 | } 1539 | } 1540 | file_canal_protocol_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { 1541 | switch v := v.(*Dump); i { 1542 | case 0: 1543 | return &v.state 1544 | case 1: 1545 | return &v.sizeCache 1546 | case 2: 1547 | return &v.unknownFields 1548 | default: 1549 | return nil 1550 | } 1551 | } 1552 | file_canal_protocol_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { 1553 | switch v := v.(*ClientRollback); i { 1554 | case 0: 1555 | return &v.state 1556 | case 1: 1557 | return &v.sizeCache 1558 | case 2: 1559 | return &v.unknownFields 1560 | default: 1561 | return nil 1562 | } 1563 | } 1564 | } 1565 | file_canal_protocol_proto_msgTypes[0].OneofWrappers = []interface{}{ 1566 | (*Packet_MagicNumber)(nil), 1567 | (*Packet_Version)(nil), 1568 | (*Packet_Compression)(nil), 1569 | } 1570 | file_canal_protocol_proto_msgTypes[2].OneofWrappers = []interface{}{ 1571 | (*Handshake_CommunicationEncoding)(nil), 1572 | } 1573 | file_canal_protocol_proto_msgTypes[3].OneofWrappers = []interface{}{ 1574 | (*ClientAuth_NetReadTimeout)(nil), 1575 | (*ClientAuth_NetWriteTimeout)(nil), 1576 | } 1577 | file_canal_protocol_proto_msgTypes[4].OneofWrappers = []interface{}{ 1578 | (*Ack_ErrorCode)(nil), 1579 | } 1580 | file_canal_protocol_proto_msgTypes[8].OneofWrappers = []interface{}{ 1581 | (*Get_Timeout)(nil), 1582 | (*Get_Unit)(nil), 1583 | (*Get_AutoAck)(nil), 1584 | } 1585 | file_canal_protocol_proto_msgTypes[10].OneofWrappers = []interface{}{ 1586 | (*Dump_Timestamp)(nil), 1587 | } 1588 | type x struct{} 1589 | out := protoimpl.TypeBuilder{ 1590 | File: protoimpl.DescBuilder{ 1591 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 1592 | RawDescriptor: file_canal_protocol_proto_rawDesc, 1593 | NumEnums: 2, 1594 | NumMessages: 12, 1595 | NumExtensions: 0, 1596 | NumServices: 0, 1597 | }, 1598 | GoTypes: file_canal_protocol_proto_goTypes, 1599 | DependencyIndexes: file_canal_protocol_proto_depIdxs, 1600 | EnumInfos: file_canal_protocol_proto_enumTypes, 1601 | MessageInfos: file_canal_protocol_proto_msgTypes, 1602 | }.Build() 1603 | File_canal_protocol_proto = out.File 1604 | file_canal_protocol_proto_rawDesc = nil 1605 | file_canal_protocol_proto_goTypes = nil 1606 | file_canal_protocol_proto_depIdxs = nil 1607 | } 1608 | -------------------------------------------------------------------------------- /protocol/packet/canal_protocol.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package com.alibaba.otter.canal.protocol.packet; 3 | 4 | option java_package = "com.alibaba.otter.canal.protocol"; 5 | option java_outer_classname = "CanalPacket"; 6 | option optimize_for = SPEED; 7 | 8 | option go_package = "./;packet"; 9 | 10 | enum Compression { 11 | COMPRESSIONCOMPATIBLEPROTO2 = 0; 12 | NONE = 1; 13 | ZLIB = 2; 14 | GZIP = 3; 15 | LZF = 4; 16 | } 17 | 18 | enum PacketType { 19 | //compatible 20 | PACKAGETYPECOMPATIBLEPROTO2 = 0; 21 | HANDSHAKE = 1; 22 | CLIENTAUTHENTICATION = 2; 23 | ACK = 3; 24 | SUBSCRIPTION = 4; 25 | UNSUBSCRIPTION = 5; 26 | GET = 6; 27 | MESSAGES = 7; 28 | CLIENTACK = 8; 29 | // management part 30 | SHUTDOWN = 9; 31 | // integration 32 | DUMP = 10; 33 | HEARTBEAT = 11; 34 | CLIENTROLLBACK = 12; 35 | } 36 | 37 | message Packet { 38 | //[default = 17]; 39 | oneof magic_number_present { 40 | int32 magic_number = 1; 41 | } 42 | //[default = 1]; 43 | oneof version_present { 44 | int32 version = 2; 45 | }; 46 | PacketType type = 3; 47 | //[default = NONE]; 48 | oneof compression_present { 49 | Compression compression = 4; 50 | } 51 | 52 | bytes body = 5; 53 | } 54 | 55 | message HeartBeat { 56 | int64 send_timestamp = 1; 57 | int64 start_timestamp = 2; 58 | } 59 | 60 | message Handshake { 61 | // [default = "utf8"]; 62 | oneof communication_encoding_present { 63 | string communication_encoding = 1; 64 | } 65 | bytes seeds = 2; 66 | Compression supported_compressions = 3; 67 | } 68 | 69 | // client authentication 70 | message ClientAuth { 71 | string username = 1; 72 | bytes password = 2; // hashed password with seeds from Handshake message 73 | // [default = 0] 74 | oneof net_read_timeout_present { 75 | int32 net_read_timeout = 3; // in seconds 76 | } 77 | // [default = 0]; 78 | oneof net_write_timeout_present { 79 | int32 net_write_timeout = 4; // in seconds 80 | } 81 | string destination = 5; 82 | string client_id = 6; 83 | string filter = 7; 84 | int64 start_timestamp = 8; 85 | } 86 | 87 | message Ack { 88 | //[default = 0] 89 | oneof error_code_present { 90 | int32 error_code = 1; 91 | } 92 | string error_message = 2; // if something like compression is not supported, erorr_message will tell about it. 93 | } 94 | 95 | message ClientAck { 96 | string destination = 1; 97 | string client_id = 2; 98 | int64 batch_id = 3; 99 | } 100 | 101 | // subscription 102 | message Sub { 103 | string destination = 1; 104 | string client_id = 2; 105 | string filter = 7; 106 | } 107 | 108 | // Unsubscription 109 | message Unsub { 110 | string destination = 1; 111 | string client_id = 2; 112 | string filter = 7; 113 | } 114 | 115 | // PullRequest 116 | message Get { 117 | string destination = 1; 118 | string client_id = 2; 119 | int32 fetch_size = 3; 120 | //[default = -1] 121 | oneof timeout_present { 122 | int64 timeout = 4; // 默认-1时代表不控制 123 | } 124 | //[default = 2] 125 | oneof unit_present { 126 | int32 unit = 5;// 数字类型,0:纳秒,1:微秒,2:毫秒,3:秒,4:分钟,5:小时,6:天 127 | } 128 | //[default = false] 129 | oneof auto_ack_present { 130 | bool auto_ack = 6; // 是否自动ack 131 | } 132 | 133 | } 134 | 135 | // 136 | message Messages { 137 | int64 batch_id = 1; 138 | repeated bytes messages = 2; 139 | } 140 | 141 | // TBD when new packets are required 142 | message Dump{ 143 | string journal = 1; 144 | int64 position = 2; 145 | // [default = 0] 146 | oneof timestamp_present { 147 | int64 timestamp = 3; 148 | } 149 | 150 | } 151 | 152 | message ClientRollback{ 153 | string destination = 1; 154 | string client_id = 2; 155 | int64 batch_id = 3; 156 | } -------------------------------------------------------------------------------- /protocol/position/doc.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | -------------------------------------------------------------------------------- /protocol/position/entry_position.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | 19 | const ( 20 | EVENTIDENTITY_SEGMENT = 3 21 | EVENTIDENTITY_SPLIT = 5 22 | ) 23 | 24 | type EntryPosition struct { 25 | TimePosition 26 | Included bool 27 | JournalName string 28 | Position int64 29 | ServerId int64 30 | } 31 | 32 | func NewEntryPosition(journalName string, position int64, timestamp int64, serverId int64, Included bool) *EntryPosition { 33 | entryPosition := &EntryPosition{TimePosition{timestamp}, false, journalName, position, serverId} 34 | return entryPosition 35 | } 36 | -------------------------------------------------------------------------------- /protocol/position/log_identity.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | 19 | type LogIdentity struct { 20 | SourceAddress string 21 | SlaveId int64 22 | } 23 | -------------------------------------------------------------------------------- /protocol/position/log_position.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | 19 | type LogPosition struct { 20 | Identity LogIdentity 21 | Postion EntryPosition 22 | } 23 | -------------------------------------------------------------------------------- /protocol/position/metaq_position.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | 19 | type MetaqPosition struct { 20 | Topic string 21 | MsgNewId string 22 | Offset int64 23 | } 24 | -------------------------------------------------------------------------------- /protocol/position/position.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | 19 | type Position interface { 20 | } 21 | -------------------------------------------------------------------------------- /protocol/position/time_position.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package position 18 | 19 | type TimePosition struct { 20 | Timestamp int64 21 | } 22 | 23 | func NewTimePosition(timestamp int64) *TimePosition { 24 | tstamp := &TimePosition{Timestamp: timestamp} 25 | return tstamp 26 | } 27 | -------------------------------------------------------------------------------- /samples/cluster/cluster_main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/withlin/canal-go/client" 6 | pbe "github.com/withlin/canal-go/protocol/entry" 7 | proto "google.golang.org/protobuf/proto" 8 | "log" 9 | "os" 10 | "time" 11 | ) 12 | 13 | var conn *client.ClusterCanalConnector 14 | 15 | func main() { 16 | conn = createConnection() 17 | subscribe(conn, ".*\\..*") 18 | 19 | fmt.Println("canal start listening...") 20 | listen() 21 | err := conn.DisConnection() 22 | if err != nil { 23 | fmt.Println(err) 24 | } 25 | } 26 | 27 | func listen() { 28 | for { 29 | message, err := conn.Get(100, nil, nil) 30 | if err != nil { 31 | fmt.Println(err) 32 | return 33 | } 34 | 35 | batchId := message.Id 36 | if batchId == -1 || len(message.Entries) <= 0 { 37 | time.Sleep(200 * time.Millisecond) 38 | continue 39 | } 40 | 41 | printEntry(message.Entries) 42 | } 43 | } 44 | 45 | func subscribe(conn *client.ClusterCanalConnector, str string) { 46 | err := conn.Subscribe(str) 47 | if err != nil { 48 | log.Println(err) 49 | os.Exit(1) 50 | } 51 | } 52 | 53 | func createConnection() *client.ClusterCanalConnector { 54 | cn, err := client.NewCanalClusterNode("example", []string{"192.168.0.201:2181", "192.168.0.202:2181", "192.168.0.203:2181"}, time.Second*10) 55 | if err != nil { 56 | log.Println(err) 57 | os.Exit(1) 58 | } 59 | 60 | canalConnector, err := client.NewClusterCanalConnector(cn, "canal", "canal", "example", 60000, 60*60*1000) 61 | if err != nil { 62 | log.Println(err) 63 | os.Exit(1) 64 | } 65 | 66 | err = canalConnector.Connect() 67 | if err != nil { 68 | log.Println(err) 69 | os.Exit(1) 70 | } 71 | 72 | return canalConnector 73 | } 74 | 75 | func printEntry(entrys []pbe.Entry) { 76 | 77 | for _, entry := range entrys { 78 | if entry.GetEntryType() == pbe.EntryType_TRANSACTIONBEGIN || entry.GetEntryType() == pbe.EntryType_TRANSACTIONEND { 79 | continue 80 | } 81 | rowChange := new(pbe.RowChange) 82 | 83 | err := proto.Unmarshal(entry.GetStoreValue(), rowChange) 84 | checkError(err) 85 | if rowChange != nil { 86 | eventType := rowChange.GetEventType() 87 | header := entry.GetHeader() 88 | fmt.Println(fmt.Sprintf("================> binlog[%s : %d],name[%s,%s], eventType: %s", header.GetLogfileName(), header.GetLogfileOffset(), header.GetSchemaName(), header.GetTableName(), header.GetEventType())) 89 | 90 | for _, rowData := range rowChange.GetRowDatas() { 91 | if eventType == pbe.EventType_DELETE { 92 | printColumn(rowData.GetBeforeColumns()) 93 | } else if eventType == pbe.EventType_INSERT { 94 | printColumn(rowData.GetAfterColumns()) 95 | } else { 96 | fmt.Println("-------> before") 97 | printColumn(rowData.GetBeforeColumns()) 98 | fmt.Println("-------> after") 99 | printColumn(rowData.GetAfterColumns()) 100 | } 101 | } 102 | } 103 | } 104 | } 105 | 106 | func printColumn(columns []*pbe.Column) { 107 | for _, col := range columns { 108 | fmt.Println(fmt.Sprintf("%s : %s update= %t", col.GetName(), col.GetValue(), col.GetUpdated())) 109 | } 110 | } 111 | 112 | func checkError(err error) { 113 | if err != nil { 114 | fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 115 | os.Exit(1) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /samples/doc.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package main 18 | -------------------------------------------------------------------------------- /samples/main.go: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | "os" 23 | "time" 24 | 25 | "github.com/withlin/canal-go/client" 26 | pbe "github.com/withlin/canal-go/protocol/entry" 27 | "google.golang.org/protobuf/proto" 28 | ) 29 | 30 | func main() { 31 | 32 | // 192.168.199.17 替换成你的canal server的地址 33 | // example 替换成-e canal.destinations=example 你自己定义的名字 34 | connector := client.NewSimpleCanalConnector("127.0.0.1", 11111, "", "", "example", 60000, 60*60*1000) 35 | err := connector.Connect() 36 | if err != nil { 37 | log.Println(err) 38 | os.Exit(1) 39 | } 40 | 41 | // https://github.com/alibaba/canal/wiki/AdminGuide 42 | //mysql 数据解析关注的表,Perl正则表达式. 43 | // 44 | //多个正则之间以逗号(,)分隔,转义符需要双斜杠(\\) 45 | // 46 | //常见例子: 47 | // 48 | // 1. 所有表:.* or .*\\..* 49 | // 2. canal schema下所有表: canal\\..* 50 | // 3. canal下的以canal打头的表:canal\\.canal.* 51 | // 4. canal schema下的一张表:canal\\.test1 52 | // 5. 多个规则组合使用:canal\\..*,mysql.test1,mysql.test2 (逗号分隔) 53 | 54 | err = connector.Subscribe(".*\\..*") 55 | if err != nil { 56 | log.Println(err) 57 | os.Exit(1) 58 | } 59 | 60 | for { 61 | 62 | message, err := connector.Get(100, nil, nil) 63 | if err != nil { 64 | log.Println(err) 65 | os.Exit(1) 66 | } 67 | batchId := message.Id 68 | if batchId == -1 || len(message.Entries) <= 0 { 69 | time.Sleep(300 * time.Millisecond) 70 | fmt.Println("===没有数据了===") 71 | continue 72 | } 73 | 74 | printEntry(message.Entries) 75 | 76 | } 77 | } 78 | 79 | func printEntry(entrys []pbe.Entry) { 80 | 81 | for _, entry := range entrys { 82 | if entry.GetEntryType() == pbe.EntryType_TRANSACTIONBEGIN || entry.GetEntryType() == pbe.EntryType_TRANSACTIONEND { 83 | continue 84 | } 85 | rowChange := new(pbe.RowChange) 86 | 87 | err := proto.Unmarshal(entry.GetStoreValue(), rowChange) 88 | checkError(err) 89 | if rowChange != nil { 90 | eventType := rowChange.GetEventType() 91 | header := entry.GetHeader() 92 | fmt.Println(fmt.Sprintf("================> binlog[%s : %d],name[%s,%s], eventType: %s", header.GetLogfileName(), header.GetLogfileOffset(), header.GetSchemaName(), header.GetTableName(), header.GetEventType())) 93 | 94 | for _, rowData := range rowChange.GetRowDatas() { 95 | if eventType == pbe.EventType_DELETE { 96 | printColumn(rowData.GetBeforeColumns()) 97 | } else if eventType == pbe.EventType_INSERT { 98 | printColumn(rowData.GetAfterColumns()) 99 | } else { 100 | fmt.Println("-------> before") 101 | printColumn(rowData.GetBeforeColumns()) 102 | fmt.Println("-------> after") 103 | printColumn(rowData.GetAfterColumns()) 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | func printColumn(columns []*pbe.Column) { 111 | for _, col := range columns { 112 | fmt.Println(fmt.Sprintf("%s : %s update= %t", col.GetName(), col.GetValue(), col.GetUpdated())) 113 | } 114 | } 115 | 116 | func checkError(err error) { 117 | if err != nil { 118 | fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 119 | os.Exit(1) 120 | } 121 | } 122 | --------------------------------------------------------------------------------