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  }