go.temporal.io/server@v1.23.0/common/headers/caller_info.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package headers
    26  
    27  import (
    28  	"context"
    29  
    30  	"google.golang.org/grpc/metadata"
    31  )
    32  
    33  const (
    34  	CallerTypeOperator    = "operator"
    35  	CallerTypeAPI         = "api"
    36  	CallerTypeBackground  = "background"
    37  	CallerTypePreemptable = "preemptable"
    38  
    39  	CallerNameSystem = "system"
    40  )
    41  
    42  var (
    43  	SystemBackgroundCallerInfo = CallerInfo{
    44  		CallerName: CallerNameSystem,
    45  		CallerType: CallerTypeBackground,
    46  	}
    47  	SystemPreemptableCallerInfo = CallerInfo{
    48  		CallerName: CallerNameSystem,
    49  		CallerType: CallerTypePreemptable,
    50  	}
    51  )
    52  
    53  type (
    54  	CallerInfo struct {
    55  		// CallerName is the name of the caller.
    56  		// It can either user namespace name or
    57  		// the predefined CallerNameSystem.
    58  		CallerName string
    59  
    60  		// CallerType indicates if the call originates from
    61  		// user API calls or from system background operations.
    62  		CallerType string
    63  
    64  		// CallOrigin is the first API method name in the call chain.
    65  		// Currently, it is only specified when CallerType is CallerTypeAPI
    66  		CallOrigin string
    67  	}
    68  )
    69  
    70  // NewCallerInfo creates a new CallerInfo
    71  func NewCallerInfo(
    72  	callerName string,
    73  	callerType string,
    74  	callOrigin string,
    75  ) CallerInfo {
    76  	return CallerInfo{
    77  		CallerName: callerName,
    78  		CallerType: callerType,
    79  		CallOrigin: callOrigin,
    80  	}
    81  }
    82  
    83  // NewBackgroundCallerInfo creates a new CallerInfo with Background callerType
    84  // and empty callOrigin.
    85  // This is equivalent to NewCallerInfo(callerName, CallerTypeBackground, "")
    86  func NewBackgroundCallerInfo(
    87  	callerName string,
    88  ) CallerInfo {
    89  	return CallerInfo{
    90  		CallerName: callerName,
    91  		CallerType: CallerTypeBackground,
    92  	}
    93  }
    94  
    95  // NewPreemptableCallerInfo creates a new CallerInfo with Preemptable callerType
    96  // and empty callOrigin.
    97  // This is equivalent to NewCallerInfo(callerName, CallerTypePreemptable, "")
    98  func NewPreemptableCallerInfo(
    99  	callerName string,
   100  ) CallerInfo {
   101  	return CallerInfo{
   102  		CallerName: callerName,
   103  		CallerType: CallerTypePreemptable,
   104  	}
   105  }
   106  
   107  // SetCallerInfo sets callerName, callerType and CallOrigin in the context.
   108  // Existing values will be overwritten if new value is not empty.
   109  // TODO: consider only set the caller info to golang context instead of grpc metadata
   110  // and propagate to grpc outgoing context upon making an rpc call
   111  func SetCallerInfo(
   112  	ctx context.Context,
   113  	info CallerInfo,
   114  ) context.Context {
   115  	return setIncomingMD(ctx, map[string]string{
   116  		callerNameHeaderName: info.CallerName,
   117  		CallerTypeHeaderName: info.CallerType,
   118  		callOriginHeaderName: info.CallOrigin,
   119  	})
   120  }
   121  
   122  // SetCallerName set caller name in the context.
   123  // Existing caller name will be overwritten if exists and new caller name is not empty.
   124  func SetCallerName(
   125  	ctx context.Context,
   126  	callerName string,
   127  ) context.Context {
   128  	return setIncomingMD(ctx, map[string]string{callerNameHeaderName: callerName})
   129  }
   130  
   131  // SetCallerType set caller type in the context.
   132  // Existing caller type will be overwritten if exists and new caller type is not empty.
   133  func SetCallerType(
   134  	ctx context.Context,
   135  	callerType string,
   136  ) context.Context {
   137  	return setIncomingMD(ctx, map[string]string{CallerTypeHeaderName: callerType})
   138  }
   139  
   140  // SetOrigin set call origin in the context.
   141  // Existing call origin will be overwritten if exists and new call origin is not empty.
   142  func SetOrigin(
   143  	ctx context.Context,
   144  	callOrigin string,
   145  ) context.Context {
   146  	return setIncomingMD(ctx, map[string]string{callOriginHeaderName: callOrigin})
   147  }
   148  
   149  func setIncomingMD(
   150  	ctx context.Context,
   151  	kv map[string]string,
   152  ) context.Context {
   153  	mdIncoming, ok := metadata.FromIncomingContext(ctx)
   154  	if !ok {
   155  		mdIncoming = metadata.MD{}
   156  	}
   157  
   158  	for k, v := range kv {
   159  		if v != "" {
   160  			mdIncoming.Set(k, v)
   161  		}
   162  	}
   163  
   164  	return metadata.NewIncomingContext(ctx, mdIncoming)
   165  }
   166  
   167  // GetCallerInfo retrieves caller information from the context if exists. Empty value is returned
   168  // if any piece of caller information is not specified in the context.
   169  func GetCallerInfo(
   170  	ctx context.Context,
   171  ) CallerInfo {
   172  	values := GetValues(ctx, callerNameHeaderName, CallerTypeHeaderName, callOriginHeaderName)
   173  	return CallerInfo{
   174  		CallerName: values[0],
   175  		CallerType: values[1],
   176  		CallOrigin: values[2],
   177  	}
   178  }