decred.org/dcrdex@v1.0.5/dex/meter/meterer.go (about)

     1  // This code is available on the terms of the project LICENSE.md file,
     2  // also available online at https://blueoakcouncil.org/license/1.0.0.
     3  
     4  package meter
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  )
    10  
    11  // DelayedRelay creates a simple error signal pipeline that delays and
    12  // aggregates the relaying of nil errors. Non-nil errors received on the in
    13  // channel are immediately sent on the out channel without delay. If a nil error
    14  // arrives within minDelay of the previous one, it will be scheduled for later
    15  // to respect the configured delay. If multiple arrive within minDelay, they
    16  // will be grouped into a single delayed signal.
    17  func DelayedRelay(ctx context.Context, minDelay time.Duration, n int) (out <-chan error, in chan<- error) {
    18  	inC := make(chan error, n)
    19  	outC := make(chan error, n)
    20  
    21  	go func() {
    22  		defer close(outC) // signal shutdown to the consumer
    23  
    24  		var last time.Time
    25  		var scheduled *time.Timer
    26  		now := make(chan struct{})
    27  
    28  		for {
    29  			select {
    30  			case err := <-inC:
    31  				if err != nil {
    32  					outC <- err
    33  					continue
    34  				}
    35  
    36  				if scheduled != nil {
    37  					continue
    38  				}
    39  
    40  				if time.Since(last) > minDelay {
    41  					outC <- nil
    42  					last = time.Now()
    43  					continue
    44  				}
    45  
    46  				delay := time.Until(last.Add(minDelay))
    47  				scheduled = time.AfterFunc(delay, func() {
    48  					now <- struct{}{}
    49  				})
    50  
    51  			case <-now:
    52  				outC <- nil
    53  				scheduled = nil
    54  				last = time.Now()
    55  
    56  			case <-ctx.Done():
    57  				if scheduled != nil {
    58  					scheduled.Stop()
    59  				}
    60  				return
    61  			}
    62  		}
    63  	}()
    64  
    65  	return outC, inC
    66  }