github.com/cloudwego/kitex@v0.9.0/pkg/remote/message.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 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 remote 18 19 import ( 20 "fmt" 21 "sync" 22 23 "github.com/cloudwego/kitex/pkg/rpcinfo" 24 "github.com/cloudwego/kitex/pkg/serviceinfo" 25 "github.com/cloudwego/kitex/pkg/utils" 26 "github.com/cloudwego/kitex/transport" 27 ) 28 29 var ( 30 messagePool sync.Pool 31 transInfoPool sync.Pool 32 emptyServiceInfo serviceinfo.ServiceInfo 33 ) 34 35 func init() { 36 messagePool.New = newMessage 37 transInfoPool.New = newTransInfo 38 } 39 40 // MessageType indicates the type of message. 41 type MessageType int32 42 43 // MessageTypes. 44 const ( 45 // 0-4 corresponding to thrift.TMessageType 46 InvalidMessageType MessageType = 0 47 Call MessageType = 1 48 Reply MessageType = 2 49 Exception MessageType = 3 50 // Oneway means there's no need to wait for the response. 51 // When the actual message is transmitted, Oneway writes a Call to avoid compatibility issues 52 // and to maintain consistency with the original logic. 53 Oneway MessageType = 4 54 55 Stream MessageType = 5 56 57 Heartbeat MessageType = 6 58 ) 59 60 const ( 61 // ReadFailed . 62 ReadFailed string = "RFailed" 63 64 // MeshHeader use in message.Tag to check MeshHeader 65 MeshHeader string = "mHeader" 66 ) 67 68 var emptyProtocolInfo ProtocolInfo 69 70 // ProtocolInfo is used to indicate the transport protocol and payload codec information. 71 type ProtocolInfo struct { 72 TransProto transport.Protocol 73 CodecType serviceinfo.PayloadCodec 74 } 75 76 // NewProtocolInfo creates a new ProtocolInfo using the given tp and ct. 77 func NewProtocolInfo(tp transport.Protocol, ct serviceinfo.PayloadCodec) ProtocolInfo { 78 return ProtocolInfo{ 79 TransProto: tp, 80 CodecType: ct, 81 } 82 } 83 84 // Message is the core abstraction for Kitex message. 85 type Message interface { 86 RPCInfo() rpcinfo.RPCInfo 87 ServiceInfo() *serviceinfo.ServiceInfo 88 SpecifyServiceInfo(svcName, methodName string) (*serviceinfo.ServiceInfo, error) 89 Data() interface{} 90 NewData(method string) (ok bool) 91 MessageType() MessageType 92 SetMessageType(MessageType) 93 RPCRole() RPCRole 94 PayloadLen() int 95 SetPayloadLen(size int) 96 TransInfo() TransInfo 97 Tags() map[string]interface{} 98 ProtocolInfo() ProtocolInfo 99 SetProtocolInfo(ProtocolInfo) 100 PayloadCodec() PayloadCodec 101 SetPayloadCodec(pc PayloadCodec) 102 Recycle() 103 } 104 105 // NewMessage creates a new Message using the given info. 106 func NewMessage(data interface{}, svcInfo *serviceinfo.ServiceInfo, ri rpcinfo.RPCInfo, msgType MessageType, rpcRole RPCRole) Message { 107 msg := messagePool.Get().(*message) 108 msg.data = data 109 msg.rpcInfo = ri 110 msg.targetSvcInfo = svcInfo 111 msg.msgType = msgType 112 msg.rpcRole = rpcRole 113 msg.transInfo = transInfoPool.Get().(*transInfo) 114 return msg 115 } 116 117 // NewMessageWithNewer creates a new Message and set data later. 118 func NewMessageWithNewer(targetSvcInfo *serviceinfo.ServiceInfo, svcSearchMap map[string]*serviceinfo.ServiceInfo, ri rpcinfo.RPCInfo, msgType MessageType, rpcRole RPCRole, refuseTrafficWithoutServiceName bool) Message { 119 msg := messagePool.Get().(*message) 120 msg.rpcInfo = ri 121 msg.targetSvcInfo = targetSvcInfo 122 msg.svcSearchMap = svcSearchMap 123 msg.msgType = msgType 124 msg.rpcRole = rpcRole 125 msg.transInfo = transInfoPool.Get().(*transInfo) 126 msg.refuseTrafficWithoutServiceName = refuseTrafficWithoutServiceName 127 return msg 128 } 129 130 // RecycleMessage is used to recycle message. 131 func RecycleMessage(msg Message) { 132 if msg != nil { 133 msg.Recycle() 134 } 135 } 136 137 func newMessage() interface{} { 138 return &message{tags: make(map[string]interface{})} 139 } 140 141 type message struct { 142 msgType MessageType 143 data interface{} 144 rpcInfo rpcinfo.RPCInfo 145 targetSvcInfo *serviceinfo.ServiceInfo 146 svcSearchMap map[string]*serviceinfo.ServiceInfo 147 rpcRole RPCRole 148 compressType CompressType 149 payloadSize int 150 transInfo TransInfo 151 tags map[string]interface{} 152 protocol ProtocolInfo 153 payloadCodec PayloadCodec 154 refuseTrafficWithoutServiceName bool 155 } 156 157 func (m *message) zero() { 158 m.msgType = InvalidMessageType 159 m.data = nil 160 m.rpcInfo = nil 161 m.targetSvcInfo = &emptyServiceInfo 162 m.rpcRole = -1 163 m.compressType = NoCompress 164 m.payloadSize = 0 165 if m.transInfo != nil { 166 m.transInfo.Recycle() 167 m.transInfo = nil 168 } 169 for k := range m.tags { 170 delete(m.tags, k) 171 } 172 m.protocol = emptyProtocolInfo 173 } 174 175 // RPCInfo implements the Message interface. 176 func (m *message) RPCInfo() rpcinfo.RPCInfo { 177 return m.rpcInfo 178 } 179 180 // ServiceInfo implements the Message interface. 181 func (m *message) ServiceInfo() *serviceinfo.ServiceInfo { 182 return m.targetSvcInfo 183 } 184 185 func (m *message) SpecifyServiceInfo(svcName, methodName string) (*serviceinfo.ServiceInfo, error) { 186 // for non-multi-service including generic server scenario 187 if m.targetSvcInfo != nil { 188 if mt := m.targetSvcInfo.MethodInfo(methodName); mt == nil { 189 return nil, NewTransErrorWithMsg(UnknownMethod, fmt.Sprintf("unknown method %s", methodName)) 190 } 191 return m.targetSvcInfo, nil 192 } 193 if svcName == "" && m.refuseTrafficWithoutServiceName { 194 return nil, NewTransErrorWithMsg(NoServiceName, "no service name while the server has WithRefuseTrafficWithoutServiceName option enabled") 195 } 196 var key string 197 if svcName == "" { 198 key = methodName 199 } else { 200 key = BuildMultiServiceKey(svcName, methodName) 201 } 202 svcInfo := m.svcSearchMap[key] 203 if svcInfo == nil { 204 return nil, NewTransErrorWithMsg(UnknownMethod, fmt.Sprintf("unknown method %s", methodName)) 205 } 206 m.targetSvcInfo = svcInfo 207 return svcInfo, nil 208 } 209 210 // Data implements the Message interface. 211 func (m *message) Data() interface{} { 212 return m.data 213 } 214 215 // NewData implements the Message interface. 216 func (m *message) NewData(method string) (ok bool) { 217 if m.data != nil { 218 return false 219 } 220 if mt := m.targetSvcInfo.MethodInfo(method); mt != nil { 221 m.data = mt.NewArgs() 222 } 223 if m.data == nil { 224 return false 225 } 226 return true 227 } 228 229 // MessageType implements the Message interface. 230 func (m *message) MessageType() MessageType { 231 return m.msgType 232 } 233 234 // SetMessageType implements the Message interface. 235 func (m *message) SetMessageType(mt MessageType) { 236 m.msgType = mt 237 } 238 239 // RPCRole implements the Message interface. 240 func (m *message) RPCRole() RPCRole { 241 return m.rpcRole 242 } 243 244 // TransInfo implements the Message interface. 245 func (m *message) TransInfo() TransInfo { 246 return m.transInfo 247 } 248 249 // Tags implements the Message interface. 250 func (m *message) Tags() map[string]interface{} { 251 return m.tags 252 } 253 254 // PayloadLen implements the Message interface. 255 func (m *message) PayloadLen() int { 256 return m.payloadSize 257 } 258 259 // SetPayloadLen implements the Message interface. 260 func (m *message) SetPayloadLen(size int) { 261 m.payloadSize = size 262 } 263 264 // ProtocolInfo implements the Message interface. 265 func (m *message) ProtocolInfo() ProtocolInfo { 266 return m.protocol 267 } 268 269 // SetProtocolInfo implements the Message interface. 270 func (m *message) SetProtocolInfo(pt ProtocolInfo) { 271 m.protocol = pt 272 } 273 274 // PayloadCodec implements the Message interface. 275 func (m *message) PayloadCodec() PayloadCodec { 276 return m.payloadCodec 277 } 278 279 // SetPayloadCodec implements the Message interface. 280 func (m *message) SetPayloadCodec(pc PayloadCodec) { 281 m.payloadCodec = pc 282 } 283 284 // Recycle is used to recycle the message. 285 func (m *message) Recycle() { 286 m.zero() 287 messagePool.Put(m) 288 } 289 290 // TransInfo contains transport information. 291 type TransInfo interface { 292 TransStrInfo() map[string]string 293 TransIntInfo() map[uint16]string 294 PutTransIntInfo(map[uint16]string) 295 PutTransStrInfo(kvInfo map[string]string) 296 Recycle() 297 } 298 299 func newTransInfo() interface{} { 300 return &transInfo{ 301 intInfo: make(map[uint16]string), 302 strInfo: make(map[string]string), 303 } 304 } 305 306 type transInfo struct { 307 strInfo map[string]string 308 intInfo map[uint16]string 309 } 310 311 func (ti *transInfo) zero() { 312 for k := range ti.intInfo { 313 delete(ti.intInfo, k) 314 } 315 for k := range ti.strInfo { 316 delete(ti.strInfo, k) 317 } 318 } 319 320 // TransIntInfo implements the TransInfo interface. 321 func (ti *transInfo) TransIntInfo() map[uint16]string { 322 return ti.intInfo 323 } 324 325 // PutTransIntInfo implements the TransInfo interface. 326 func (ti *transInfo) PutTransIntInfo(kvInfo map[uint16]string) { 327 if kvInfo == nil { 328 return 329 } 330 if len(ti.intInfo) == 0 { 331 ti.intInfo = kvInfo 332 } else { 333 for k, v := range kvInfo { 334 ti.intInfo[k] = v 335 } 336 } 337 } 338 339 // TransStrInfo implements the TransInfo interface. 340 func (ti *transInfo) TransStrInfo() map[string]string { 341 return ti.strInfo 342 } 343 344 // PutTransStrInfo implements the TransInfo interface. 345 func (ti *transInfo) PutTransStrInfo(kvInfo map[string]string) { 346 if kvInfo == nil { 347 return 348 } 349 if len(ti.strInfo) == 0 { 350 ti.strInfo = kvInfo 351 } else { 352 for k, v := range kvInfo { 353 ti.strInfo[k] = v 354 } 355 } 356 } 357 358 // Recycle is used to recycle the transInfo. 359 func (ti *transInfo) Recycle() { 360 ti.zero() 361 transInfoPool.Put(ti) 362 } 363 364 // FillSendMsgFromRecvMsg is used to fill the transport information to the message to be sent. 365 func FillSendMsgFromRecvMsg(recvMsg, sendMsg Message) { 366 sendMsg.SetProtocolInfo(recvMsg.ProtocolInfo()) 367 sendMsg.SetPayloadCodec(recvMsg.PayloadCodec()) 368 } 369 370 // BuildMultiServiceKey is used to create a key to search svcInfo from svcSearchMap. 371 func BuildMultiServiceKey(serviceName, methodName string) string { 372 var builder utils.StringBuilder 373 builder.Grow(len(serviceName) + len(methodName) + 1) 374 builder.WriteString(serviceName) 375 builder.WriteString(".") 376 builder.WriteString(methodName) 377 return builder.String() 378 }