github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekatime/once_in.go (about)

     1  // Copyright © 2020. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekatime
     7  
     8  import (
     9  	"sync/atomic"
    10  )
    11  
    12  type (
    13  	// OnceInCallback is an alias to the function that user must define.
    14  	//
    15  	// That function user could pass to the OnceIn<interval>.Call() call.
    16  	// Then it will be called each time when time has come.
    17  	//
    18  	// An arguments represents a moment when a callback is called.
    19  	OnceInCallback func(ts Timestamp)
    20  
    21  	// OnceInPanicCallback is an alias to the function that user may define.
    22  	//
    23  	// That function user could pass along with OnceInCallback
    24  	// to the OnceIn<interval>.Call() call.
    25  	// This function will be called only if original OnceInCallback panics.
    26  	//
    27  	// An argument represents a recovered panic object.
    28  	OnceInPanicCallback func(panicObj any)
    29  )
    30  
    31  // noinspection GoUnusedGlobalVariable
    32  var (
    33  	// -----
    34  	// OnceIn<period> are a special objects that allows you to get the current time
    35  	// that is not really actual but under updating each time when specified
    36  	// period has come.
    37  	//
    38  	// For example, the OnceInMinute provides a new time for you each minute,
    39  	// meaning that inside one minute you will get the same unix timestamp.
    40  	//
    41  	// It's useful when you do not need an exact time or time with highest precision
    42  	// because of NewTimestampNow() call more expensive than these calls (up to 8x times).
    43  	// -----
    44  
    45  	// OnceInMinute allows you to get an actual time once in 60 seconds (1 minute).
    46  	OnceInMinute onceInUpdater
    47  
    48  	// OnceIn10Minutes allows you to get an actual time once in 10 minutes.
    49  	OnceIn10Minutes onceInUpdater
    50  
    51  	// OnceIn15Minutes allows you to get an actual time once in 15 minutes.
    52  	OnceIn15Minutes onceInUpdater
    53  
    54  	// OnceIn30Minutes allows you to get an actual time once in 30 minutes.
    55  	OnceIn30Minutes onceInUpdater
    56  
    57  	// OnceInHour allows you to get an actual time once in 60 minutes (1 hour).
    58  	OnceInHour onceInUpdater
    59  
    60  	// OnceIn2Hour allows you to get an actual time once in 120 minutes (2 hours).
    61  	OnceIn2Hour onceInUpdater
    62  
    63  	// OnceIn3Hour allows you to get an actual time once in 180 minutes (3 hours).
    64  	OnceIn3Hour onceInUpdater
    65  
    66  	// OnceIn6Hour allows you to get an actual time once in 1440 minutes (6 hours).
    67  	OnceIn6Hour onceInUpdater
    68  
    69  	// OnceIn12Hours allows you to get an actual time once in 12 hours.
    70  	OnceIn12Hours onceInUpdater
    71  
    72  	// OnceInDay allows you to get an actual time once in 24 hours (1 day).
    73  	OnceInDay onceInUpdater
    74  )
    75  
    76  // Now returns the cached unix Timestamp from the current onceInUpdater that caches
    77  // the current Timestamp once in the specified period.
    78  func (oiu *onceInUpdater) Now() Timestamp {
    79  	return Timestamp(atomic.LoadInt64((*int64)(&oiu.ts)))
    80  }
    81  
    82  // Date returns the cached Date from the current onceInUpdater that caches
    83  // the current Date once in the specified period.
    84  func (oiu *onceInUpdater) Date() Date {
    85  	return Date(atomic.LoadUint32((*uint32)(&oiu.d)))
    86  }
    87  
    88  // Time returns the cached Time from the current onceInUpdater that caches
    89  // the current Time once in the specified period.
    90  func (oiu *onceInUpdater) Time() Time {
    91  	return Time(atomic.LoadUint32((*uint32)(&oiu.t)))
    92  }
    93  
    94  // Call calls cb every time when associated onceIn updater's time has come.
    95  // So, it means that
    96  //
    97  //	ekatime.OnceInHour.Call(func(ts Timestamp){
    98  //	    fmt.Println(ts)
    99  //	})
   100  //
   101  // will call provided callback every hour, printing the UNIX timestamp of the time
   102  // when that hour has come.
   103  //
   104  // Does nothing if you pass a nil cb.
   105  // That callback will be rejected with no-op.
   106  //
   107  // WARNING!
   108  // IMPOSSIBLE TO STOP! YOU CANNOT "CANCEL" A CALLBACK YOU ONCE ADDED TO PLANNER.
   109  // It will be called every time until the end. If you need to stop, handle it manually!
   110  //
   111  // WARNING!
   112  // ONE THREAD! ALL CALLBACKS SHARES THE SAME WORKER GOROUTINE.
   113  // So, if there is some "big" work, wrap your callback manually to the closure with
   114  // "go callback(ts, dd, t)" call (spawn a separate goroutine).
   115  func (oiu *onceInUpdater) Call(invokeNow bool, cb OnceInCallback, panicCb ...OnceInPanicCallback) {
   116  	if cb != nil {
   117  		cbNum := atomic.AddUint32(&oiu.cbNum, 1) - 1
   118  		onceInRegister(cb, panicCb, oiu.repeatDelay, 1, invokeNow, true, cbNum)
   119  	}
   120  }
   121  
   122  // After is the same as Call() but calls cb after dur is passed.
   123  //
   124  // Does nothing if dur >= OnceIn's delayer time.
   125  // It means, you cannot delay up to 1h function execution using OnceInHour.
   126  func (oiu *onceInUpdater) After(delayInSec Timestamp, invokeNow bool, cb OnceInCallback, panicCb ...OnceInPanicCallback) {
   127  
   128  	if delayInSec < 1 {
   129  		delayInSec = 1
   130  	}
   131  
   132  	if cb != nil && delayInSec < oiu.repeatDelay {
   133  		cbNum := atomic.AddUint32(&oiu.cbNum, 1) - 1
   134  		onceInRegister(cb, panicCb, oiu.repeatDelay, delayInSec, invokeNow, true, cbNum)
   135  	}
   136  }