nightingale/vendor/github.com/uber/tchannel-go/relay_messages.go

199 lines
5.5 KiB
Go
Raw Normal View History

2020-11-16 08:56:04 +08:00
// Copyright (c) 2015 Uber Technologies, Inc.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package tchannel
import (
"bytes"
"encoding/binary"
"fmt"
"time"
)
var (
_callerNameKeyBytes = []byte(CallerName)
_routingDelegateKeyBytes = []byte(RoutingDelegate)
_routingKeyKeyBytes = []byte(RoutingKey)
)
const (
// Common to many frame types.
_flagsIndex = 0
// For call req.
_ttlIndex = 1
_ttlLen = 4
_spanIndex = _ttlIndex + _ttlLen
_spanLength = 25
_serviceLenIndex = _spanIndex + _spanLength
_serviceNameIndex = _serviceLenIndex + 1
// For call res and call res continue.
_resCodeOK = 0x00
_resCodeIndex = 1
// For error.
_errCodeIndex = 0
)
type lazyError struct {
*Frame
}
func newLazyError(f *Frame) lazyError {
if msgType := f.Header.messageType; msgType != messageTypeError {
panic(fmt.Errorf("newLazyError called for wrong messageType: %v", msgType))
}
return lazyError{f}
}
func (e lazyError) Code() SystemErrCode {
return SystemErrCode(e.Payload[_errCodeIndex])
}
type lazyCallRes struct {
*Frame
}
func newLazyCallRes(f *Frame) lazyCallRes {
if msgType := f.Header.messageType; msgType != messageTypeCallRes {
panic(fmt.Errorf("newLazyCallRes called for wrong messageType: %v", msgType))
}
return lazyCallRes{f}
}
func (cr lazyCallRes) OK() bool {
return cr.Payload[_resCodeIndex] == _resCodeOK
}
// TODO: Use []byte instead of string for caller/method to avoid allocations.
type lazyCallReq struct {
*Frame
caller, method, delegate, key []byte
}
// TODO: Consider pooling lazyCallReq and using pointers to the struct.
func newLazyCallReq(f *Frame) lazyCallReq {
if msgType := f.Header.messageType; msgType != messageTypeCallReq {
panic(fmt.Errorf("newLazyCallReq called for wrong messageType: %v", msgType))
}
cr := lazyCallReq{Frame: f}
serviceLen := f.Payload[_serviceLenIndex]
// nh:1 (hk~1 hv~1){nh}
headerStart := _serviceLenIndex + 1 /* length byte */ + serviceLen
numHeaders := int(f.Payload[headerStart])
cur := int(headerStart) + 1
for i := 0; i < numHeaders; i++ {
keyLen := int(f.Payload[cur])
cur++
key := f.Payload[cur : cur+keyLen]
cur += keyLen
valLen := int(f.Payload[cur])
cur++
val := f.Payload[cur : cur+valLen]
cur += valLen
if bytes.Equal(key, _callerNameKeyBytes) {
cr.caller = val
} else if bytes.Equal(key, _routingDelegateKeyBytes) {
cr.delegate = val
} else if bytes.Equal(key, _routingKeyKeyBytes) {
cr.key = val
}
}
// csumtype:1 (csum:4){0,1} arg1~2 arg2~2 arg3~2
checkSumType := ChecksumType(f.Payload[cur])
cur += 1 /* checksum */ + checkSumType.ChecksumSize()
// arg1~2
arg1Len := int(binary.BigEndian.Uint16(f.Payload[cur : cur+2]))
cur += 2
cr.method = f.Payload[cur : cur+arg1Len]
return cr
}
// Caller returns the name of the originator of this callReq.
func (f lazyCallReq) Caller() []byte {
return f.caller
}
// Service returns the name of the destination service for this callReq.
func (f lazyCallReq) Service() []byte {
l := f.Payload[_serviceLenIndex]
return f.Payload[_serviceNameIndex : _serviceNameIndex+l]
}
// Method returns the name of the method being called.
func (f lazyCallReq) Method() []byte {
return f.method
}
// RoutingDelegate returns the routing delegate for this call req, if any.
func (f lazyCallReq) RoutingDelegate() []byte {
return f.delegate
}
// RoutingKey returns the routing delegate for this call req, if any.
func (f lazyCallReq) RoutingKey() []byte {
return f.key
}
// TTL returns the time to live for this callReq.
func (f lazyCallReq) TTL() time.Duration {
ttl := binary.BigEndian.Uint32(f.Payload[_ttlIndex : _ttlIndex+_ttlLen])
return time.Duration(ttl) * time.Millisecond
}
// SetTTL overwrites the frame's TTL.
func (f lazyCallReq) SetTTL(d time.Duration) {
ttl := uint32(d / time.Millisecond)
binary.BigEndian.PutUint32(f.Payload[_ttlIndex:_ttlIndex+_ttlLen], ttl)
}
// Span returns the Span
func (f lazyCallReq) Span() Span {
return callReqSpan(f.Frame)
}
// HasMoreFragments returns whether the callReq has more fragments.
func (f lazyCallReq) HasMoreFragments() bool {
return f.Payload[_flagsIndex]&hasMoreFragmentsFlag != 0
}
// finishesCall checks whether this frame is the last one we should expect for
// this RPC req-res.
func finishesCall(f *Frame) bool {
switch f.messageType() {
case messageTypeError:
return true
case messageTypeCallRes, messageTypeCallResContinue:
flags := f.Payload[_flagsIndex]
return flags&hasMoreFragmentsFlag == 0
default:
return false
}
}