代码拉取完成,页面将自动刷新
package system
import (
"context"
"errors"
"fmt"
"gitee.com/h79/goutils/common/option"
"os"
"os/signal"
"sync"
"sync/atomic"
"syscall"
"time"
)
var closeCh chan bool
var quited bool
var quitErr error
var quitCode int32
var ErrNormalQuit = errors.New("normal quit")
func init() {
var _ = closeCh
var _ = quited
closeCh = make(chan bool)
quited = false
}
type ExitSig struct {
S chan os.Signal
}
func (c *ExitSig) Done() <-chan os.Signal {
return c.S
}
func Exit() *ExitSig {
e := &ExitSig{S: make(chan os.Signal)}
signal.Notify(e.S, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGQUIT)
return e
}
func IsNormalQuit() bool {
return quited && (quitErr == nil || errors.Is(ErrNormalQuit, quitErr))
}
func IsQuit() bool {
return quited
}
func GetQuitCode() int32 {
return quitCode
}
func SetQuitCode(code int32) {
quitCode = code
}
func GetQuitErr() error {
return quitErr
}
func SetQuitErr(err error) {
quitErr = err
}
func QuitApp(code int32) {
if quited {
return
}
quited = true
quitCode = code
close(closeCh)
fmt.Println("quit program.")
}
func Close() {
QuitApp(-1)
}
func Closed() <-chan bool {
return closeCh
}
func AfterQuit(t time.Duration) {
Wait(t)
}
func Wait(t time.Duration) {
ti := time.NewTimer(t)
defer ti.Stop()
select {
case <-ti.C:
return
}
}
func Stop(d time.Duration, stop chan bool) {
go func() {
Wait(d)
ti := time.NewTimer(d * 2)
defer ti.Stop()
select {
case <-stop:
stop <- true
return
case <-ti.C:
return
}
}()
stop <- true
<-stop
}
type Running struct {
ev *Event
c int32
wg sync.WaitGroup
}
var (
mainIf int32 = 0
running *Running
once sync.Once
)
func Go() *Running {
once.Do(func() {
running = NewRunning()
})
return running
}
// NewRunning
// f 是否fire
func NewRunning() *Running {
return &Running{ev: NewEvent()}
}
func ChildRunning(fn func(), exits ...func()) {
Go().Run(false, fn, exits...)
}
func MainRunning(fn func(), exits ...func()) {
if atomic.AddInt32(&mainIf, 1) > 1 {
panic("can not repeat call,only call one")
}
Go().runM(fn, exits...)
}
// Run if fire=true, select Running.Done()
func (m *Running) Run(fire bool, fn func(), exits ...func()) {
if quited {
return
}
var c = atomic.AddInt32(&m.c, 1)
fmt.Println("enter child go coroutine,count: ", c)
m.wg.Add(1)
go func() {
defer m.done(true, fire)
defer Recover(exits...)
fn()
}()
}
func (m *Running) runM(fn func(), exits ...func()) {
if quited {
return
}
var c = atomic.AddInt32(&m.c, 1)
fmt.Println("enter main go coroutine,count: ", c)
m.wg.Add(1)
go func() {
defer m.done(false, true)
defer Recover(exits...)
defer Close()
defer atomic.StoreInt32(&mainIf, 0)
fn()
}()
}
func (m *Running) done(child, fire bool) {
var c = atomic.AddInt32(&m.c, -1)
fmt.Println("exit go coroutine, count: ", c, ",it is main coroutine: ", !child)
if fire {
m.ev.Fire()
}
m.wg.Done()
}
func (m *Running) Done() <-chan struct{} {
return m.ev.Done()
}
func (m *Running) Wait() {
m.wg.Wait()
}
func (m *Running) Count() int32 {
return atomic.LoadInt32(&m.c)
}
type RunningCheck struct {
rm sync.RWMutex
fRun bool
}
func (rc *RunningCheck) IsRunning() bool {
rc.rm.RLock()
defer rc.rm.RUnlock()
return rc.fRun
}
// Deprecated: this function simply calls [GoRunning].
func (rc *RunningCheck) TryGoRunning(fn func(), exits ...func()) {
rc.GoRunning(fn, exits...)
}
func (rc *RunningCheck) GoRunning(fn func(), exits ...func()) {
rc.GoRunningV2(func() {}, fn, exits...)
}
func (rc *RunningCheck) GoRunningV2(running func(), fn func(), exits ...func()) {
if rc.IsRunning() {
return
}
rc.runningSet(true)
running()
ChildRunning(func() {
defer rc.runningSet(false)
fn()
}, exits...)
}
func (rc *RunningCheck) runningSet(flag bool) {
rc.rm.Lock()
rc.fRun = flag
rc.rm.Unlock()
}
type Task func(opts ...option.Option) (any, error)
func RunAfter(timeout time.Duration, task Task, opts ...option.Option) (any, error) {
if timeout <= 0 {
return task(opts...)
}
resultCh := make(chan *resultWithError, 1)
ChildRunning(func() {
result, err := task(opts...)
resultCh <- &resultWithError{result, err}
})
ti := time.NewTimer(timeout)
defer ti.Stop()
select {
case <-ti.C:
return nil, TimeoutError
case rwe := <-resultCh:
return rwe.result, rwe.err
case <-Closed():
return nil, ClosedError
}
}
func RunWithContext(ctx context.Context, task Task) (any, error) {
resultCh := make(chan *resultWithError, 1)
ChildRunning(func() {
result, err := task()
resultCh <- &resultWithError{result, err}
})
select {
case <-ctx.Done():
return nil, ctx.Err()
case rwe := <-resultCh:
return rwe.result, rwe.err
case <-Closed():
return nil, ClosedError
}
}
// Ticker
// 定时调用
func Ticker(tick time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) {
Delay(0, tick, fun, param, funcDefer, paramDefer)
}
func DelayOnly(delay time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) {
Delay(delay, 0, fun, param, funcDefer, paramDefer)
}
func Delay(delay, tick time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) {
if fun == nil {
panic("fun is nil")
}
ChildRunning(func() {
pd := ParamDefer{P: paramDefer}
defer func() {
if funcDefer != nil {
funcDefer(pd)
}
}()
if delay > 0 {
Wait(delay)
}
if tick <= 0 {
fun(param)
pd.Reason = 2
return
}
if delay > 0 {
if fun(param) {
pd.Reason = 2
return
}
}
ticker := time.NewTicker(tick)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if fun(param) {
pd.Reason = 2
return
}
case <-Closed():
pd.Reason = 1
return
}
}
})
}
type resultWithError struct {
result any
err error
}
type ParamDefer struct {
P any
Reason int
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。