mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	add cancellation code to util, like context but just the cancellation parts + some error logic
This commit is contained in:
		
							parent
							
								
									c36da7b814
								
							
						
					
					
						commit
						06e8403aaf
					
				
					 1 changed files with 83 additions and 0 deletions
				
			
		
							
								
								
									
										83
									
								
								src/util/cancellation.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/util/cancellation.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,83 @@
 | 
			
		|||
package util
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
  "errors"
 | 
			
		||||
  "sync"
 | 
			
		||||
  "time"
 | 
			
		||||
  "runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Cancellation interface {
 | 
			
		||||
  Finished() <-chan struct{}
 | 
			
		||||
  Cancel(error) error
 | 
			
		||||
  Error() error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CancellationFinalizer(c Cancellation) {
 | 
			
		||||
  c.Cancel(errors.New("finalizer called"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cancellation struct {
 | 
			
		||||
  signal chan error
 | 
			
		||||
  cancel chan struct{}
 | 
			
		||||
  errMtx sync.RWMutex
 | 
			
		||||
  err error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cancellation) worker() {
 | 
			
		||||
    // Launch this in a separate goroutine when creating a cancellation
 | 
			
		||||
    err := <-c.signal
 | 
			
		||||
    c.errMtx.Lock()
 | 
			
		||||
    c.err = err
 | 
			
		||||
    c.errMtx.Unlock()
 | 
			
		||||
    close(c.cancel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCancellation() Cancellation {
 | 
			
		||||
  c := cancellation{
 | 
			
		||||
    signal: make(chan error),
 | 
			
		||||
    cancel: make(chan struct{}),
 | 
			
		||||
  }
 | 
			
		||||
  runtime.SetFinalizer(&c, CancellationFinalizer)
 | 
			
		||||
  go c.worker()
 | 
			
		||||
  return &c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cancellation) Finished() <-chan struct{} {
 | 
			
		||||
  return c.cancel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cancellation) Cancel(err error) error {
 | 
			
		||||
  select {
 | 
			
		||||
  case c.signal<-err:
 | 
			
		||||
    return nil
 | 
			
		||||
  case <-c.cancel:
 | 
			
		||||
    return c.Error()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cancellation) Error() error {
 | 
			
		||||
  c.errMtx.RLock()
 | 
			
		||||
  err := c.err
 | 
			
		||||
  c.errMtx.RUnlock()
 | 
			
		||||
  return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CancellationWithTimeout(parent Cancellation, timeout time.Duration) Cancellation {
 | 
			
		||||
  child := NewCancellation()
 | 
			
		||||
  go func() {
 | 
			
		||||
    timer := time.NewTimer(timeout)
 | 
			
		||||
    defer TimerStop(timer)
 | 
			
		||||
    select {
 | 
			
		||||
    case <-parent.Finished():
 | 
			
		||||
      child.Cancel(parent.Error())
 | 
			
		||||
    case <-timer.C:
 | 
			
		||||
      child.Cancel(errors.New("timeout"))
 | 
			
		||||
    }
 | 
			
		||||
  }()
 | 
			
		||||
  return child
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CancellationWithDeadline(parent Cancellation, deadline time.Time) Cancellation {
 | 
			
		||||
  return CancellationWithTimeout(parent, deadline.Sub(time.Now()))
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue