gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/credentials/tls/certprovider/store.go (about)

     1  /*
     2   *
     3   * Copyright 2020 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package certprovider
    20  
    21  import (
    22  	"fmt"
    23  	"sync"
    24  )
    25  
    26  // provStore is the global singleton certificate provider store.
    27  var provStore = &store{
    28  	providers: make(map[storeKey]*wrappedProvider),
    29  }
    30  
    31  // storeKey acts as the key to the map of providers maintained by the store. A
    32  // combination of provider name and configuration is used to uniquely identify
    33  // every provider instance in the store. Go maps need to be indexed by
    34  // comparable types, so the provider configuration is converted from
    35  // `interface{}` to string using the ParseConfig method while creating this key.
    36  type storeKey struct {
    37  	// name of the certificate provider.
    38  	name string
    39  	// configuration of the certificate provider in string form.
    40  	config string
    41  	// opts contains the certificate name and other keyMaterial options.
    42  	opts BuildOptions
    43  }
    44  
    45  // wrappedProvider wraps a provider instance with a reference count.
    46  type wrappedProvider struct {
    47  	Provider
    48  	refCount int
    49  
    50  	// A reference to the key and store are also kept here to override the
    51  	// Close method on the provider.
    52  	storeKey storeKey
    53  	store    *store
    54  }
    55  
    56  // store is a collection of provider instances, safe for concurrent access.
    57  type store struct {
    58  	mu        sync.Mutex
    59  	providers map[storeKey]*wrappedProvider
    60  }
    61  
    62  // Close overrides the Close method of the embedded provider. It releases the
    63  // reference held by the caller on the underlying provider and if the
    64  // provider's reference count reaches zero, it is removed from the store, and
    65  // its Close method is also invoked.
    66  func (wp *wrappedProvider) Close() {
    67  	ps := wp.store
    68  	ps.mu.Lock()
    69  	defer ps.mu.Unlock()
    70  
    71  	wp.refCount--
    72  	if wp.refCount == 0 {
    73  		wp.Provider.Close()
    74  		delete(ps.providers, wp.storeKey)
    75  	}
    76  }
    77  
    78  // BuildableConfig wraps parsed provider configuration and functionality to
    79  // instantiate provider instances.
    80  type BuildableConfig struct {
    81  	name    string
    82  	config  []byte
    83  	starter func(BuildOptions) Provider
    84  	pStore  *store
    85  }
    86  
    87  // NewBuildableConfig creates a new BuildableConfig with the given arguments.
    88  // Provider implementations are expected to invoke this function after parsing
    89  // the given configuration as part of their ParseConfig() method.
    90  // Equivalent configurations are expected to invoke this function with the same
    91  // config argument.
    92  func NewBuildableConfig(name string, config []byte, starter func(BuildOptions) Provider) *BuildableConfig {
    93  	return &BuildableConfig{
    94  		name:    name,
    95  		config:  config,
    96  		starter: starter,
    97  		pStore:  provStore,
    98  	}
    99  }
   100  
   101  // Build kicks off a provider instance with the wrapped configuration. Multiple
   102  // invocations of this method with the same opts will result in provider
   103  // instances being reused.
   104  func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
   105  	provStore.mu.Lock()
   106  	defer provStore.mu.Unlock()
   107  
   108  	sk := storeKey{
   109  		name:   bc.name,
   110  		config: string(bc.config),
   111  		opts:   opts,
   112  	}
   113  	if wp, ok := provStore.providers[sk]; ok {
   114  		wp.refCount++
   115  		return wp, nil
   116  	}
   117  
   118  	provider := bc.starter(opts)
   119  	if provider == nil {
   120  		return nil, fmt.Errorf("provider(%q, %q).Build(%v) failed", sk.name, sk.config, opts)
   121  	}
   122  	wp := &wrappedProvider{
   123  		Provider: provider,
   124  		refCount: 1,
   125  		storeKey: sk,
   126  		store:    provStore,
   127  	}
   128  	provStore.providers[sk] = wp
   129  	return wp, nil
   130  }
   131  
   132  // String returns the provider name and config as a colon separated string.
   133  func (bc *BuildableConfig) String() string {
   134  	return fmt.Sprintf("%s:%s", bc.name, string(bc.config))
   135  }
   136  
   137  // ParseConfig is a convenience function to create a BuildableConfig given a
   138  // provider name and configuration. Returns an error if there is no registered
   139  // builder for the given name or if the config parsing fails.
   140  func ParseConfig(name string, config interface{}) (*BuildableConfig, error) {
   141  	parser := getBuilder(name)
   142  	if parser == nil {
   143  		return nil, fmt.Errorf("no certificate provider builder found for %q", name)
   144  	}
   145  	return parser.ParseConfig(config)
   146  }
   147  
   148  // GetProvider is a convenience function to create a provider given the name,
   149  // config and build options.
   150  func GetProvider(name string, config interface{}, opts BuildOptions) (Provider, error) {
   151  	bc, err := ParseConfig(name, config)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	return bc.Build(opts)
   156  }