github.com/status-im/status-go@v1.1.0/server/timeout.go (about) 1 package server 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 // timeoutManager represents a discrete encapsulation of timeout functionality. 9 // this struct expose 3 functions: 10 // - SetTimeout 11 // - StartTimeout 12 // - StopTimeout 13 type timeoutManager struct { 14 // timeout number of milliseconds the timeout operation will run before executing the `terminate` func() 15 // 0 represents an inactive timeout 16 timeout uint 17 18 // exitQueue handles the cancel signal channels that circumvent timeout operations and prevent the 19 // execution of any `terminate` func() 20 exitQueue *exitQueueManager 21 } 22 23 // newTimeoutManager returns a fully qualified and initialised timeoutManager 24 func newTimeoutManager() *timeoutManager { 25 return &timeoutManager{ 26 exitQueue: &exitQueueManager{queue: []chan struct{}{}}, 27 } 28 } 29 30 // SetTimeout sets the value of the timeoutManager.timeout 31 func (t *timeoutManager) SetTimeout(milliseconds uint) { 32 t.timeout = milliseconds 33 } 34 35 // StartTimeout starts a timeout operation based on the set timeoutManager.timeout value 36 // the given terminate func() will be executed once the timeout duration has passed 37 func (t *timeoutManager) StartTimeout(terminate func()) { 38 if t.timeout == 0 { 39 return 40 } 41 t.StopTimeout() 42 43 exit := make(chan struct{}, 1) 44 t.exitQueue.add(exit) 45 go t.run(terminate, exit) 46 } 47 48 // StopTimeout terminates a timeout operation and exits gracefully 49 func (t *timeoutManager) StopTimeout() { 50 if t.timeout == 0 { 51 return 52 } 53 t.exitQueue.empty() 54 } 55 56 // run inits the main timeout run function that awaits for the exit command to be triggered or for the 57 // timeout duration to elapse and trigger the parameter terminate function. 58 func (t *timeoutManager) run(terminate func(), exit chan struct{}) { 59 select { 60 case <-exit: 61 return 62 case <-time.After(time.Duration(t.timeout) * time.Millisecond): 63 terminate() 64 // TODO fire signal to let UI know 65 // https://github.com/status-im/status-go/issues/3305 66 return 67 } 68 } 69 70 // exitQueueManager 71 type exitQueueManager struct { 72 queue []chan struct{} 73 queueLock sync.Mutex 74 } 75 76 // add handles new exit channels adding them to the exit queue 77 func (e *exitQueueManager) add(exit chan struct{}) { 78 e.queueLock.Lock() 79 defer e.queueLock.Unlock() 80 81 e.queue = append(e.queue, exit) 82 } 83 84 // empty sends a signal to every exit channel in the queue and then resets the queue 85 func (e *exitQueueManager) empty() { 86 e.queueLock.Lock() 87 defer e.queueLock.Unlock() 88 89 for i := range e.queue { 90 e.queue[i] <- struct{}{} 91 } 92 93 e.queue = []chan struct{}{} 94 }