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 }