github.com/golodash/godash@v1.3.0/functions/run_after.go (about)

     1  package functions
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/golodash/godash/internal"
     9  )
    10  
    11  type runCancel interface {
    12  	Run() []interface{}
    13  	Cancel() (bool, error)
    14  }
    15  
    16  type runCancelStruct struct {
    17  	function   func() []interface{}
    18  	wait       time.Duration
    19  	parallel   bool
    20  	lock       *sync.Mutex
    21  	canceled   bool
    22  	inProgress bool
    23  	done       bool
    24  }
    25  
    26  // Returns an interface with two methods. one called Run which executes the
    27  // function and other one called Cancel which cancels executing of current
    28  // executed Run function.
    29  //
    30  // You can use WrapFunc to generate `function`.
    31  //
    32  // Complexity: O(1)
    33  func RunAfter(function func() []interface{}, wait time.Duration, parallel bool) runCancel {
    34  	if ok := internal.IsFunc(function); !ok {
    35  		panic("`function` input is not a function")
    36  	}
    37  
    38  	r := runCancelStruct{
    39  		function:   function,
    40  		wait:       wait,
    41  		parallel:   parallel,
    42  		lock:       &sync.Mutex{},
    43  		canceled:   false,
    44  		inProgress: false,
    45  		done:       false,
    46  	}
    47  
    48  	return &r
    49  }
    50  
    51  func (r *runCancelStruct) Run() []interface{} {
    52  	r.lock.Lock()
    53  	r.reset()
    54  	r.lock.Unlock()
    55  	if r.parallel {
    56  		ch := make(chan bool)
    57  		go func() {
    58  			value, ok := <-ch
    59  			if ok && value {
    60  				r.function()
    61  				r.lock.Lock()
    62  				defer r.lock.Unlock()
    63  				r.done = true
    64  			} else {
    65  				return
    66  			}
    67  		}()
    68  		go func() {
    69  			time.Sleep(r.wait)
    70  			r.lock.Lock()
    71  			defer r.lock.Unlock()
    72  			if !r.canceled {
    73  				r.inProgress = true
    74  				ch <- true
    75  			} else {
    76  				ch <- false
    77  			}
    78  		}()
    79  	} else {
    80  		time.Sleep(r.wait)
    81  		return r.function()
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func (r *runCancelStruct) Cancel() (bool, error) {
    88  	if r.parallel {
    89  		r.lock.Lock()
    90  		defer r.lock.Unlock()
    91  		if r.inProgress && !r.done {
    92  			return false, errors.New("function in progress")
    93  		} else if r.done {
    94  			return false, errors.New("function done")
    95  		}
    96  
    97  		r.canceled = true
    98  		return true, nil
    99  	} else {
   100  		return false, errors.New("parallel is off")
   101  	}
   102  }
   103  
   104  func (r *runCancelStruct) reset() {
   105  	r.canceled = false
   106  	r.inProgress = false
   107  	r.done = false
   108  }