 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			283 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			283 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2021 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 dig
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"math/rand"
 | |
| 	"reflect"
 | |
| 
 | |
| 	"go.uber.org/dig/internal/dot"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	_optionalTag         = "optional"
 | |
| 	_nameTag             = "name"
 | |
| 	_ignoreUnexportedTag = "ignore-unexported"
 | |
| )
 | |
| 
 | |
| // Unique identification of an object in the graph.
 | |
| type key struct {
 | |
| 	t reflect.Type
 | |
| 
 | |
| 	// Only one of name or group will be set.
 | |
| 	name  string
 | |
| 	group string
 | |
| }
 | |
| 
 | |
| func (k key) String() string {
 | |
| 	if k.name != "" {
 | |
| 		return fmt.Sprintf("%v[name=%q]", k.t, k.name)
 | |
| 	}
 | |
| 	if k.group != "" {
 | |
| 		return fmt.Sprintf("%v[group=%q]", k.t, k.group)
 | |
| 	}
 | |
| 	return k.t.String()
 | |
| }
 | |
| 
 | |
| // Option configures a Container.
 | |
| type Option interface {
 | |
| 	applyOption(*Container)
 | |
| }
 | |
| 
 | |
| // Container is a directed acyclic graph of types and their dependencies.
 | |
| // A Container is the root Scope that represents the top-level scoped
 | |
| // directed acyclic graph of the dependencies.
 | |
| type Container struct {
 | |
| 	// this is the "root" Scope that represents the
 | |
| 	// root of the scope tree.
 | |
| 	scope *Scope
 | |
| }
 | |
| 
 | |
| // containerWriter provides write access to the Container's underlying data
 | |
| // store.
 | |
| type containerWriter interface {
 | |
| 	// setValue sets the value with the given name and type in the container.
 | |
| 	// If a value with the same name and type already exists, it will be
 | |
| 	// overwritten.
 | |
| 	setValue(name string, t reflect.Type, v reflect.Value)
 | |
| 
 | |
| 	// setDecoratedValue sets a decorated value with the given name and type
 | |
| 	// in the container. If a decorated value with the same name and type already
 | |
| 	// exists, it will be overwritten.
 | |
| 	setDecoratedValue(name string, t reflect.Type, v reflect.Value)
 | |
| 
 | |
| 	// submitGroupedValue submits a value to the value group with the provided
 | |
| 	// name.
 | |
| 	submitGroupedValue(name string, t reflect.Type, v reflect.Value)
 | |
| 
 | |
| 	// submitDecoratedGroupedValue submits a decorated value to the value group
 | |
| 	// with the provided name.
 | |
| 	submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value)
 | |
| }
 | |
| 
 | |
| // containerStore provides access to the Container's underlying data store.
 | |
| type containerStore interface {
 | |
| 	containerWriter
 | |
| 
 | |
| 	// Adds a new graph node to the Container
 | |
| 	newGraphNode(w interface{}, orders map[*Scope]int)
 | |
| 
 | |
| 	// Returns a slice containing all known types.
 | |
| 	knownTypes() []reflect.Type
 | |
| 
 | |
| 	// Retrieves the value with the provided name and type, if any.
 | |
| 	getValue(name string, t reflect.Type) (v reflect.Value, ok bool)
 | |
| 
 | |
| 	// Retrieves a decorated value with the provided name and type, if any.
 | |
| 	getDecoratedValue(name string, t reflect.Type) (v reflect.Value, ok bool)
 | |
| 
 | |
| 	// Retrieves all values for the provided group and type.
 | |
| 	//
 | |
| 	// The order in which the values are returned is undefined.
 | |
| 	getValueGroup(name string, t reflect.Type) []reflect.Value
 | |
| 
 | |
| 	// Retrieves all decorated values for the provided group and type, if any.
 | |
| 	getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool)
 | |
| 
 | |
| 	// Returns the providers that can produce a value with the given name and
 | |
| 	// type.
 | |
| 	getValueProviders(name string, t reflect.Type) []provider
 | |
| 
 | |
| 	// Returns the providers that can produce values for the given group and
 | |
| 	// type.
 | |
| 	getGroupProviders(name string, t reflect.Type) []provider
 | |
| 
 | |
| 	// Returns the providers that can produce a value with the given name and
 | |
| 	// type across all the Scopes that are in effect of this containerStore.
 | |
| 	getAllValueProviders(name string, t reflect.Type) []provider
 | |
| 
 | |
| 	// Returns the decorator that can decorate values for the given name and
 | |
| 	// type.
 | |
| 	getValueDecorator(name string, t reflect.Type) (decorator, bool)
 | |
| 
 | |
| 	// Reutrns the decorator that can decorate values for the given group and
 | |
| 	// type.
 | |
| 	getGroupDecorator(name string, t reflect.Type) (decorator, bool)
 | |
| 
 | |
| 	// Reports a list of stores (starting at this store) up to the root
 | |
| 	// store.
 | |
| 	storesToRoot() []containerStore
 | |
| 
 | |
| 	createGraph() *dot.Graph
 | |
| 
 | |
| 	// Returns invokerFn function to use when calling arguments.
 | |
| 	invoker() invokerFn
 | |
| }
 | |
| 
 | |
| // New constructs a Container.
 | |
| func New(opts ...Option) *Container {
 | |
| 	s := newScope()
 | |
| 	c := &Container{scope: s}
 | |
| 
 | |
| 	for _, opt := range opts {
 | |
| 		opt.applyOption(c)
 | |
| 	}
 | |
| 	return c
 | |
| }
 | |
