github.com/nacos-group/nacos-sdk-go@v1.1.4/clients/naming_client/push_receiver.go (about) 1 /* 2 * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package naming_client 18 19 import ( 20 "bytes" 21 "compress/gzip" 22 "encoding/json" 23 "io/ioutil" 24 "math/rand" 25 "net" 26 "strconv" 27 "time" 28 29 "github.com/nacos-group/nacos-sdk-go/common/logger" 30 "github.com/nacos-group/nacos-sdk-go/util" 31 ) 32 33 type PushReceiver struct { 34 port int 35 host string 36 hostReactor *HostReactor 37 } 38 39 type PushData struct { 40 PushType string `json:"type"` 41 Data string `json:"data"` 42 LastRefTime int64 `json:"lastRefTime"` 43 } 44 45 var ( 46 GZIP_MAGIC = []byte("\x1F\x8B") 47 ) 48 49 func NewPushReceiver(hostReactor *HostReactor) *PushReceiver { 50 pr := PushReceiver{ 51 hostReactor: hostReactor, 52 } 53 pr.startServer() 54 return &pr 55 } 56 57 func (us *PushReceiver) tryListen() (*net.UDPConn, bool) { 58 addr, err := net.ResolveUDPAddr("udp", us.host+":"+strconv.Itoa(us.port)) 59 if err != nil { 60 logger.Errorf("can't resolve address,err: %+v", err) 61 return nil, false 62 } 63 64 conn, err := net.ListenUDP("udp", addr) 65 if err != nil { 66 logger.Errorf("error listening %s:%d,err:%+v", us.host, us.port, err) 67 return nil, false 68 } 69 70 return conn, true 71 } 72 73 func (us *PushReceiver) getConn() *net.UDPConn { 74 r := rand.New(rand.NewSource(time.Now().UnixNano())) 75 76 for i := 0; i < 3; i++ { 77 port := r.Intn(1000) + 54951 78 us.port = port 79 conn, ok := us.tryListen() 80 if ok { 81 logger.Infof("udp server start, port: " + strconv.Itoa(port)) 82 return conn 83 } 84 if !ok && i == 2 { 85 logger.Errorf("failed to start udp server after trying 3 times.") 86 } 87 } 88 return nil 89 } 90 91 func (us *PushReceiver) startServer() { 92 conn := us.getConn() 93 if conn == nil { 94 return 95 } 96 go func() { 97 defer conn.Close() 98 for { 99 us.handleClient(conn) 100 } 101 }() 102 } 103 104 func (us *PushReceiver) handleClient(conn *net.UDPConn) { 105 106 if conn == nil { 107 time.Sleep(time.Second * 5) 108 conn = us.getConn() 109 if conn == nil { 110 return 111 } 112 } 113 114 data := make([]byte, 4024) 115 n, remoteAddr, err := conn.ReadFromUDP(data) 116 if err != nil { 117 logger.Errorf("failed to read UDP msg because of %+v", err) 118 return 119 } 120 121 s := TryDecompressData(data[:n]) 122 logger.Info("receive push: "+s+" from: ", remoteAddr) 123 124 var pushData PushData 125 err1 := json.Unmarshal([]byte(s), &pushData) 126 if err1 != nil { 127 logger.Infof("failed to process push data.err:%+v", err1) 128 return 129 } 130 ack := make(map[string]string) 131 132 if pushData.PushType == "dom" || pushData.PushType == "service" { 133 us.hostReactor.ProcessServiceJson(pushData.Data) 134 135 ack["type"] = "push-ack" 136 ack["lastRefTime"] = strconv.FormatInt(pushData.LastRefTime, 10) 137 ack["data"] = "" 138 139 } else if pushData.PushType == "dump" { 140 ack["type"] = "dump-ack" 141 ack["lastRefTime"] = strconv.FormatInt(pushData.LastRefTime, 10) 142 ack["data"] = util.ToJsonString(us.hostReactor.serviceInfoMap) 143 } else { 144 ack["type"] = "unknow-ack" 145 ack["lastRefTime"] = strconv.FormatInt(pushData.LastRefTime, 10) 146 ack["data"] = "" 147 } 148 149 bs, _ := json.Marshal(ack) 150 c, err := conn.WriteToUDP(bs, remoteAddr) 151 if err != nil { 152 logger.Errorf("WriteToUDP failed,return:%d,err:%+v", c, err) 153 } 154 } 155 156 func TryDecompressData(data []byte) string { 157 158 if !IsGzipFile(data) { 159 return string(data) 160 } 161 reader, err := gzip.NewReader(bytes.NewReader(data)) 162 163 if err != nil { 164 logger.Errorf("failed to decompress gzip data,err:%+v", err) 165 return "" 166 } 167 168 defer reader.Close() 169 bs, err := ioutil.ReadAll(reader) 170 171 if err != nil { 172 logger.Errorf("failed to decompress gzip data,err:%+v", err) 173 return "" 174 } 175 176 return string(bs) 177 } 178 179 func IsGzipFile(data []byte) bool { 180 if len(data) < 2 { 181 return false 182 } 183 184 return bytes.HasPrefix(data, GZIP_MAGIC) 185 }