 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>
		
			
				
	
	
		
			327 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			9.2 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 (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"math/rand"
 | |
| 	"reflect"
 | |
| 	"sort"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| // A ScopeOption modifies the default behavior of Scope; currently,
 | |
| // there are no implementations.
 | |
| type ScopeOption interface {
 | |
| 	noScopeOption() //yet
 | |
| }
 | |
| 
 | |
| // Scope is a scoped DAG of types and their dependencies.
 | |
| // A Scope may also have one or more child Scopes that inherit
 | |
| // from it.
 | |
| type Scope struct {
 | |
| 	// This implements containerStore interface.
 | |
| 
 | |
| 	// Name of the Scope
 | |
| 	name string
 | |
| 	// Mapping from key to all the constructor node that can provide a value for that
 | |
| 	// key.
 | |
| 	providers map[key][]*constructorNode
 | |
| 
 | |
| 	// Mapping from key to the decorator that decorates a value for that key.
 | |
| 	decorators map[key]*decoratorNode
 | |
| 
 | |
| 	// constructorNodes provided directly to this Scope. i.e. it does not include
 | |
| 	// any nodes that were provided to the parent Scope this inherited from.
 | |
| 	nodes []*constructorNode
 | |
| 
 | |
| 	// Values that generated via decorators in the Scope.
 | |
| 	decoratedValues map[key]reflect.Value
 | |
| 
 | |
| 	// Values that generated directly in the Scope.
 | |
| 	values map[key]reflect.Value
 | |
| 
 | |
| 	// Values groups that generated directly in the Scope.
 | |
| 	groups map[key][]reflect.Value
 | |
| 
 | |
| 	// Values groups that generated via decoraters in the Scope.
 | |
| 	decoratedGroups map[key]reflect.Value
 | |
| 
 | |
| 	// Source of randomness.
 | |
| 	rand *rand.Rand
 | |
| 
 | |
| 	// Flag indicating whether the graph has been checked for cycles.
 | |
| 	isVerifiedAcyclic bool
 | |
| 
 | |
| 	// Defer acyclic check on provide until Invoke.
 | |
| 	deferAcyclicVerification bool
 | |
| 
 | |
| 	// Recover from panics in user-provided code and wrap in an exported error type.
 | |
| 	recoverFromPanics bool
 | |
| 
 | |
| 	// invokerFn calls a function with arguments provided to Provide or Invoke.
 | |
| 	invokerFn invokerFn
 | |
| 
 | |
| 	// graph of this Scope. Note that this holds the dependency graph of all the
 | |
| 	// nodes that affect this Scope, not just the ones provided directly to this Scope.
 | |
| 	gh *graphHolder
 | |
| 
 | |
| 	// Parent of this Scope.
 | |
| 	parentScope *Scope
 | |
| 
 | |
| 	// All the child scopes of this Scope.
 | |
| 	childScopes []*Scope
 | |
| }
 | |
| 
 | |
| func newScope() *Scope {
 | |
| 	s := &Scope{
 | |
| 		providers:       make(map[key][]*constructorNode),
 | |
| 		decorators:      make(map[key]*decoratorNode),
 | |
| 		values:          make(map[key]reflect.Value),
 | |
| 		decoratedValues: make(map[key]reflect.Value),
 | |
| 		groups:          make(map[key][]reflect.Value),
 | |
| 		decoratedGroups: make(map[key]reflect.Value),
 | |
| 		invokerFn:       defaultInvoker,
 | |
| 		rand:            rand.New(rand.NewSource(time.Now().UnixNano())),
 | |
| 	}
 | |
| 	s.gh = newGraphHolder(s)
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // Scope creates a new Scope with the given name and options from current Scope.
 | |
| // Any constructors that the current Scope knows about, as well as any modifications
 | |
| // made to it in the future will be propagated to the child scope.
 | |
| // However, no modifications made to the child scope being created will be propagated
 | |
| // to the parent Scope.
 | |
| func (s *Scope) Scope(name string, opts ...ScopeOption) *Scope {
 | |
| 	child := newScope()
 | |
| 	child.name = name
 | |
| 	child.parentScope = s
 | |
| 	child.invokerFn = s.invokerFn
 | |
| 	child.deferAcyclicVerification = s.deferAcyclicVerification
 | |
| 	child.recoverFromPanics = s.recoverFromPanics
 | |
| 
 | |
| 	// child copies the parent's graph nodes.
 | |
| 	for _, node := range s.gh.nodes {
 | |
| 		child.gh.nodes = append(child.gh.nodes, node)
 | |
| 		if ctrNode, ok := node.Wrapped.(*constructorNode); ok {
 | |
| 			ctrNode.CopyOrder(s, child)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for _, opt := range opts {
 | |
| 		opt.noScopeOption()
 | |
| 	}
 | |
| 
 | |
| 	s.childScopes = append(s.childScopes, child)
 | |
| 	return child
 | |
| }
 | |
| 
 | |
| // ancestors returns a list of scopes of ancestors of this scope up to the
 | |
| // root. The scope at at index 0 is this scope itself.
 | |
| func (s *Scope) ancestors() []*Scope {
 | |
| 	var scopes []*Scope
 | |
| 	for s := s; s != nil; s = s.parentScope {
 | |
| 		scopes = append(scopes, s)
 | |
| 	}
 | |
| 	return scopes
 | |
| }
 | |
| 
 | |
| func (s *Scope) appendSubscopes(dest []*Scope) []*Scope {
 | |
| 	dest = append(dest, s)
 | |
| 	for _, cs := range s.childScopes {
 | |
| 		dest = cs.appendSubscopes(dest)
 | |
| 	}
 | |
| 	return dest
 | |
| }
 | |
| 
 | |
| func (s *Scope) storesToRoot() []containerStore {
 | |
| 	scopes := s.ancestors()
 | |
| 	stores := make([]containerStore, len(scopes))
 | |
| 	for i, s := range scopes {
 | |
| 		stores[i] = s
 | |
| 	}
 | |
| 	return stores
 | |
| }
 | |
| 
 | |
| func (s *Scope) knownTypes() []reflect.Type {
 | |
| 	typeSet := make(map[reflect.Type]struct{}, len(s.providers))
 | |
| 	for k := range s.providers {
 | |
| 		typeSet[k.t] = struct{}{}
 | |
| 	}
 | |
| 
 | |
| 	types := make([]reflect.Type, 0, len(typeSet))
 | |
| 	for t := range typeSet {
 | |
| 		types = append(types, t)
 | |
| 	}
 | |
| 	sort.Sort(byTypeName(types))
 | |
| 	return types
 | |
| }
 | |
| 
 | |
| func (s *Scope) getValue(name string, t reflect.Type) (v reflect.Value, ok bool) {
 | |
| 	v, ok = s.values[key{name: name, t: t}]
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (s *Scope) getDecoratedValue(name string, t reflect.Type) (v reflect.Value, ok bool) {
 | |
| 	v, ok = s.decoratedValues[key{name: name, t: t}]
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (s *Scope) setValue(name string, t reflect.Type, v reflect.Value) {
 | |
| 	s.values[key{name: name, t: t}] = v
 | |
| }
 | |
| 
 | |
| func (s *Scope) setDecoratedValue(name string, t reflect.Type, v reflect.Value) {
 | |
| 	s.decoratedValues[key{name: name, t: t}] = v
 | |
| }
 | |
| 
 | |
| func (s *Scope) getValueGroup(name string, t reflect.Type) []reflect.Value {
 | |
| 	items := s.groups[key{group: name, t: t}]
 | |
| 	// shuffle the list so users don't rely on the ordering of grouped values
 | |
| 	return shuffledCopy(s.rand, items)
 | |
| }
 | |
| 
 | |
| func (s *Scope) getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool) {
 | |
| 	items, ok := s.decoratedGroups[key{group: name, t: t}]
 | |
| 	return items, ok
 | |
| }
 | |
| 
 | |
| func (s *Scope) submitGroupedValue(name string, t reflect.Type, v reflect.Value) {
 | |
| 	k := key{group: name, t: t}
 | |
| 	s.groups[k] = append(s.groups[k], v)
 | |
| }
 | |
| 
 | |
| func (s *Scope) submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value) {
 | |
| 	k := key{group: name, t: t}
 | |
| 	s.decoratedGroups[k] = v
 | |
| }
 | |
| 
 | |
| func (s *Scope) getValueProviders(name string, t reflect.Type) []provider {
 | |
| 	return s.getProviders(key{name: name, t: t})
 | |
| }
 | |
| 
 | |
| func (s *Scope) getGroupProviders(name string, t reflect.Type) []provider {
 | |
| 	return s.getProviders(key{group: name, t: t})
 | |
| }
 | |
| 
 | |
| func (s *Scope) getValueDecorator(name string, t reflect.Type) (decorator, bool) {
 | |
| 	return s.getDecorators(key{name: name, t: t})
 | |
| }
 | |
| 
 | |
| func (s *Scope) getGroupDecorator(name string, t reflect.Type) (decorator, bool) {
 | |
| 	return s.getDecorators(key{group: name, t: t})
 | |
| }
 | |
| 
 | |
| func (s *Scope) getDecorators(k key) (decorator, bool) {
 | |
| 	d, found := s.decorators[k]
 | |
| 	return d, found
 | |
| }
 | |
| 
 | |
| func (s *Scope) getProviders(k key) []provider {
 | |
| 	nodes := s.providers[k]
 | |
| 	providers := make([]provider, len(nodes))
 | |
| 	for i, n := range nodes {
 | |
| 		providers[i] = n
 | |
| 	}
 | |
| 	return providers
 | |
| }
 | |
| 
 | |
| func (s *Scope) getAllGroupProviders(name string, t reflect.Type) []provider {
 | |
| 	return s.getAllProviders(key{group: name, t: t})
 | |
| }
 | |
| 
 | |
| func (s *Scope) getAllValueProviders(name string, t reflect.Type) []provider {
 | |
| 	return s.getAllProviders(key{name: name, t: t})
 | |
| }
 | |
| 
 | |
| func (s *Scope) getAllProviders(k key) []provider {
 | |
| 	allScopes := s.ancestors()
 | |
| 	var providers []provider
 | |
| 	for _, scope := range allScopes {
 | |
| 		providers = append(providers, scope.getProviders(k)...)
 | |
| 	}
 | |
| 	return providers
 | |
| }
 | |
| 
 | |
| func (s *Scope) invoker() invokerFn {
 | |
| 	return s.invokerFn
 | |
| }
 | |
| 
 | |
| // adds a new graphNode to this Scope and all of its descendent
 | |
| // scope.
 | |
| func (s *Scope) newGraphNode(wrapped interface{}, orders map[*Scope]int) {
 | |
| 	orders[s] = s.gh.NewNode(wrapped)
 | |
| 	for _, cs := range s.childScopes {
 | |
| 		cs.newGraphNode(wrapped, orders)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *Scope) cycleDetectedError(cycle []int) error {
 | |
| 	var path []cycleErrPathEntry
 | |
| 	for _, n := range cycle {
 | |
| 		if n, ok := s.gh.Lookup(n).(*constructorNode); ok {
 | |
| 			path = append(path, cycleErrPathEntry{
 | |
| 				Key: key{
 | |
| 					t: n.CType(),
 | |
| 				},
 | |
| 				Func: n.Location(),
 | |
| 			})
 | |
| 		}
 | |
| 	}
 | |
| 	return errCycleDetected{Path: path, scope: s}
 | |
| }
 | |
| 
 | |
| // Returns the root Scope that can be reached from this Scope.
 | |
| func (s *Scope) rootScope() *Scope {
 | |
| 	curr := s
 | |
| 	for curr.parentScope != nil {
 | |
| 		curr = curr.parentScope
 | |
| 	}
 | |
| 	return curr
 | |
| }
 | |
| 
 | |
| // String representation of the entire Scope
 | |
| func (s *Scope) String() string {
 | |
| 	b := &bytes.Buffer{}
 | |
| 	fmt.Fprintln(b, "nodes: {")
 | |
| 	for k, vs := range s.providers {
 | |
| 		for _, v := range vs {
 | |
| 			fmt.Fprintln(b, "\t", k, "->", v)
 | |
| 		}
 | |
| 	}
 | |
| 	fmt.Fprintln(b, "}")
 | |
| 
 | |
| 	fmt.Fprintln(b, "values: {")
 | |
| 	for k, v := range s.values {
 | |
| 		fmt.Fprintln(b, "\t", k, "=>", v)
 | |
| 	}
 | |
| 	for k, vs := range s.groups {
 | |
| 		for _, v := range vs {
 | |
| 			fmt.Fprintln(b, "\t", k, "=>", v)
 | |
| 		}
 | |
| 	}
 | |
| 	fmt.Fprintln(b, "}")
 | |
| 
 | |
| 	return b.String()
 | |
| }
 |