github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/credentials/tls/certprovider/distributor.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 "context" 23 "sync" 24 25 "github.com/hxx258456/ccgo/grpc/internal/grpcsync" 26 ) 27 28 // Distributor makes it easy for provider implementations to furnish new key 29 // materials by handling synchronization between the producer and consumers of 30 // the key material. 31 // 32 // Provider implementations which choose to use a Distributor should do the 33 // following: 34 // - create a new Distributor using the NewDistributor() function. 35 // - invoke the Set() method whenever they have new key material or errors to 36 // report. 37 // - delegate to the distributor when handing calls to KeyMaterial(). 38 // - invoke the Stop() method when they are done using the distributor. 39 type Distributor struct { 40 // mu protects the underlying key material. 41 mu sync.Mutex 42 km *KeyMaterial 43 pErr error 44 45 // ready channel to unblock KeyMaterial() invocations blocked on 46 // availability of key material. 47 ready *grpcsync.Event 48 // done channel to notify provider implementations and unblock any 49 // KeyMaterial() calls, once the Distributor is closed. 50 closed *grpcsync.Event 51 } 52 53 // NewDistributor returns a new Distributor. 54 func NewDistributor() *Distributor { 55 return &Distributor{ 56 ready: grpcsync.NewEvent(), 57 closed: grpcsync.NewEvent(), 58 } 59 } 60 61 // Set updates the key material in the distributor with km. 62 // 63 // Provider implementations which use the distributor must not modify the 64 // contents of the KeyMaterial struct pointed to by km. 65 // 66 // A non-nil err value indicates the error that the provider implementation ran 67 // into when trying to fetch key material, and makes it possible to surface the 68 // error to the user. A non-nil error value passed here causes distributor's 69 // KeyMaterial() method to return nil key material. 70 func (d *Distributor) Set(km *KeyMaterial, err error) { 71 d.mu.Lock() 72 d.km = km 73 d.pErr = err 74 if err != nil { 75 // If a non-nil err is passed, we ignore the key material being passed. 76 d.km = nil 77 } 78 d.ready.Fire() 79 d.mu.Unlock() 80 } 81 82 // KeyMaterial returns the most recent key material provided to the Distributor. 83 // If no key material was provided at the time of this call, it will block until 84 // the deadline on the context expires or fresh key material arrives. 85 func (d *Distributor) KeyMaterial(ctx context.Context) (*KeyMaterial, error) { 86 if d.closed.HasFired() { 87 return nil, errProviderClosed 88 } 89 90 if d.ready.HasFired() { 91 return d.keyMaterial() 92 } 93 94 select { 95 case <-ctx.Done(): 96 return nil, ctx.Err() 97 case <-d.closed.Done(): 98 return nil, errProviderClosed 99 case <-d.ready.Done(): 100 return d.keyMaterial() 101 } 102 } 103 104 func (d *Distributor) keyMaterial() (*KeyMaterial, error) { 105 d.mu.Lock() 106 defer d.mu.Unlock() 107 return d.km, d.pErr 108 } 109 110 // Stop turns down the distributor, releases allocated resources and fails any 111 // active KeyMaterial() call waiting for new key material. 112 func (d *Distributor) Stop() { 113 d.closed.Fire() 114 }