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  }