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  }