parent
3d9cae23e7
commit
7669987b25
@ -0,0 +1,75 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 contexts
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Cancel struct {
|
||||
active uint32
|
||||
doneCh chan struct{}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewCancel() *Cancel {
|
||||
return &Cancel{
|
||||
active: 1,
|
||||
doneCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cancel) Cancel() {
|
||||
if atomic.CompareAndSwapUint32(&c.active,1,0) {
|
||||
close(c.doneCh)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (c *Cancel) Done() <-chan struct{} {
|
||||
return c.doneCh }
|
||||
|
||||
|
||||
func (c *Cancel) IsDone() bool {
|
||||
return atomic.LoadUint32(&c.active) == 1 }
|
||||
|
||||
|
||||
func (c *Cancel) Wait() {
|
||||
<-c.doneCh }
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
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 times
|
||||
|
||||
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 times
|
||||
|
||||
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,82 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 times
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
DurationFormatter interface {
|
||||
|
||||
FormatDuration (dur time.Duration, dst []byte) []byte
|
||||
}
|
||||
|
||||
|
||||
FormatDurationFnc func (dur time.Duration, dst []byte) []byte
|
||||
|
||||
)
|
||||
|
||||
|
||||
func (f FormatDurationFnc) FormatDuration (dur time.Duration, dst []byte) []byte { return f(dur,dst) }
|
||||
|
||||
func WrapDurationFormatterQuoted (dfm DurationFormatter, qte byte) DurationFormatter {
|
||||
return FormatDurationFnc(func(tme time.Duration, dst []byte) []byte {
|
||||
dst = append(dst, qte)
|
||||
dst = dfm.FormatDuration(tme, dst)
|
||||
return append(dst, qte)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func DurationMillis (dur time.Duration, dst []byte) []byte {
|
||||
return strconv.AppendFloat(dst, float64(dur)/float64(time.Millisecond), 'f', -1, 64)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func DurationNanos(dur time.Duration, dst []byte) []byte {
|
||||
return strconv.AppendInt(dst, int64(dur), 10) }
|
||||
|
||||
|
||||
|
||||
func DurationSecs(dur time.Duration, dst []byte) []byte {
|
||||
return strconv.AppendFloat(dst, float64(dur)/float64(time.Second), 'f', -1, 64) }
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
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 times
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Expiration struct {
|
||||
timer *time.Timer
|
||||
times Chrono
|
||||
|
||||
state uint32
|
||||
source uint32
|
||||
timeout int64
|
||||
deadline int64
|
||||
|
||||
expireFn func()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewExpiration(tmo time.Duration, fnc func()) *Expiration {
|
||||
ex := &Expiration{
|
||||
times: *NewChrono(false),
|
||||
state: uint32(TimerStateCreated),
|
||||
source: uint32(ExpirationSourceSelf),
|
||||
timeout: int64(tmo),
|
||||
expireFn: fnc,
|
||||
}
|
||||
if tmo > 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(exp 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 exp != nil {
|
||||
pd, ph := exp.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 times
|
||||
|
||||
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 times
|
||||
|
||||
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 activething.com/go/gogog/core/times
|
||||
|
||||
|
||||
go 1.20
|
||||
@ -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 times
|
||||
|
||||
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,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 times
|
||||
|
||||
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() 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(); 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,149 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 times
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimeFormatter interface {
|
||||
|
||||
FormatTime (tme time.Time, dst []byte) []byte
|
||||
}
|
||||
|
||||
|
||||
FormatTimeFnc func (tme time.Time, dst []byte) []byte
|
||||
|
||||
)
|
||||
|
||||
|
||||
func (f FormatTimeFnc) FormatTime (tme time.Time, dst []byte) []byte { return f(tme,dst) }
|
||||
|
||||
|
||||
|
||||
|
||||
func WrapTimeFormatterQuoted (tmf TimeFormatter, qte byte) TimeFormatter {
|
||||
return FormatTimeFnc(func(tme time.Time, dst []byte) []byte {
|
||||
dst = append(dst, qte)
|
||||
dst = tmf.FormatTime(tme, dst)
|
||||
return append(dst, qte)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func TimeRFC3339Nano(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC3339Nano)
|
||||
}
|
||||
|
||||
|
||||
func TimeANSIC(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.ANSIC)
|
||||
}
|
||||
|
||||
|
||||
func TimeUnixDate(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.UnixDate)
|
||||
}
|
||||
|
||||
|
||||
func TimeRubyDate(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RubyDate)
|
||||
}
|
||||
|
||||
|
||||
func TimeRFC822(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC822)
|
||||
}
|
||||
|
||||
|
||||
func TimeRFC822Z(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC822Z) }
|
||||
|
||||
|
||||
func TimeRFC850(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC850) }
|
||||
|
||||
|
||||
func TimeRFC1123(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC1123) }
|
||||
|
||||
|
||||
func TimeRFC1123Z(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC1123Z) }
|
||||
|
||||
|
||||
func TimeRFC3339(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.RFC3339) }
|
||||
|
||||
|
||||
func TimeKitchen(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.Kitchen) }
|
||||
|
||||
|
||||
func TimeISO8601(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, "2006-01-02T15:04:05.000Z0700") }
|
||||
|
||||
|
||||
|
||||
func TimeEpoch(tme time.Time, dst []byte) []byte {
|
||||
return strconv.AppendFloat(dst, float64(tme.UnixNano())/float64(time.Second), 'f', -1, 64) }
|
||||
|
||||
|
||||
func TimeEpochMillis(tme time.Time, dst []byte) []byte {
|
||||
return strconv.AppendFloat(dst, float64(tme.UnixNano())/float64(time.Millisecond), 'f', -1, 64) }
|
||||
|
||||
|
||||
func TimeStamp(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.Stamp) }
|
||||
|
||||
|
||||
func TimeStampMilli(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.StampMilli) }
|
||||
|
||||
|
||||
func TimeStampMicro(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.StampMicro) }
|
||||
|
||||
|
||||
func TimeStampNano(tme time.Time, dst []byte) []byte {
|
||||
return tme.AppendFormat(dst, time.StampNano) }
|
||||
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
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 times
|
||||
|
||||
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)
|
||||
}
|
||||
}(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(rat time.Time, fnc TimeTaskFnc) error {
|
||||
switch {
|
||||
case rat.Before(time.Now()):
|
||||
return G.ErrExpired
|
||||
case fnc == nil:
|
||||
return G.ErrTimerTaskInvalid
|
||||
case TimerState(atomic.LoadUint32(&q.state)) != TimerStateStarted:
|
||||
return G.ErrNotStarted
|
||||
default:
|
||||
select {
|
||||
case q.pushCh <- NewTimerTask(rat, fnc):
|
||||
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 times
|
||||
|
||||
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 times
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TimerTask struct {
|
||||
|
||||
RunAt time.Time
|
||||
TaskFn TimeTaskFnc
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewTimerTask(time time.Time, task TimeTaskFnc) *TimerTask {
|
||||
return &TimerTask{
|
||||
RunAt: time,
|
||||
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,86 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 times
|
||||
|
||||
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) 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] }
|
||||
|
||||
|
||||
func (h *TimerTaskHeap) Push(ele interface{}) {
|
||||
h.PushTimerTask(ele.(*TimerTask)) }
|
||||
|
||||
|
||||
func (h *TimerTaskHeap) Pop() interface{} {
|
||||
return h.PopTimerTask() }
|
||||
|
||||
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA.
|
||||
"LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS.
|
||||
|
||||
SIDDHARTA
|
||||
- HERMANN HESSE -
|
||||
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
*/
|
||||
@ -1,44 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name matcher_builder.go
|
||||
// Created by DEV
|
||||
// Modified 17/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 matches
|
||||
|
||||
|
||||
type (
|
||||
|
||||
|
||||
MatcherBuilder interface {
|
||||
BuildMatcher (value []byte) (Matcher,error)
|
||||
}
|
||||
|
||||
|
||||
BuildMatcherFnc func (value []byte)(Matcher, error)
|
||||
|
||||
)
|
||||
|
||||
|
||||
func (f BuildMatcherFnc) BuildMatcher (value []byte) (Matcher,error) {
|
||||
return f(value) }
|
||||
|
||||
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name token_builder.go
|
||||
// Created by DEV
|
||||
// Modified 18/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 tokens
|
||||
|
||||
|
||||
@ -0,0 +1,185 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name token_builder.go
|
||||
// Created by DEV
|
||||
// Modified 18/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 tokens
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/opts"
|
||||
"activething.com/go/gogo/sapis/matches"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
Tokenizer struct {
|
||||
TokenizerOptions
|
||||
matcher matches.Builder
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
func NewTokenizer(options ...opts.OptionFnc[TokenizerOptions]) *Tokenizer {
|
||||
return &Tokenizer{
|
||||
TokenizerOptions: *NewBuilderOptions(options...),
|
||||
matcher : *matches.NewBuilder(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (b *Tokenizer) Tokenize (topic []byte, allows TokenKind)([]Token,TokenKind) {
|
||||
ln := len(topic)
|
||||
if ln < b.TopicMinLen || ln > b.TopicMaxLen {
|
||||
return []Token{*(NewInvalidToken(G.ErrInvalidTopicLen,topic))},TokenKindInvalid
|
||||
}
|
||||
|
||||
ls := [topicMaxTokens]Token{}
|
||||
tt := TokenKindNone
|
||||
var m,c,x int
|
||||
|
||||
for i:=0; i<ln; i++ {
|
||||
switch topic[i] {
|
||||
case b.MatchIni: m++
|
||||
case b.MatchEnd: m--
|
||||
case b.Sep:
|
||||
if m != 0 {
|
||||
continue
|
||||
}
|
||||
if c >= b.MaxTokens {
|
||||
ls[c]=*(NewInvalidToken(G.ErrInvalidTopicLen,topic[x:]))
|
||||
return ls[:c+1],tt | TokenKindInvalid
|
||||
}
|
||||
ls[c] = b.MakeToken(topic[x:i])
|
||||
tk := ls[c].Kind()
|
||||
if tk == TokenKindRelative {
|
||||
ls[c] = *NewInvalidToken(G.ErrInvalidToken,topic[x:i])
|
||||
} else if tk&allows != 0 {
|
||||
tt |= TokenKindInvalid
|
||||
} else {
|
||||
tt |= ls[c].Kind()
|
||||
}
|
||||
x = i + 1
|
||||
c++
|
||||
}
|
||||
}
|
||||
|
||||
if m != 0 {
|
||||
ls[c] = *NewInvalidToken(G.ErrInvalidTopic,topic[x:])
|
||||
} else {
|
||||
ls[c] = b.MakeToken(topic[x:])
|
||||
}
|
||||
|
||||
return ls[:c+1], tt | ls[c].Kind()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (b *Tokenizer) MakeToken(source []byte) Token {
|
||||
ln := len(source)
|
||||
if ln < b.TokenMinLen || ln > b.TokenMaxLen {
|
||||
return *(NewInvalidToken(G.ErrInvalidTokenLen,source))
|
||||
}
|
||||
if ln == 1 {
|
||||
switch source[0] {
|
||||
case b.Wildcard: return WildcardToken{}
|
||||
case b.Relative: return RelativeToken{}
|
||||
case b.MatchIni,
|
||||
b.MatchEnd: return *(NewInvalidToken(G.ErrInvalidTokenLen,source))
|
||||
}
|
||||
}
|
||||
|
||||
if source[0] != b.MatchIni {
|
||||
return LiteralToken(source)
|
||||
}
|
||||
|
||||
if source[ln-1] != b.MatchEnd || ln > b.TokenMinLen+2 {
|
||||
m,e := b.matcher.BuildMatcher(source)
|
||||
if e != nil {
|
||||
return *NewInvalidToken(G.ErrInvalidMatcher.WithCause(e),source)
|
||||
}
|
||||
return *NewMatcherToken(m.Match,source)
|
||||
}
|
||||
|
||||
return *NewInvalidToken(G.ErrInvalidMatcher,source)
|
||||
}
|
||||
|
||||
|
||||
func (b *Tokenizer) Split (topic []byte, allows TokenKind) ([][]byte,TokenKind) {
|
||||
var ms, ps, x int
|
||||
var tk, pk TokenKind
|
||||
ln := len(topic)
|
||||
ar := [topicMaxTokens][]byte{}
|
||||
|
||||
for i := 0; i < ln; i++ {
|
||||
switch topic[i] {
|
||||
case b.MatchIni:
|
||||
ms++
|
||||
case b.MatchEnd:
|
||||
ms--
|
||||
case b.Sep:
|
||||
if ms == 0 {
|
||||
ar[ps] = topic[x:i]
|
||||
if pk = b.TokenKind(ar[ps]); pk&allows == 0 {
|
||||
return nil, TokenKindInvalid
|
||||
}
|
||||
tk |= pk
|
||||
x = i + 1
|
||||
ps++
|
||||
}
|
||||
}
|
||||
}
|
||||
ar[ps] = topic[x:]
|
||||
if pk = b.TokenKind(ar[ps]); pk&allows == 0 {
|
||||
return nil, TokenKindInvalid
|
||||
}
|
||||
tk |= pk
|
||||
|
||||
return ar[:ps+1], tk
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (b *Tokenizer) TokenKind(Token []byte) TokenKind {
|
||||
ln := len(Token)
|
||||
if ln < b.TokenMinLen || ln > b.TokenMaxLen {
|
||||
return TokenKindInvalid
|
||||
}
|
||||
|
||||
if ln == 1 {
|
||||
switch Token[0] {
|
||||
case b.Wildcard: return TokenKindWildcard
|
||||
case b.Relative: return TokenKindRelative
|
||||
case b.MatchIni,
|
||||
b.MatchEnd: return TokenKindInvalid
|
||||
}
|
||||
}
|
||||
|
||||
if Token[0] == b.MatchIni {
|
||||
if Token[ln-1] == b.MatchEnd {
|
||||
return TokenKindMatcher
|
||||
}
|
||||
return TokenKindInvalid
|
||||
}
|
||||
return TokenKindLiteral
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name topic.go
|
||||
// Created by DEV
|
||||
// Modified 18/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 tokens
|
||||
|
||||
|
||||
|
||||
type (
|
||||
|
||||
|
||||
Topic struct {
|
||||
|
||||
kind TokenKind
|
||||
|
||||
source []byte
|
||||
|
||||
tokens []Token
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewTopic(builder *Tokenizer, topic []byte, allows TokenKind) *Topic {
|
||||
tp := &Topic{ source: topic }
|
||||
tp.tokens, tp.kind = builder.Tokenize(topic, allows)
|
||||
return tp
|
||||
}
|
||||
|
||||
func (t Topic) Len() int {
|
||||
return len(t.tokens) }
|
||||
|
||||
|
||||
func (t Topic) Kind() TokenKind {
|
||||
return t.kind }
|
||||
|
||||
|
||||
func (t Topic) Source() []byte {
|
||||
return t.source }
|
||||
|
||||
|
||||
func (t Topic) Tokens() []Token {
|
||||
return t.tokens }
|
||||
|
||||
|
||||
func (t Topic) String() string {
|
||||
return string(t.source) }
|
||||
|
||||
|
||||
func (t Topic) Match(subject [][]byte) bool {
|
||||
if t.kind.HasInvalid() {
|
||||
return false
|
||||
}
|
||||
ln := len(t.tokens)
|
||||
ls := len(subject)
|
||||
|
||||
if ln != ls {
|
||||
if ln > ls {
|
||||
return false
|
||||
}
|
||||
if !t.kind.HasRelative() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < ln; i++ {
|
||||
if t.tokens[i].Kind()&TokenKindMatchable != 0 {
|
||||
if !t.tokens[i].Match(subject[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
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,111 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name topic_list.go
|
||||
// Created by DEV
|
||||
// Modified 18/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 tokens
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/slices"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
|
||||
TopicList []Topic
|
||||
)
|
||||
|
||||
|
||||
|
||||
func (s TopicList) Match(subject [][]byte) bool {
|
||||
for i, l := 0, len(subject); i < l; i++ {
|
||||
if s[i].Match(subject) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
func (s TopicList) Exists(topic []byte) int {
|
||||
ln := len(s)
|
||||
if ln > 0 {
|
||||
for i := 0; i < ln; i++ {
|
||||
if bytes.Equal(s[i].source, topic) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return slices.NotFound
|
||||
}
|
||||
|
||||
|
||||
func (s TopicList) Len() int {
|
||||
return len(s) }
|
||||
|
||||
|
||||
func (s TopicList) Less(i, j int) bool {
|
||||
li, lj := len(s[i].tokens), len(s[j].tokens)
|
||||
|
||||
if li < lj {
|
||||
return true
|
||||
}
|
||||
if lj < li {
|
||||
return false
|
||||
}
|
||||
|
||||
if s[i].kind.HasRelative() && !s[j].kind.HasRelative() {
|
||||
return true
|
||||
} else if s[j].kind.HasRelative() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Comparators token count
|
||||
ci, cj := 0, 0
|
||||
for x := 0; i < li; i++ {
|
||||
if s[i].tokens[x].Kind().HasMatchable() {
|
||||
ci++
|
||||
}
|
||||
if s[j].tokens[x].Kind().HasMatchable() {
|
||||
cj++
|
||||
}
|
||||
}
|
||||
return ci > cj
|
||||
|
||||
}
|
||||
|
||||
|
||||
func (s TopicList) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[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