| 
 | |
| // DeferAcyclicVerification is an Option to override the default behavior
 | |
| // of container.Provide, deferring the dependency graph validation to no longer
 | |
| // run after each call to container.Provide. The container will instead verify
 | |
| // the graph on first `Invoke`.
 | |
| //
 | |
| // Applications adding providers to a container in a tight loop may experience
 | |
| // performance improvements by initializing the container with this option.
 | |
| func DeferAcyclicVerification() Option {
 | |
| 	return deferAcyclicVerificationOption{}
 | |
| }
 | |
| 
 | |
| type deferAcyclicVerificationOption struct{}
 | |
| 
 | |
| func (deferAcyclicVerificationOption) String() string {
 | |
| 	return "DeferAcyclicVerification()"
 | |
| }
 | |
| 
 | |
| func (deferAcyclicVerificationOption) applyOption(c *Container) {
 | |
| 	c.scope.deferAcyclicVerification = true
 | |
| }
 | |
| 
 | |
| // RecoverFromPanics is an [Option] to recover from panics that occur while
 | |
| // running functions given to the container. When set, recovered panics
 | |
| // will be placed into a [PanicError], and returned at the invoke callsite.
 | |
| // See [PanicError] for an example on how to handle panics with this option
 | |
| // enabled, and distinguish them from errors.
 | |
| func RecoverFromPanics() Option {
 | |
| 	return recoverFromPanicsOption{}
 | |
| }
 | |
| 
 | |
| type recoverFromPanicsOption struct{}
 | |
| 
 | |
| func (recoverFromPanicsOption) String() string {
 | |
| 	return "RecoverFromPanics()"
 | |
| }
 | |
| 
 | |
| func (recoverFromPanicsOption) applyOption(c *Container) {
 | |
| 	c.scope.recoverFromPanics = true
 | |
| }
 | |
| 
 | |
| // Changes the source of randomness for the container.
 | |
| //
 | |
| // This will help provide determinism during tests.
 | |
| func setRand(r *rand.Rand) Option {
 | |
| 	return setRandOption{r: r}
 | |
| }
 | |
| 
 | |
| type setRandOption struct{ r *rand.Rand }
 | |
| 
 | |
| func (o setRandOption) String() string {
 | |
| 	return fmt.Sprintf("setRand(%p)", o.r)
 | |
| }
 | |
| 
 | |
| func (o setRandOption) applyOption(c *Container) {
 | |
| 	c.scope.rand = o.r
 | |
| }
 | |
| 
 | |
| // DryRun is an Option which, when set to true, disables invocation of functions supplied to
 | |
| // Provide and Invoke. Use this to build no-op containers.
 | |
| func DryRun(dry bool) Option {
 | |
| 	return dryRunOption(dry)
 | |
| }
 | |
| 
 | |
| type dryRunOption bool
 | |
| 
 | |
| func (o dryRunOption) String() string {
 | |
| 	return fmt.Sprintf("DryRun(%v)", bool(o))
 | |
| }
 | |
| 
 | |
| func (o dryRunOption) applyOption(c *Container) {
 | |
| 	if o {
 | |
| 		c.scope.invokerFn = dryInvoker
 | |
| 	} else {
 | |
| 		c.scope.invokerFn = defaultInvoker
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // invokerFn specifies how the container calls user-supplied functions.
 | |
| type invokerFn func(fn reflect.Value, args []reflect.Value) (results []reflect.Value)
 | |
| 
 | |
| func defaultInvoker(fn reflect.Value, args []reflect.Value) []reflect.Value {
 | |
| 	return fn.Call(args)
 | |
| }
 | |
| 
 | |
| // Generates zero values for results without calling the supplied function.
 | |
| func dryInvoker(fn reflect.Value, _ []reflect.Value) []reflect.Value {
 | |
| 	ft := fn.Type()
 | |
| 	results := make([]reflect.Value, ft.NumOut())
 | |
| 	for i := 0; i < ft.NumOut(); i++ {
 | |
| 		results[i] = reflect.Zero(fn.Type().Out(i))
 | |
| 	}
 | |
| 
 | |
| 	return results
 | |
| }
 | |
| 
 | |
| // String representation of the entire Container
 | |
| func (c *Container) String() string {
 | |
| 	return c.scope.String()
 | |
| }
 | |
| 
 | |
| // Scope creates a child scope of the Container with the given name.
 | |
| func (c *Container) Scope(name string, opts ...ScopeOption) *Scope {
 | |
| 	return c.scope.Scope(name, opts...)
 | |
| }
 | |
| 
 | |
| type byTypeName []reflect.Type
 | |
| 
 | |
| func (bs byTypeName) Len() int {
 | |
| 	return len(bs)
 | |
| }
 | |
| 
 | |
| func (bs byTypeName) Less(i int, j int) bool {
 | |
| 	return fmt.Sprint(bs[i]) < fmt.Sprint(bs[j])
 | |
| }
 | |
| 
 | |
| func (bs byTypeName) Swap(i int, j int) {
 | |
| 	bs[i], bs[j] = bs[j], bs[i]
 | |
| }
 | |
| 
 | |
| func shuffledCopy(rand *rand.Rand, items []reflect.Value) []reflect.Value {
 | |
| 	newItems := make([]reflect.Value, len(items))
 | |
| 	for i, j := range rand.Perm(len(items)) {
 | |
| 		newItems[i] = items[j]
 | |
| 	}
 | |
| 	return newItems
 | |
| }
 |