parent
a4f493855f
commit
17f2796511
@ -0,0 +1,71 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/errs"
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
var (
|
||||
|
||||
|
||||
G = struct {
|
||||
ErrExpired errs.ErrCode
|
||||
ErrTimeout errs.ErrCode
|
||||
ErrIntervalInvalid errs.ErrCode
|
||||
ErrNotStarted errs.ErrCode
|
||||
ErrNotPaused errs.ErrCode
|
||||
ErrAlreadyStarted errs.ErrCode
|
||||
ErrTransitionInvalid errs.ErrCode
|
||||
ErrTimerTaskInvalid errs.ErrCode
|
||||
} {
|
||||
|
||||
ErrExpired: errs.ErrCode("expired"),
|
||||
ErrTimeout: errs.ErrCode("timeout"),
|
||||
ErrIntervalInvalid: errs.ErrCode("interval_invalid"),
|
||||
ErrNotStarted: errs.ErrCode("not_started"),
|
||||
ErrNotPaused: errs.ErrCode("not_paused"),
|
||||
ErrAlreadyStarted: errs.ErrCode("already_started"),
|
||||
ErrTransitionInvalid:errs.ErrCode("transition_invalid"),
|
||||
ErrTimerTaskInvalid: errs.ErrCode("timer_task_invalid"),
|
||||
}
|
||||
|
||||
|
||||
)
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,108 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Chrono struct {
|
||||
started int64
|
||||
stopped int64
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewChrono(str bool) *Chrono {
|
||||
ch := &Chrono{}
|
||||
if str {
|
||||
ch.Start()
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
|
||||
func (c *Chrono) Started() time.Time {
|
||||
return time.Unix(0,atomic.LoadInt64(&c.started)) }
|
||||
|
||||
|
||||
func (c *Chrono) Stopped() time.Time {
|
||||
return time.Unix(0,atomic.LoadInt64(&c.stopped)) }
|
||||
|
||||
|
||||
func (c *Chrono) Elapsed() time.Duration {
|
||||
st := atomic.LoadInt64(&c.started)
|
||||
if st == 0 {
|
||||
return 0
|
||||
}
|
||||
sp := atomic.LoadInt64(&c.stopped)
|
||||
if sp == 0 {
|
||||
return time.Now().Sub(time.Unix(0, int64(st)))
|
||||
}
|
||||
return time.Duration(sp - st)
|
||||
}
|
||||
|
||||
|
||||
func (c *Chrono) Reset() {
|
||||
atomic.StoreInt64(&c.started,0)
|
||||
atomic.StoreInt64(&c.stopped,0)
|
||||
}
|
||||
|
||||
|
||||
func (c *Chrono) Start() (tm time.Time) {
|
||||
tm = time.Now()
|
||||
atomic.CompareAndSwapInt64(&c.started,0,tm.UnixNano())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (c *Chrono) Stop() (tm time.Time) {
|
||||
tm = time.Now()
|
||||
atomic.CompareAndSwapInt64(&c.stopped,0,tm.UnixNano())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (c *Chrono) SetTimes(str, stp time.Time) {
|
||||
atomic.StoreInt64(&c.started,str.UnixNano())
|
||||
atomic.StoreInt64(&c.stopped,str.UnixNano())
|
||||
}
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,59 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Chronometer interface {
|
||||
|
||||
Started() time.Time
|
||||
|
||||
Stopped() time.Time
|
||||
|
||||
Elapsed() time.Duration
|
||||
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,182 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Expiration struct {
|
||||
timer *time.Timer
|
||||
times Chrono
|
||||
|
||||
state uint32
|
||||
source uint32
|
||||
timeout int64
|
||||
deadline int64
|
||||
|
||||
expireFn func()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewExpiration(duration time.Duration, expirer func()) *Expiration {
|
||||
ex := &Expiration{
|
||||
times: *NewChrono(false),
|
||||
state: uint32(TimerStateCreated),
|
||||
source: uint32(ExpirationSourceSelf),
|
||||
timeout: int64(duration),
|
||||
expireFn: expirer,
|
||||
}
|
||||
if duration > 0 {
|
||||
atomic.StoreUint32(&ex.source,uint32(ExpirationSourceTimer))
|
||||
}
|
||||
return ex
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (e *Expiration) Reset() {
|
||||
e.times.Reset()
|
||||
atomic.StoreUint32(&e.state ,uint32(TimerStateCreated))
|
||||
atomic.StoreUint32(&e.source,uint32(ExpirationSourceSelf))
|
||||
atomic.StoreInt64 (&e.timeout ,0)
|
||||
atomic.StoreInt64 (&e.deadline,0)
|
||||
if e.timer != nil {
|
||||
if !e.timer.Stop() {
|
||||
select {
|
||||
case <- e.timer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (e *Expiration) State() TimerState {
|
||||
return TimerState(atomic.LoadUint32(&e.state)) }
|
||||
|
||||
|
||||
|
||||
func (e *Expiration) Chono() Chronometer {
|
||||
return &e.times }
|
||||
|
||||
|
||||
func (e *Expiration) Source() ExpirationSource {
|
||||
return ExpirationSource(atomic.LoadUint32(&e.source)) }
|
||||
|
||||
|
||||
|
||||
func (e *Expiration) Timeout() time.Duration {
|
||||
return time.Duration(atomic.LoadInt64(&e.timeout)) }
|
||||
|
||||
|
||||
func (e *Expiration) Deadline() time.Time {
|
||||
return time.Unix(0,atomic.LoadInt64(&e.deadline)) }
|
||||
|
||||
|
||||
|
||||
func (e *Expiration) Start(expirer Expirer) error {
|
||||
if !atomic.CompareAndSwapUint32(&e.state,uint32(TimerStateCreated),uint32(TimerStateStarted)) {
|
||||
return G.ErrAlreadyStarted
|
||||
}
|
||||
|
||||
st := e.times.Start()
|
||||
to := time.Duration(atomic.LoadInt64(&e.timeout))
|
||||
dl := st.Add(to)
|
||||
|
||||
if expirer != nil {
|
||||
pd, ph := expirer.Deadline()
|
||||
if ph {
|
||||
if pd.Before(st) {
|
||||
atomic.StoreUint32(&e.state ,uint32(TimerStateExpired))
|
||||
atomic.StoreUint32(&e.source,uint32(ExpirationSourceParent))
|
||||
return G.ErrExpired
|
||||
}
|
||||
if pd.Before(dl) {
|
||||
atomic.StoreInt64 (&e.deadline,pd.UnixNano())
|
||||
atomic.StoreUint32(&e.source ,uint32(ExpirationSourceParent))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if atomic.LoadUint32(&e.source) == uint32(ExpirationSourceTimer) {
|
||||
atomic.StoreInt64 (&e.deadline,dl.UnixNano())
|
||||
if e.timer == nil {
|
||||
e.timer = time.NewTimer(to)
|
||||
} else {
|
||||
e.timer.Reset(to)
|
||||
}
|
||||
go func(ex *Expiration) {
|
||||
select {
|
||||
case <-ex.timer.C:
|
||||
atomic.StoreUint32(&ex.state,uint32(TimerStateExpired))
|
||||
ex.times.Stop()
|
||||
if ex.expireFn != nil {
|
||||
ex.expireFn()
|
||||
}
|
||||
return
|
||||
}
|
||||
}(e)
|
||||
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (e *Expiration) Stop() error {
|
||||
if !atomic.CompareAndSwapUint32(&e.state,uint32(TimerStateStarted), uint32(TimerStateStopped)) {
|
||||
return G.ErrNotStarted
|
||||
}
|
||||
e.times.Stop()
|
||||
if e.timer != nil && !e.timer.Stop() {
|
||||
select {
|
||||
case <-e.timer.C:
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,62 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
const (
|
||||
|
||||
//ExpirationSource
|
||||
|
||||
ExpirationSourceSelf ExpirationSource = iota
|
||||
ExpirationSourceParent
|
||||
ExpirationSourceTimer
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
ExpirationSource uint32
|
||||
)
|
||||
|
||||
|
||||
func (c ExpirationSource) String() string {
|
||||
switch c {
|
||||
case ExpirationSourceSelf : return "self"
|
||||
case ExpirationSourceParent : return "parent"
|
||||
case ExpirationSourceTimer : return "timer"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,57 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Expirer interface {
|
||||
|
||||
Deadline() (time.Time, bool)
|
||||
}
|
||||
|
||||
|
||||
DeadlineFnc func() (time.Time, bool)
|
||||
)
|
||||
|
||||
|
||||
func (f DeadlineFnc) Deadline() (time.Time, bool) {
|
||||
return f() }
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,4 @@
|
||||
module timers
|
||||
|
||||
|
||||
go 1.20
|
||||
@ -0,0 +1,174 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/contexts"
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Pulsar struct {
|
||||
state uint32
|
||||
pulse int64
|
||||
err atomic.Value
|
||||
cancel contexts.Cancel
|
||||
workFn PulsarWorkFnc
|
||||
}
|
||||
|
||||
|
||||
PulsarWorkFnc func(ctx context.Context) error
|
||||
|
||||
)
|
||||
|
||||
|
||||
func NewPulsar(pulse time.Duration, work PulsarWorkFnc) *Pulsar {
|
||||
return &Pulsar{
|
||||
state: uint32(TimerStateCreated),
|
||||
cancel: *contexts.NewCancel(),
|
||||
pulse: int64(pulse),
|
||||
workFn: work,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (p *Pulsar) State() TimerState {
|
||||
return TimerState(atomic.LoadUint32(&p.state)) }
|
||||
|
||||
|
||||
func (p *Pulsar) Pulse() time.Duration {
|
||||
return time.Duration(atomic.LoadInt64(&p.pulse)) }
|
||||
|
||||
|
||||
func (p *Pulsar) Err() error {
|
||||
if v := p.err.Load(); v != nil {
|
||||
return v.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (p *Pulsar) Start(ctx context.Context) error {
|
||||
if !atomic.CompareAndSwapUint32(&p.state,uint32(TimerStateCreated),uint32(TimerStateStarted)) {
|
||||
return G.ErrAlreadyStarted
|
||||
}
|
||||
to := atomic.LoadInt64(&p.pulse)
|
||||
if to <= 0 {
|
||||
atomic.StoreUint32(&p.state,uint32(TimerStateExpired))
|
||||
return G.ErrIntervalInvalid
|
||||
}
|
||||
|
||||
cx := ctx
|
||||
if cx == nil {
|
||||
cx = context.Background()
|
||||
} else if ctx.Err() != nil {
|
||||
atomic.StoreUint32(&p.state,uint32(TimerStateCanceled))
|
||||
return context.Canceled
|
||||
}
|
||||
|
||||
go func(pl *Pulsar, tk *time.Ticker, cx context.Context) {
|
||||
EXIT:
|
||||
for {
|
||||
select {
|
||||
case <-cx.Done():
|
||||
atomic.StoreUint32(&pl.state,uint32(TimerStateCanceled))
|
||||
break EXIT
|
||||
|
||||
case <-pl.cancel.Done():
|
||||
break EXIT
|
||||
|
||||
case <-tk.C:
|
||||
if TimerState(atomic.LoadUint32(&pl.state)) == TimerStateStarted {
|
||||
if er := pl.workFn(cx); er != nil {
|
||||
pl.err.Store(er)
|
||||
atomic.StoreUint32(&pl.state,uint32(TimerStateCanceled))
|
||||
break EXIT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tk.Stop()
|
||||
pl.cancel.Cancel()
|
||||
|
||||
}(p, time.NewTicker(time.Duration(to)), cx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (p *Pulsar) Stop() error {
|
||||
if atomic.CompareAndSwapUint32(&p.state,uint32(TimerStateStarted), uint32(TimerStateStopped)) ||
|
||||
atomic.CompareAndSwapUint32(&p.state,uint32(TimerStatePaused), uint32(TimerStateStopped)) {
|
||||
p.cancel.Cancel()
|
||||
return nil
|
||||
}
|
||||
return G.ErrNotStarted
|
||||
}
|
||||
|
||||
|
||||
func (p *Pulsar) Pause() error {
|
||||
if atomic.CompareAndSwapUint32(&p.state,uint32(TimerStateStarted), uint32(TimerStatePaused)) {
|
||||
return nil
|
||||
}
|
||||
return G.ErrNotStarted
|
||||
}
|
||||
|
||||
|
||||
func (p *Pulsar) Continue() error {
|
||||
if atomic.CompareAndSwapUint32(&p.state,uint32(TimerStatePaused), uint32(TimerStateStarted)) {
|
||||
return nil
|
||||
}
|
||||
return G.ErrNotPaused
|
||||
}
|
||||
|
||||
|
||||
func (p *Pulsar) Done() <-chan struct{} {
|
||||
return p.cancel.Done() }
|
||||
|
||||
|
||||
func (p *Pulsar) Wait() {
|
||||
<-p.cancel.Done() }
|
||||
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,48 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimeTaskFnc func(now time.Time, ctx context.Context)
|
||||
)
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,190 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/opts"
|
||||
"container/heap"
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
||||
)
|
||||
|
||||
const (
|
||||
timerQueueLen = 4096
|
||||
timerQueueTime = time.Hour * 86400
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimerQueue struct {
|
||||
heap TimerTaskHeap
|
||||
state uint32
|
||||
|
||||
pushCh chan *TimerTask
|
||||
ctx context.Context
|
||||
ctxCancelFn context.CancelFunc
|
||||
|
||||
nextTask *time.Time
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
|
||||
)
|
||||
|
||||
|
||||
func NewTimerQueue(options ... opts.OptionFnc[TimerQueue]) *TimerQueue {
|
||||
tq := &TimerQueue{
|
||||
heap : TimerTaskHeap{},
|
||||
state: uint32(TimerStateCreated),
|
||||
}
|
||||
heap.Init(&tq.heap)
|
||||
opts.Apply(tq, options ...)
|
||||
if tq.pushCh == nil {
|
||||
tq.pushCh = make(chan *TimerTask, timerQueueLen)
|
||||
}
|
||||
return tq
|
||||
}
|
||||
|
||||
|
||||
func (q *TimerQueue) State() TimerState {
|
||||
return TimerState(atomic.LoadUint32(&q.state)) }
|
||||
|
||||
|
||||
func (q *TimerQueue) Start(ctx context.Context) error {
|
||||
if !atomic.CompareAndSwapUint32(&q.state,uint32(TimerStateCreated),uint32(TimerStateStarted)) {
|
||||
// error already started
|
||||
return G.ErrAlreadyStarted
|
||||
}
|
||||
if q.timer == nil {
|
||||
q.timer = time.NewTimer(timerQueueTime)
|
||||
} else {
|
||||
q.timer.Reset(timerQueueTime)
|
||||
}
|
||||
|
||||
q.ctx, q.ctxCancelFn = context.WithCancel(ctx)
|
||||
go func(qu *TimerQueue, cx context.Context) {
|
||||
ts := make([]*TimerTask, 0, 10)
|
||||
EXIT:
|
||||
for {
|
||||
select {
|
||||
//--
|
||||
case <-cx.Done():
|
||||
atomic.CompareAndSwapUint32(&qu.state,uint32(TimerStateStarted),uint32(TimerStateCanceled))
|
||||
break EXIT
|
||||
//--
|
||||
case nw := <-qu.timer.C:
|
||||
ts = ts[:0]
|
||||
for ix, ln := 0, qu.heap.Len(); ix < ln; ix++ {
|
||||
pk := qu.heap[0]
|
||||
if pk.RunAt.Before(nw) {
|
||||
pp := heap.Pop(&qu.heap).(*TimerTask)
|
||||
ts = append(ts, pp)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if len(ts) > 0 {
|
||||
go func(tm time.Time, tk []*TimerTask) {
|
||||
for _, tt := range tk {
|
||||
tt.TaskFn(tm, ctx)
|
||||
}
|
||||
}(nw, ts)
|
||||
}
|
||||
|
||||
if qu.heap.Len() > 0 {
|
||||
nr := qu.heap[0].RunAt
|
||||
qu.nextTask = &nr
|
||||
qu.timer.Reset(nr.Sub(time.Now()))
|
||||
} else {
|
||||
qu.timer.Stop()
|
||||
qu.nextTask = nil
|
||||
}
|
||||
//--
|
||||
case tt := <-q.pushCh:
|
||||
heap.Push(&q.heap, tt)
|
||||
if qu.nextTask == nil || qu.nextTask.After(tt.RunAt) {
|
||||
if qu.nextTask != nil && !qu.timer.Stop() {
|
||||
<-qu.timer.C
|
||||
}
|
||||
qu.timer.Reset(tt.RunAt.Sub(time.Now()))
|
||||
qu.nextTask = &tt.RunAt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !q.timer.Stop() {
|
||||
<-qu.timer.C
|
||||
}
|
||||
qu.heap.Reset()
|
||||
|
||||
}(q, q.ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (q *TimerQueue) Stop() error {
|
||||
if atomic.CompareAndSwapUint32(&q.state,uint32(TimerStateStarted),uint32(TimerStateCanceled)) {
|
||||
q.ctxCancelFn()
|
||||
return nil
|
||||
}
|
||||
return G.ErrNotStarted
|
||||
}
|
||||
|
||||
|
||||
func (q *TimerQueue) Push(runAt time.Time, task TimeTaskFnc) error {
|
||||
switch {
|
||||
case runAt.Before(time.Now()):
|
||||
return G.ErrExpired
|
||||
case task == nil:
|
||||
return G.ErrTimerTaskInvalid
|
||||
case TimerState(atomic.LoadUint32(&q.state)) != TimerStateStarted:
|
||||
return G.ErrNotStarted
|
||||
default:
|
||||
select {
|
||||
case q.pushCh <- NewTimerTask(runAt, task):
|
||||
return nil
|
||||
case <-q.ctx.Done():
|
||||
return context.Canceled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,81 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
const (
|
||||
|
||||
//Enum values for TimerState
|
||||
TimerStateCreated TimerState = 1 << iota
|
||||
TimerStateStarted
|
||||
TimerStatePaused
|
||||
TimerStateExpired
|
||||
TimerStateStopped
|
||||
TimerStateCanceled
|
||||
|
||||
timerStateActive = TimerStateStarted + TimerStatePaused
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimerState uint32
|
||||
)
|
||||
|
||||
|
||||
|
||||
func (t TimerState) String() string {
|
||||
switch t {
|
||||
case TimerStateCreated:
|
||||
return "created"
|
||||
case TimerStateStarted:
|
||||
return "started"
|
||||
case TimerStatePaused:
|
||||
return "paused"
|
||||
case TimerStateExpired:
|
||||
return "expired"
|
||||
case TimerStateStopped:
|
||||
return "stopped"
|
||||
case TimerStateCanceled:
|
||||
return "canceled"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (t TimerState) IsActive() bool {
|
||||
return t != timerStateActive }
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,60 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
package timers
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimerTask struct {
|
||||
|
||||
RunAt time.Time
|
||||
TaskFn TimeTaskFnc
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewTimerTask(runAt time.Time, task TimeTaskFnc) *TimerTask {
|
||||
return &TimerTask{
|
||||
RunAt: runAt,
|
||||
TaskFn: task,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -0,0 +1,89 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 05/02/2024
|
||||
//
|
||||
// Copyright 2024 activething.com
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package timers
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimerTaskHeap []*TimerTask
|
||||
)
|
||||
|
||||
|
||||
func (h *TimerTaskHeap) Reset() {
|
||||
*h = (*h)[:0] }
|
||||
|
||||
|
||||
func (h *TimerTaskHeap) PushTimerTask(ele *TimerTask) {
|
||||
if ele != nil {
|
||||
*h = append(*h, ele)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TimerTaskHeap) PopTimerTask() *TimerTask {
|
||||
th := *h
|
||||
if ln := len(th); ln > 0 {
|
||||
tt := th[ln-1]
|
||||
*h = th[:ln-1]
|
||||
return tt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (h *TimerTaskHeap) Push(ele interface{}) {
|
||||
h.PushTimerTask(ele.(*TimerTask)) }
|
||||
|
||||
|
||||
func (h *TimerTaskHeap) Pop() interface{} {
|
||||
return h.PopTimerTask() }
|
||||
|
||||
|
||||
func (h TimerTaskHeap) Len() int {
|
||||
return len(h) }
|
||||
|
||||
|
||||
func (h TimerTaskHeap) Less(i, j int) bool {
|
||||
return h[i].RunAt.Before(h[j].RunAt) }
|
||||
|
||||
|
||||
func (h TimerTaskHeap) Swap(i, j int) {
|
||||
h[i], h[j] = h[j], h[i] }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
Loading…
Reference in new issue