github.com/polarismesh/polaris@v1.17.8/apiserver/eurekaserver/model.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package eurekaserver 19 20 import ( 21 "encoding/json" 22 "encoding/xml" 23 "fmt" 24 "reflect" 25 "strconv" 26 "strings" 27 28 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 29 ) 30 31 // PortWrapper 端口包装类 32 type PortWrapper struct { 33 Port interface{} `json:"$" xml:",chardata"` 34 35 RealPort int `json:"-" xml:"-"` 36 37 Enabled interface{} `json:"@enabled" xml:"enabled,attr"` 38 39 RealEnable bool `json:"-" xml:"-"` 40 } 41 42 // UnmarshalXML PortWrapper xml 反序列化 43 func (p *PortWrapper) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 44 var err error 45 port := struct { 46 Port string `xml:",chardata"` 47 Enabled string `xml:"enabled,attr"` 48 }{} 49 if err = d.DecodeElement(&port, &start); err != nil { 50 return err 51 } 52 53 p.RealPort, err = strconv.Atoi(port.Port) 54 if err != nil { 55 return err 56 } 57 p.Port = port.Port 58 p.RealEnable, err = strconv.ParseBool(port.Enabled) 59 if err != nil { 60 return err 61 } 62 p.Enabled = port.Enabled 63 return nil 64 } 65 66 func convertIntValue(value interface{}) (int, error) { 67 if jsonNumber, ok := value.(json.Number); ok { 68 realPort, err := jsonNumber.Int64() 69 if err != nil { 70 return 0, err 71 } 72 return int(realPort), nil 73 } 74 if floatValue, ok := value.(float64); ok { 75 return int(floatValue), nil 76 } 77 if strValue, ok := value.(string); ok { 78 return strconv.Atoi(strValue) 79 } 80 return 0, fmt.Errorf("unknow type of port value, type is %v", reflect.TypeOf(value)) 81 } 82 83 func (p *PortWrapper) convertPortValue() error { 84 var err error 85 p.RealPort, err = convertIntValue(p.Port) 86 return err 87 } 88 89 func (p *PortWrapper) convertEnableValue() error { 90 if jsonEnableStr, ok := p.Enabled.(string); ok { 91 enableValue, err := strconv.ParseBool(jsonEnableStr) 92 if err != nil { 93 return err 94 } 95 p.RealEnable = enableValue 96 return nil 97 } 98 if jsonEnableValue, ok := p.Enabled.(bool); ok { 99 p.RealEnable = jsonEnableValue 100 return nil 101 } 102 return fmt.Errorf("unknow type of enable value, type is %v", reflect.TypeOf(p.Enabled)) 103 } 104 105 // DataCenterInfo 数据中心信息 106 type DataCenterInfo struct { 107 Clazz string `json:"@class" xml:"class,attr"` 108 109 Name string `json:"name" xml:"name"` 110 } 111 112 // LeaseInfo 租约信息 113 type LeaseInfo struct { 114 115 // Client settings 116 RenewalIntervalInSecs int `json:"renewalIntervalInSecs" xml:"renewalIntervalInSecs"` 117 118 DurationInSecs int `json:"durationInSecs" xml:"durationInSecs"` 119 120 // Server populated 121 RegistrationTimestamp int `json:"registrationTimestamp" xml:"registrationTimestamp"` 122 123 LastRenewalTimestamp int `json:"lastRenewalTimestamp" xml:"lastRenewalTimestamp"` 124 125 EvictionTimestamp int `json:"evictionTimestamp" xml:"evictionTimestamp"` 126 127 ServiceUpTimestamp int `json:"serviceUpTimestamp" xml:"serviceUpTimestamp"` 128 } 129 130 // RegistrationRequest 实例注册请求 131 type RegistrationRequest struct { 132 Instance *InstanceInfo `json:"instance"` 133 } 134 135 // ApplicationsResponse 服务拉取应答 136 type ApplicationsResponse struct { 137 Applications *Applications `json:"applications"` 138 } 139 140 // ApplicationResponse 单个服务拉取响应 141 type ApplicationResponse struct { 142 Application *Application `json:"application"` 143 } 144 145 // InstanceResponse 单个服务实例拉取响应 146 type InstanceResponse struct { 147 InstanceInfo *InstanceInfo `json:"instance" xml:"instance"` 148 } 149 150 // Metadata 元数据信息,xml 格式无法直接反序列化成 map[string]string 类型。这里通过 []byte 类型的 Raw 接收,并反序列化到 Meta 中。 151 // 反序列化后,polaris 在业务中只使用 Meta 字段。 152 type Metadata struct { 153 Raw []byte `xml:",innerxml" json:"-"` 154 155 Attributes StringMap 156 157 Meta StringMap 158 } 159 160 // UnmarshalJSON Metadata json 反序列化方法 161 func (i *Metadata) UnmarshalJSON(b []byte) error { 162 i.Raw = b 163 164 err := json.Unmarshal(b, &i.Meta) 165 if err != nil { 166 return err 167 } 168 169 return nil 170 } 171 172 // UnmarshalXML Metadata xml 反序列化方法 173 func (i *Metadata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 174 i.Meta = make(map[string]interface{}) 175 values, err := xmlToMapParser(start.Name.Local, start.Attr, d, true) 176 if err != nil { 177 return err 178 } 179 var subValues map[string]interface{} 180 if len(values) > 0 { 181 subValuesRaw := values[start.Name.Local] 182 subValues, _ = subValuesRaw.(map[string]interface{}) 183 } 184 if len(subValues) > 0 { 185 for k, v := range subValues { 186 i.Meta[k] = v 187 } 188 } 189 return nil 190 } 191 192 // MarshalJSON Metadata json 序列化方法 193 func (i *Metadata) MarshalJSON() ([]byte, error) { 194 if i.Meta != nil { 195 return json.Marshal(i.Meta) 196 } 197 198 if i.Raw == nil { 199 i.Raw = []byte("{}") 200 } 201 202 return i.Raw, nil 203 } 204 205 func startLocalName(local string) xml.StartElement { 206 return xml.StartElement{Name: xml.Name{Space: "", Local: local}} 207 } 208 209 func startLocalAttribute(attrName string, attrValue string) xml.Attr { 210 return xml.Attr{Name: xml.Name{Space: "", Local: attrName}, Value: attrValue} 211 } 212 213 // MarshalXML Metadata xml 序列化方法 214 func (i *Metadata) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 215 tokens := []xml.Token{start} 216 if i.Meta != nil { 217 for key, value := range i.Meta { 218 strValue := ObjectToString(value) 219 if strings.HasPrefix(key, attributeNotion) { 220 start.Attr = append(start.Attr, startLocalAttribute(key[1:], strValue)) 221 continue 222 } 223 // 兼容,后续去掉 224 if strings.HasPrefix(key, attributeNotionCross) { 225 start.Attr = append(start.Attr, startLocalAttribute(key[1:], strValue)) 226 continue 227 } 228 t := startLocalName(key) 229 tokens = append(tokens, t, xml.CharData(strValue), xml.EndElement{Name: t.Name}) 230 } 231 } 232 tokens = append(tokens, xml.EndElement{Name: start.Name}) 233 if len(start.Attr) > 0 { 234 tokens[0] = start 235 } 236 for _, t := range tokens { 237 err := e.EncodeToken(t) 238 if err != nil { 239 return err 240 } 241 } 242 243 // flush to ensure tokens are written 244 return e.Flush() 245 } 246 247 // InstanceInfo 实例信息 248 type InstanceInfo struct { 249 XMLName struct{} `json:"-" xml:"instance"` 250 251 InstanceId string `json:"instanceId" xml:"instanceId"` 252 253 AppName string `json:"app" xml:"app"` 254 255 AppGroupName string `json:"appGroupName" xml:"appGroupName,omitempty"` 256 257 IpAddr string `json:"ipAddr" xml:"ipAddr"` 258 259 Sid string `json:"sid" xml:"sid,omitempty"` 260 261 Port *PortWrapper `json:"port" xml:"port,omitempty"` 262 263 SecurePort *PortWrapper `json:"securePort" xml:"securePort,omitempty"` 264 265 HomePageUrl string `json:"homePageUrl" xml:"homePageUrl,omitempty"` 266 267 StatusPageUrl string `json:"statusPageUrl" xml:"statusPageUrl,omitempty"` 268 269 HealthCheckUrl string `json:"healthCheckUrl" xml:"healthCheckUrl,omitempty"` 270 271 SecureHealthCheckUrl string `json:"secureHealthCheckUrl" xml:"secureHealthCheckUrl,omitempty"` 272 273 VipAddress string `json:"vipAddress" xml:"vipAddress,omitempty"` 274 275 SecureVipAddress string `json:"secureVipAddress" xml:"secureVipAddress,omitempty"` 276 277 CountryId interface{} `json:"countryId" xml:"countryId,omitempty"` 278 279 DataCenterInfo *DataCenterInfo `json:"dataCenterInfo" xml:"dataCenterInfo"` 280 281 HostName string `json:"hostName" xml:"hostName,omitempty"` 282 283 Status string `json:"status" xml:"status"` 284 285 OverriddenStatus string `json:"overriddenStatus" xml:"overriddenStatus,omitempty"` 286 287 LeaseInfo *LeaseInfo `json:"leaseInfo" xml:"leaseInfo,omitempty"` 288 289 IsCoordinatingDiscoveryServer interface{} `json:"isCoordinatingDiscoveryServer" xml:"isCoordinatingDiscoveryServer,omitempty"` 290 291 Metadata *Metadata `json:"metadata" xml:"metadata"` 292 293 LastUpdatedTimestamp interface{} `json:"lastUpdatedTimestamp" xml:"lastUpdatedTimestamp,omitempty"` 294 295 LastDirtyTimestamp interface{} `json:"lastDirtyTimestamp" xml:"lastDirtyTimestamp,omitempty"` 296 297 ActionType string `json:"actionType" xml:"actionType"` 298 299 // 实际的北极星实例模型 300 RealInstance *apiservice.Instance `json:"-" xml:"-"` 301 } 302 303 // Clone 对实例进行拷贝 304 func (i *InstanceInfo) Clone(actionType string) *InstanceInfo { 305 return &InstanceInfo{ 306 InstanceId: i.InstanceId, 307 AppName: i.AppName, 308 AppGroupName: i.AppGroupName, 309 IpAddr: i.IpAddr, 310 Sid: i.Sid, 311 Port: i.Port, 312 SecurePort: i.SecurePort, 313 HomePageUrl: i.HomePageUrl, 314 StatusPageUrl: i.StatusPageUrl, 315 HealthCheckUrl: i.HealthCheckUrl, 316 SecureHealthCheckUrl: i.SecureHealthCheckUrl, 317 VipAddress: i.VipAddress, 318 SecureVipAddress: i.SecureVipAddress, 319 CountryId: i.CountryId, 320 DataCenterInfo: i.DataCenterInfo, 321 HostName: i.HostName, 322 Status: i.Status, 323 OverriddenStatus: i.OverriddenStatus, 324 LeaseInfo: i.LeaseInfo, 325 IsCoordinatingDiscoveryServer: i.IsCoordinatingDiscoveryServer, 326 Metadata: i.Metadata, 327 LastUpdatedTimestamp: i.LastUpdatedTimestamp, 328 LastDirtyTimestamp: i.LastDirtyTimestamp, 329 ActionType: actionType, 330 } 331 } 332 333 // Equals 判断实例是否发生变更 334 func (i *InstanceInfo) Equals(another *InstanceInfo) bool { 335 return i.RealInstance.GetRevision().GetValue() == another.RealInstance.GetRevision().GetValue() 336 } 337 338 // Application 服务数据 339 type Application struct { 340 XMLName struct{} `json:"-" xml:"application"` 341 342 Name string `json:"name" xml:"name"` 343 344 Instance []*InstanceInfo `json:"instance" xml:"instance"` 345 346 InstanceMap map[string]*InstanceInfo `json:"-" xml:"-"` 347 348 Revision string `json:"-" xml:"-"` 349 350 StatusCounts map[string]int `json:"-" xml:"-"` 351 } 352 353 // GetInstance 获取eureka实例 354 func (a *Application) GetInstance(instId string) *InstanceInfo { 355 if len(a.InstanceMap) > 0 { 356 return a.InstanceMap[instId] 357 } 358 return nil 359 } 360 361 // Applications 服务列表 362 type Applications struct { 363 XMLName struct{} `json:"-" xml:"applications"` 364 365 VersionsDelta string `json:"versions__delta" xml:"versions__delta"` 366 367 AppsHashCode string `json:"apps__hashcode" xml:"apps__hashcode"` 368 369 Application []*Application `json:"application" xml:"application"` 370 371 ApplicationMap map[string]*Application `json:"-" xml:"-"` 372 } 373 374 // GetApplication 获取eureka应用 375 func (a *Applications) GetApplication(appId string) *Application { 376 if len(a.ApplicationMap) > 0 { 377 return a.ApplicationMap[appId] 378 } 379 return nil 380 } 381 382 // GetInstance get instance by instanceId 383 func (a *Applications) GetInstance(instId string) *InstanceInfo { 384 if len(a.Application) == 0 { 385 return nil 386 } 387 for _, app := range a.Application { 388 inst, ok := app.InstanceMap[instId] 389 if ok { 390 return inst 391 } 392 } 393 return nil 394 } 395 396 // StringMap is a map[string]string. 397 type StringMap map[string]interface{} 398 399 // ReplicationInstance request for instance replicate 400 type ReplicationInstance struct { 401 AppName string `json:"appName"` 402 Id string `json:"id"` 403 LastDirtyTimestamp int64 `json:"lastDirtyTimestamp"` 404 OverriddenStatus string `json:"overriddenStatus"` 405 Status string `json:"status"` 406 InstanceInfo *InstanceInfo `json:"instanceInfo"` 407 Action string `json:"action"` 408 } 409 410 // ReplicationList instances list to replicate 411 type ReplicationList struct { 412 ReplicationList []*ReplicationInstance `json:"replicationList"` 413 } 414 415 // ReplicationInstanceResponse response for instance replicate process 416 type ReplicationInstanceResponse struct { 417 StatusCode int `json:"statusCode"` 418 ResponseEntity *InstanceInfo `json:"responseEntity"` 419 } 420 421 // ReplicationListResponse list for replicate instance response 422 type ReplicationListResponse struct { 423 ResponseList []*ReplicationInstanceResponse `json:"responseList"` 424 }