dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/credentials/certprovider/distributor.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. 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 * 20 * Copyright 2020 gRPC authors. 21 * 22 */ 23 24 package certprovider 25 26 import ( 27 "context" 28 "sync" 29 ) 30 31 import ( 32 "dubbo.apache.org/dubbo-go/v3/xds/utils/grpcsync" 33 ) 34 35 // Distributor makes it easy for provider implementations to furnish new key 36 // materials by handling synchronization between the producer and consumers of 37 // the key material. 38 // 39 // Provider implementations which choose to use a Distributor should do the 40 // following: 41 // - create a new Distributor using the NewDistributor() function. 42 // - invoke the Set() method whenever they have new key material or errors to 43 // report. 44 // - delegate to the distributor when handing calls to KeyMaterial(). 45 // - invoke the Stop() method when they are done using the distributor. 46 type Distributor struct { 47 // mu protects the underlying key material. 48 mu sync.Mutex 49 km *KeyMaterial 50 pErr error 51 52 // ready channel to unblock KeyMaterial() invocations blocked on 53 // availability of key material. 54 ready *grpcsync.Event 55 // done channel to notify provider implementations and unblock any 56 // KeyMaterial() calls, once the Distributor is closed. 57 closed *grpcsync.Event 58 } 59 60 // NewDistributor returns a new Distributor. 61 func NewDistributor() *Distributor { 62 return &Distributor{ 63 ready: grpcsync.NewEvent(), 64 closed: grpcsync.NewEvent(), 65 } 66 } 67 68 // Set updates the key material in the distributor with km. 69 // 70 // Provider implementations which use the distributor must not modify the 71 // contents of the KeyMaterial struct pointed to by km. 72 // 73 // A non-nil err value indicates the error that the provider implementation ran 74 // into when trying to fetch key material, and makes it possible to surface the 75 // error to the user. A non-nil error value passed here causes distributor's 76 // KeyMaterial() method to return nil key material. 77 func (d *Distributor) Set(km *KeyMaterial, err error) { 78 d.mu.Lock() 79 d.km = km 80 d.pErr = err 81 if err != nil { 82 // If a non-nil err is passed, we ignore the key material being passed. 83 d.km = nil 84 } 85 d.ready.Fire() 86 d.mu.Unlock() 87 } 88 89 // KeyMaterial returns the most recent key material provided to the Distributor. 90 // If no key material was provided at the time of this call, it will block until 91 // the deadline on the context expires or fresh key material arrives. 92 func (d *Distributor) KeyMaterial(ctx context.Context) (*KeyMaterial, error) { 93 if d.closed.HasFired() { 94 return nil, errProviderClosed 95 } 96 97 if d.ready.HasFired() { 98 return d.keyMaterial() 99 } 100 101 select { 102 case <-ctx.Done(): 103 return nil, ctx.Err() 104 case <-d.closed.Done(): 105 return nil, errProviderClosed 106 case <-d.ready.Done(): 107 return d.keyMaterial() 108 } 109 } 110 111 func (d *Distributor) keyMaterial() (*KeyMaterial, error) { 112 d.mu.Lock() 113 defer d.mu.Unlock() 114 return d.km, d.pErr 115 } 116 117 // Stop turns down the distributor, releases allocated resources and fails any 118 // active KeyMaterial() call waiting for new key material. 119 func (d *Distributor) Stop() { 120 d.closed.Fire() 121 }