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 }