wp-go/app/cmd/reload/reload.go
2023-05-04 20:36:17 +08:00

184 lines
3.4 KiB
Go

package reload
import (
"github.com/fthvgb1/wp-go/helper/number"
"github.com/fthvgb1/wp-go/safety"
"sync"
)
var calls []func()
var anyMap = safety.NewMap[string, any]()
type safetyVar[T, A any] struct {
Val *safety.Var[val[T]]
mutex sync.Mutex
}
type val[T any] struct {
v T
ok bool
counter number.Counter[int]
}
type safetyMap[K comparable, V, A any] struct {
val *safety.Map[K, V]
mutex sync.Mutex
}
var safetyMaps = safety.NewMap[string, any]()
var safetyMapLock = sync.Mutex{}
func GetAnyMapFnBys[K comparable, V, A any](namespace string, fn func(A) V) func(key K, args A) V {
m := safetyMapFn[K, V, A](namespace)
return func(key K, a A) V {
v, ok := m.val.Load(key)
if ok {
return v
}
m.mutex.Lock()
v, ok = m.val.Load(key)
if ok {
m.mutex.Unlock()
return v
}
v = fn(a)
m.val.Store(key, v)
m.mutex.Unlock()
return v
}
}
func safetyMapFn[K comparable, V, A any](namespace string) *safetyMap[K, V, A] {
vv, ok := safetyMaps.Load(namespace)
var m *safetyMap[K, V, A]
if ok {
m = vv.(*safetyMap[K, V, A])
} else {
safetyMapLock.Lock()
vv, ok = safetyMaps.Load(namespace)
if ok {
m = vv.(*safetyMap[K, V, A])
} else {
m = &safetyMap[K, V, A]{safety.NewMap[K, V](), sync.Mutex{}}
Push(func() {
m.val.Flush()
})
safetyMaps.Store(namespace, m)
}
safetyMapLock.Unlock()
}
return m
}
func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn func(A) V) V {
m := safetyMapFn[K, V, A](namespace)
v, ok := m.val.Load(key)
if ok {
return v
}
m.mutex.Lock()
v, ok = m.val.Load(key)
if ok {
m.mutex.Unlock()
return v
}
v = fn(a)
m.val.Store(key, v)
m.mutex.Unlock()
return v
}
func anyVal[T, A any](namespace string, counter bool) *safetyVar[T, A] {
var vv *safetyVar[T, A]
vvv, ok := safetyMaps.Load(namespace)
if ok {
vv = vvv.(*safetyVar[T, A])
} else {
safetyMapLock.Lock()
vvv, ok = safetyMaps.Load(namespace)
if ok {
vv = vvv.(*safetyVar[T, A])
} else {
v := val[T]{}
if counter {
v.counter = number.Counters[int]()
}
vv = &safetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
Push(func() {
vv.Val.Flush()
})
safetyMaps.Store(namespace, vv)
}
safetyMapLock.Unlock()
}
return vv
}
func GetAnyValBy[T, A any](namespace string, tryTimes int, a A, fn func(A) (T, bool)) T {
var vv = anyVal[T, A](namespace, true)
var ok bool
v := vv.Val.Load()
if v.ok {
return v.v
}
vv.mutex.Lock()
v = vv.Val.Load()
if v.ok {
vv.mutex.Unlock()
return v.v
}
v.v, ok = fn(a)
times := v.counter()
if ok || times >= tryTimes {
v.ok = true
vv.Val.Store(v)
}
vv.mutex.Unlock()
return v.v
}
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) T) T {
var vv = anyVal[T, A](namespace, false)
v := vv.Val.Load()
if v.ok {
return v.v
}
vv.mutex.Lock()
v = vv.Val.Load()
if v.ok {
vv.mutex.Unlock()
return v.v
}
v.v = fn(a)
v.ok = true
vv.Val.Store(v)
vv.mutex.Unlock()
return v.v
}
func Vars[T any](defaults T) *safety.Var[T] {
ss := safety.NewVar(defaults)
calls = append(calls, func() {
ss.Store(defaults)
})
return ss
}
func VarsBy[T any](fn func() T) *safety.Var[T] {
ss := safety.NewVar(fn())
calls = append(calls, func() {
ss.Store(fn())
})
return ss
}
func Push(fn ...func()) {
calls = append(calls, fn...)
}
func Reload() {
for _, call := range calls {
call()
}
anyMap.Flush()
safetyMaps.Flush()
}