Compare commits
No commits in common. "137b2a9738c481a14a9e0d6b9f71c977c18ff306" and "547d8e59e6905c38516bb71c95329b762462d50c" have entirely different histories.
137b2a9738
...
547d8e59e6
13
app/pkg/cache/cache.go
vendored
13
app/pkg/cache/cache.go
vendored
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/dao"
|
"github.com/fthvgb1/wp-go/app/pkg/dao"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/logs"
|
"github.com/fthvgb1/wp-go/app/pkg/logs"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/cache"
|
|
||||||
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
|
@ -52,15 +51,9 @@ func InitActionsCommonCache() {
|
||||||
return config.GetConfig().CacheTime.RecentCommentsCacheTime
|
return config.GetConfig().CacheTime.RecentCommentsCacheTime
|
||||||
})
|
})
|
||||||
|
|
||||||
cachemanager.NewMemoryMapCache(nil, dao.PostComments, c.CacheTime.PostCommentsCacheTime,
|
cachemanager.NewMemoryMapCache(nil, dao.PostComments, c.CacheTime.PostCommentsCacheTime, "postCommentIds", func() time.Duration {
|
||||||
"postCommentIds",
|
return config.GetConfig().CacheTime.PostCommentsCacheTime
|
||||||
func() time.Duration {
|
})
|
||||||
return config.GetConfig().CacheTime.PostCommentsCacheTime
|
|
||||||
},
|
|
||||||
cache.NewIncreaseUpdate("comment-increaseUpdate", dao.GetIncreaseComment, 30*time.Second,
|
|
||||||
func() time.Duration {
|
|
||||||
return config.GetConfig().CacheTime.CommentsIncreaseUpdateTime
|
|
||||||
}))
|
|
||||||
|
|
||||||
cachemanager.NewVarMemoryCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime, "maxPostId", func() time.Duration {
|
cachemanager.NewVarMemoryCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime, "maxPostId", func() time.Duration {
|
||||||
return config.GetConfig().CacheTime.MaxPostIdCacheTime
|
return config.GetConfig().CacheTime.MaxPostIdCacheTime
|
||||||
|
|
|
@ -46,24 +46,23 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CacheTime struct {
|
type CacheTime struct {
|
||||||
CacheControl time.Duration `yaml:"cacheControl" json:"cacheControl,omitempty"`
|
CacheControl time.Duration `yaml:"cacheControl" json:"cacheControl,omitempty"`
|
||||||
RecentPostCacheTime time.Duration `yaml:"recentPostCacheTime" json:"recentPostCacheTime,omitempty"`
|
RecentPostCacheTime time.Duration `yaml:"recentPostCacheTime" json:"recentPostCacheTime,omitempty"`
|
||||||
CategoryCacheTime time.Duration `yaml:"categoryCacheTime" json:"categoryCacheTime,omitempty"`
|
CategoryCacheTime time.Duration `yaml:"categoryCacheTime" json:"categoryCacheTime,omitempty"`
|
||||||
ArchiveCacheTime time.Duration `yaml:"archiveCacheTime" json:"archiveCacheTime,omitempty"`
|
ArchiveCacheTime time.Duration `yaml:"archiveCacheTime" json:"archiveCacheTime,omitempty"`
|
||||||
ContextPostCacheTime time.Duration `yaml:"contextPostCacheTime" json:"contextPostCacheTime,omitempty"`
|
ContextPostCacheTime time.Duration `yaml:"contextPostCacheTime" json:"contextPostCacheTime,omitempty"`
|
||||||
RecentCommentsCacheTime time.Duration `yaml:"recentCommentsCacheTime" json:"recentCommentsCacheTime,omitempty"`
|
RecentCommentsCacheTime time.Duration `yaml:"recentCommentsCacheTime" json:"recentCommentsCacheTime,omitempty"`
|
||||||
DigestCacheTime time.Duration `yaml:"digestCacheTime" json:"digestCacheTime,omitempty"`
|
DigestCacheTime time.Duration `yaml:"digestCacheTime" json:"digestCacheTime,omitempty"`
|
||||||
PostListCacheTime time.Duration `yaml:"postListCacheTime" json:"postListCacheTime,omitempty"`
|
PostListCacheTime time.Duration `yaml:"postListCacheTime" json:"postListCacheTime,omitempty"`
|
||||||
SearchPostCacheTime time.Duration `yaml:"searchPostCacheTime" json:"searchPostCacheTime,omitempty"`
|
SearchPostCacheTime time.Duration `yaml:"searchPostCacheTime" json:"searchPostCacheTime,omitempty"`
|
||||||
MonthPostCacheTime time.Duration `yaml:"monthPostCacheTime" json:"monthPostCacheTime,omitempty"`
|
MonthPostCacheTime time.Duration `yaml:"monthPostCacheTime" json:"monthPostCacheTime,omitempty"`
|
||||||
PostDataCacheTime time.Duration `yaml:"postDataCacheTime" json:"postDataCacheTime,omitempty"`
|
PostDataCacheTime time.Duration `yaml:"postDataCacheTime" json:"postDataCacheTime,omitempty"`
|
||||||
PostCommentsCacheTime time.Duration `yaml:"postCommentsCacheTime" json:"postCommentsCacheTime,omitempty"`
|
PostCommentsCacheTime time.Duration `yaml:"postCommentsCacheTime" json:"postCommentsCacheTime,omitempty"`
|
||||||
CrontabClearCacheTime time.Duration `yaml:"crontabClearCacheTime" json:"crontabClearCacheTime,omitempty"`
|
CrontabClearCacheTime time.Duration `yaml:"crontabClearCacheTime" json:"crontabClearCacheTime,omitempty"`
|
||||||
MaxPostIdCacheTime time.Duration `yaml:"maxPostIdCacheTime" json:"maxPostIdCacheTime,omitempty"`
|
MaxPostIdCacheTime time.Duration `yaml:"maxPostIdCacheTime" json:"maxPostIdCacheTime,omitempty"`
|
||||||
UserInfoCacheTime time.Duration `yaml:"userInfoCacheTime" json:"userInfoCacheTime,omitempty"`
|
UserInfoCacheTime time.Duration `yaml:"userInfoCacheTime" json:"userInfoCacheTime,omitempty"`
|
||||||
CommentsCacheTime time.Duration `yaml:"commentsCacheTime" json:"commentsCacheTime,omitempty"`
|
CommentsCacheTime time.Duration `yaml:"commentsCacheTime" json:"commentsCacheTime,omitempty"`
|
||||||
SleepTime []time.Duration `yaml:"sleepTime" json:"sleepTime,omitempty"`
|
SleepTime []time.Duration `yaml:"sleepTime" json:"sleepTime,omitempty"`
|
||||||
CommentsIncreaseUpdateTime time.Duration `yaml:"commentsIncreaseUpdateTime" json:"commentsIncreaseUpdateTime"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ssl struct {
|
type Ssl struct {
|
||||||
|
|
|
@ -2,14 +2,11 @@ package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
"github.com/fthvgb1/wp-go/helper/number"
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecentComments
|
// RecentComments
|
||||||
|
@ -52,63 +49,14 @@ func PostComments(ctx context.Context, postId uint64, _ ...any) ([]uint64, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCommentByIds(ctx context.Context, ids []uint64, _ ...any) (map[uint64]models.Comments, error) {
|
func GetCommentByIds(ctx context.Context, ids []uint64, _ ...any) (map[uint64]models.Comments, error) {
|
||||||
if len(ids) < 1 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
m := make(map[uint64]models.Comments)
|
m := make(map[uint64]models.Comments)
|
||||||
off := 0
|
r, err := model.SimpleFind[models.Comments](ctx, model.SqlBuilder{
|
||||||
for {
|
{"comment_ID", "in", ""}, {"comment_approved", "1"},
|
||||||
id := slice.Slice(ids, off, 500)
|
}, "*", slice.ToAnySlice(ids))
|
||||||
if len(id) < 1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
r, err := model.Finds[models.Comments](ctx, model.Conditions(
|
|
||||||
model.Where(model.SqlBuilder{
|
|
||||||
{"comment_ID", "in", ""}, {"comment_approved", "1"},
|
|
||||||
}),
|
|
||||||
model.Fields("*"),
|
|
||||||
model.In(slice.ToAnySlice(id)),
|
|
||||||
))
|
|
||||||
if err != nil {
|
|
||||||
return m, err
|
|
||||||
}
|
|
||||||
for _, comments := range r {
|
|
||||||
m[comments.CommentId] = comments
|
|
||||||
}
|
|
||||||
off += 500
|
|
||||||
}
|
|
||||||
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIncreaseComment(ctx context.Context, currentData []uint64, k uint64, t time.Time, _ ...any) (data []uint64, save bool, refresh bool, err error) {
|
|
||||||
r, err := model.ChunkFind[models.Comments](ctx, 1000, model.Conditions(
|
|
||||||
model.Where(model.SqlBuilder{
|
|
||||||
{"comment_approved", "1"},
|
|
||||||
{"comment_post_ID", "=", number.IntToString(k), "int"},
|
|
||||||
{"comment_date", ">=", t.Format(time.DateTime)},
|
|
||||||
}),
|
|
||||||
model.Fields("comment_ID"),
|
|
||||||
model.Order(model.SqlBuilder{
|
|
||||||
{"comment_date_gmt", "asc"},
|
|
||||||
{"comment_ID", "asc"},
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
return m, err
|
||||||
err = nil
|
|
||||||
refresh = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if len(r) < 1 {
|
return slice.SimpleToMap(r, func(t models.Comments) uint64 {
|
||||||
refresh = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rr := slice.Map(r, func(t models.Comments) uint64 {
|
|
||||||
return t.CommentId
|
return t.CommentId
|
||||||
})
|
}), err
|
||||||
data = append(currentData, rr...)
|
|
||||||
save = true
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
7
cache/cache.go
vendored
7
cache/cache.go
vendored
|
@ -30,10 +30,3 @@ type AnyCache[T any] interface {
|
||||||
Flush(ctx context.Context)
|
Flush(ctx context.Context)
|
||||||
GetLastSetTime(ctx context.Context) time.Time
|
GetLastSetTime(ctx context.Context) time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type Refresh[K comparable, V any] interface {
|
|
||||||
Refresh(ctx context.Context, k K, a ...any)
|
|
||||||
}
|
|
||||||
type RefreshVar[T any] interface {
|
|
||||||
Refresh(ctx context.Context, a ...any)
|
|
||||||
}
|
|
||||||
|
|
52
cache/cachemanager/manger.go
vendored
52
cache/cachemanager/manger.go
vendored
|
@ -5,7 +5,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/fthvgb1/wp-go/cache"
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,6 +15,8 @@ var ctx = context.Background()
|
||||||
var mapFlush = safety.NewMap[string, func(any)]()
|
var mapFlush = safety.NewMap[string, func(any)]()
|
||||||
var anyFlush = safety.NewMap[string, func()]()
|
var anyFlush = safety.NewMap[string, func()]()
|
||||||
|
|
||||||
|
var expiredTime = safety.NewMap[string, expire]()
|
||||||
|
|
||||||
var varCache = safety.NewMap[string, any]()
|
var varCache = safety.NewMap[string, any]()
|
||||||
var mapCache = safety.NewMap[string, any]()
|
var mapCache = safety.NewMap[string, any]()
|
||||||
|
|
||||||
|
@ -47,6 +48,12 @@ func SetMapCache[K comparable, V any](name string, ca *cache.MapCache[K, V]) err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type expire struct {
|
||||||
|
fn func() time.Duration
|
||||||
|
p *safety.Var[time.Duration]
|
||||||
|
isUseManger *safety.Var[bool]
|
||||||
|
}
|
||||||
|
|
||||||
type flush interface {
|
type flush interface {
|
||||||
Flush(ctx context.Context)
|
Flush(ctx context.Context)
|
||||||
}
|
}
|
||||||
|
@ -169,8 +176,7 @@ func parseArgs(args ...any) (string, func() time.Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapBatchFn[K, V], fn cache.MapSingleFn[K, V], args ...any) *cache.MapCache[K, V] {
|
func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapBatchFn[K, V], fn cache.MapSingleFn[K, V], args ...any) *cache.MapCache[K, V] {
|
||||||
inc := helper.ParseArgs(cache.IncreaseUpdate[K, V]{}, args...)
|
m := cache.NewMapCache[K, V](data, fn, batchFn)
|
||||||
m := cache.NewMapCache[K, V](data, fn, batchFn, inc)
|
|
||||||
FlushPush(m)
|
FlushPush(m)
|
||||||
ClearPush(m)
|
ClearPush(m)
|
||||||
name, f := parseArgs(args...)
|
name, f := parseArgs(args...)
|
||||||
|
@ -195,13 +201,43 @@ func SetExpireTime(c cache.SetTime, name string, expireTime time.Duration, expir
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fn := reload.FnVal(str.Join("cacheManger-", name, "-expiredTime"), expireTime, expireTimeFn)
|
var t, tt func() time.Duration
|
||||||
c.SetExpiredTime(fn)
|
t = expireTimeFn
|
||||||
|
if t == nil {
|
||||||
|
t = func() time.Duration {
|
||||||
|
return expireTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tt = t
|
||||||
|
expireTime = t()
|
||||||
|
p := safety.NewVar(expireTime)
|
||||||
|
e := expire{
|
||||||
|
fn: t,
|
||||||
|
p: p,
|
||||||
|
isUseManger: safety.NewVar(false),
|
||||||
|
}
|
||||||
|
expiredTime.Store(name, e)
|
||||||
|
reload.Push(func() {
|
||||||
|
if !e.isUseManger.Load() {
|
||||||
|
e.p.Store(tt())
|
||||||
|
}
|
||||||
|
}, str.Join("cacheManger-", name, "-expiredTime"))
|
||||||
|
t = func() time.Duration {
|
||||||
|
return e.p.Load()
|
||||||
|
}
|
||||||
|
c.SetExpiredTime(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeExpireTime(t time.Duration, name ...string) {
|
func ChangeExpireTime(t time.Duration, name ...string) {
|
||||||
for _, s := range name {
|
for _, s := range name {
|
||||||
reload.ChangeFnVal(s, t)
|
v, ok := expiredTime.Load(s)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.p.Store(t)
|
||||||
|
if !v.isUseManger.Load() {
|
||||||
|
v.isUseManger.Store(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,9 +255,7 @@ func ClearExpired() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVarCache[T any](c cache.AnyCache[T], fn func(context.Context, ...any) (T, error), a ...any) *cache.VarCache[T] {
|
func NewVarCache[T any](c cache.AnyCache[T], fn func(context.Context, ...any) (T, error), a ...any) *cache.VarCache[T] {
|
||||||
inc := helper.ParseArgs(cache.IncreaseUpdateVar[T]{}, a...)
|
v := cache.NewVarCache(c, fn)
|
||||||
ref := helper.ParseArgs(cache.RefreshVar[T](nil), a...)
|
|
||||||
v := cache.NewVarCache(c, fn, inc, ref)
|
|
||||||
FlushPush(v)
|
FlushPush(v)
|
||||||
name, _ := parseArgs(a...)
|
name, _ := parseArgs(a...)
|
||||||
if name != "" {
|
if name != "" {
|
||||||
|
|
16
cache/cachemanager/manger_test.go
vendored
16
cache/cachemanager/manger_test.go
vendored
|
@ -94,18 +94,18 @@ func TestSetExpireTime(t *testing.T) {
|
||||||
|
|
||||||
func TestSetMapCache(t *testing.T) {
|
func TestSetMapCache(t *testing.T) {
|
||||||
t.Run("t1", func(t *testing.T) {
|
t.Run("t1", func(t *testing.T) {
|
||||||
x := NewMemoryMapCache(nil, func(ctx2 context.Context, k string, a ...any) (string, error) {
|
NewMemoryMapCache(nil, func(ctx2 context.Context, k string, a ...any) (string, error) {
|
||||||
fmt.Println("memory cache")
|
fmt.Println("memory cache")
|
||||||
return strings.Repeat(k, 2), nil
|
return strings.Repeat(k, 2), nil
|
||||||
}, time.Hour, "test")
|
}, time.Hour, "test")
|
||||||
fmt.Println(Get[string]("test", ctx, "test", time.Second))
|
fmt.Println(Get[string]("test", ctx, "test", time.Second))
|
||||||
|
|
||||||
NewMapCache[string, string](xx[string, string]{m: map[string]string{}}, nil, func(ctx2 context.Context, k string, a ...any) (string, error) {
|
cc := NewMapCache[string, string](xx[string, string]{m: map[string]string{}}, nil, func(ctx2 context.Context, k string, a ...any) (string, error) {
|
||||||
fmt.Println("other cache drives. eg: redis,file.....")
|
fmt.Println("other cache drives. eg: redis,file.....")
|
||||||
return strings.Repeat(k, 2), nil
|
return strings.Repeat(k, 2), nil
|
||||||
}, "test", time.Hour)
|
}, "kkk", time.Hour)
|
||||||
|
|
||||||
if err := SetMapCache("kkk", x); err != nil {
|
if err := SetMapCache("test", cc); err != nil {
|
||||||
t.Errorf("SetMapCache() error = %v, wantErr %v", err, nil)
|
t.Errorf("SetMapCache() error = %v, wantErr %v", err, nil)
|
||||||
}
|
}
|
||||||
fmt.Println(Get[string]("test", ctx, "test", time.Second))
|
fmt.Println(Get[string]("test", ctx, "test", time.Second))
|
||||||
|
@ -152,16 +152,16 @@ func (x xx[K, V]) ClearExpired(ctx context.Context) {
|
||||||
|
|
||||||
func TestSetVarCache(t *testing.T) {
|
func TestSetVarCache(t *testing.T) {
|
||||||
t.Run("t1", func(t *testing.T) {
|
t.Run("t1", func(t *testing.T) {
|
||||||
bak := NewVarMemoryCache(func(ctx2 context.Context, a ...any) (string, error) {
|
NewVarMemoryCache(func(ctx2 context.Context, a ...any) (string, error) {
|
||||||
fmt.Println("memory cache")
|
fmt.Println("memory cache")
|
||||||
return "xxx", nil
|
return "xxx", nil
|
||||||
}, time.Hour, "test")
|
}, time.Hour, "test")
|
||||||
fmt.Println(GetVarVal[string]("test", ctx, time.Second))
|
fmt.Println(GetVarVal[string]("test", ctx, time.Second))
|
||||||
NewVarCache[string](oo[string]{}, func(ctx2 context.Context, a ...any) (string, error) {
|
o := NewVarCache[string](oo[string]{}, func(ctx2 context.Context, a ...any) (string, error) {
|
||||||
fmt.Println("other cache drives. eg: redis,file.....")
|
fmt.Println("other cache drives. eg: redis,file.....")
|
||||||
return "ooo", nil
|
return "ooo", nil
|
||||||
}, "test")
|
})
|
||||||
if err := SetVarCache("xx", bak); err != nil {
|
if err := SetVarCache("test", o); err != nil {
|
||||||
t.Errorf("SetVarCache() error = %v, wantErr %v", err, nil)
|
t.Errorf("SetVarCache() error = %v, wantErr %v", err, nil)
|
||||||
}
|
}
|
||||||
fmt.Println(GetVarVal[string]("test", ctx, time.Second))
|
fmt.Println(GetVarVal[string]("test", ctx, time.Second))
|
||||||
|
|
93
cache/map.go
vendored
93
cache/map.go
vendored
|
@ -4,8 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
|
||||||
"github.com/fthvgb1/wp-go/helper/maps"
|
"github.com/fthvgb1/wp-go/helper/maps"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -18,37 +16,24 @@ type MapCache[K comparable, V any] struct {
|
||||||
batchCacheFn MapBatchFn[K, V]
|
batchCacheFn MapBatchFn[K, V]
|
||||||
getCacheBatch func(c context.Context, key []K, timeout time.Duration, params ...any) ([]V, error)
|
getCacheBatch func(c context.Context, key []K, timeout time.Duration, params ...any) ([]V, error)
|
||||||
getCacheBatchToMap func(c context.Context, key []K, timeout time.Duration, params ...any) (map[K]V, error)
|
getCacheBatchToMap func(c context.Context, key []K, timeout time.Duration, params ...any) (map[K]V, error)
|
||||||
increaseUpdate IncreaseUpdate[K, V]
|
|
||||||
refresh Refresh[K, V]
|
|
||||||
}
|
|
||||||
type IncreaseUpdate[K comparable, V any] struct {
|
|
||||||
CycleTime func() time.Duration
|
|
||||||
Fn IncreaseFn[K, V]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewIncreaseUpdate[K comparable, V any](name string, fn IncreaseFn[K, V], cycleTime time.Duration, tFn func() time.Duration) IncreaseUpdate[K, V] {
|
|
||||||
tFn = reload.FnVal(name, cycleTime, tFn)
|
|
||||||
return IncreaseUpdate[K, V]{CycleTime: tFn, Fn: fn}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MapSingleFn[K, V any] func(context.Context, K, ...any) (V, error)
|
type MapSingleFn[K, V any] func(context.Context, K, ...any) (V, error)
|
||||||
type MapBatchFn[K comparable, V any] func(context.Context, []K, ...any) (map[K]V, error)
|
type MapBatchFn[K comparable, V any] func(context.Context, []K, ...any) (map[K]V, error)
|
||||||
type IncreaseFn[K comparable, V any] func(c context.Context, currentData V, k K, t time.Time, a ...any) (data V, save bool, refresh bool, err error)
|
|
||||||
|
|
||||||
func NewMapCache[K comparable, V any](ca Cache[K, V], cacheFunc MapSingleFn[K, V], batchCacheFn MapBatchFn[K, V], inc IncreaseUpdate[K, V]) *MapCache[K, V] {
|
func NewMapCache[K comparable, V any](data Cache[K, V], cacheFunc MapSingleFn[K, V], batchCacheFn MapBatchFn[K, V]) *MapCache[K, V] {
|
||||||
r := &MapCache[K, V]{
|
r := &MapCache[K, V]{
|
||||||
Cache: ca,
|
Cache: data,
|
||||||
mux: sync.Mutex{},
|
mux: sync.Mutex{},
|
||||||
cacheFunc: cacheFunc,
|
cacheFunc: cacheFunc,
|
||||||
batchCacheFn: batchCacheFn,
|
batchCacheFn: batchCacheFn,
|
||||||
increaseUpdate: inc,
|
|
||||||
}
|
}
|
||||||
if cacheFunc == nil && batchCacheFn != nil {
|
if cacheFunc == nil && batchCacheFn != nil {
|
||||||
r.setDefaultCacheFn(batchCacheFn)
|
r.setDefaultCacheFn(batchCacheFn)
|
||||||
} else if batchCacheFn == nil && cacheFunc != nil {
|
} else if batchCacheFn == nil && cacheFunc != nil {
|
||||||
r.SetDefaultBatchFunc(cacheFunc)
|
r.SetDefaultBatchFunc(cacheFunc)
|
||||||
}
|
}
|
||||||
ex, ok := any(ca).(Expend[K, V])
|
ex, ok := any(data).(Expend[K, V])
|
||||||
if !ok {
|
if !ok {
|
||||||
r.getCacheBatch = r.getCacheBatchs
|
r.getCacheBatch = r.getCacheBatchs
|
||||||
r.getCacheBatchToMap = r.getBatchToMapes
|
r.getCacheBatchToMap = r.getBatchToMapes
|
||||||
|
@ -56,10 +41,6 @@ func NewMapCache[K comparable, V any](ca Cache[K, V], cacheFunc MapSingleFn[K, V
|
||||||
r.getCacheBatch = r.getBatches(ex)
|
r.getCacheBatch = r.getBatches(ex)
|
||||||
r.getCacheBatchToMap = r.getBatchToMap(ex)
|
r.getCacheBatchToMap = r.getBatchToMap(ex)
|
||||||
}
|
}
|
||||||
re, ok := any(ca).(Refresh[K, V])
|
|
||||||
if ok {
|
|
||||||
r.refresh = re
|
|
||||||
}
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,44 +101,10 @@ func (m *MapCache[K, V]) Flush(ctx context.Context) {
|
||||||
|
|
||||||
func (m *MapCache[K, V]) GetCache(c context.Context, key K, timeout time.Duration, params ...any) (V, error) {
|
func (m *MapCache[K, V]) GetCache(c context.Context, key K, timeout time.Duration, params ...any) (V, error) {
|
||||||
data, ok := m.Get(c, key)
|
data, ok := m.Get(c, key)
|
||||||
var err error
|
|
||||||
if ok {
|
if ok {
|
||||||
if m.increaseUpdate.Fn == nil || m.refresh == nil {
|
return data, nil
|
||||||
return data, err
|
|
||||||
}
|
|
||||||
nowTime := time.Now()
|
|
||||||
if nowTime.Sub(m.GetLastSetTime(c, key)) < m.increaseUpdate.CycleTime() {
|
|
||||||
return data, err
|
|
||||||
}
|
|
||||||
fn := func() {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
if nowTime.Sub(m.GetLastSetTime(c, key)) < m.increaseUpdate.CycleTime() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dat, save, refresh, er := m.increaseUpdate.Fn(c, data, key, m.GetLastSetTime(c, key), params...)
|
|
||||||
if er != nil {
|
|
||||||
err = er
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if refresh {
|
|
||||||
m.refresh.Refresh(c, key, params...)
|
|
||||||
}
|
|
||||||
if save {
|
|
||||||
m.Set(c, key, dat)
|
|
||||||
data = dat
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if timeout > 0 {
|
|
||||||
er := helper.RunFnWithTimeout(c, timeout, fn, fmt.Sprintf("increateUpdate cache %v err", key))
|
|
||||||
if err == nil && er != nil {
|
|
||||||
return data, er
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
return data, err
|
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
call := func() {
|
call := func() {
|
||||||
m.mux.Lock()
|
m.mux.Lock()
|
||||||
defer m.mux.Unlock()
|
defer m.mux.Unlock()
|
||||||
|
@ -171,9 +118,19 @@ func (m *MapCache[K, V]) GetCache(c context.Context, key K, timeout time.Duratio
|
||||||
m.Set(c, key, data)
|
m.Set(c, key, data)
|
||||||
}
|
}
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
er := helper.RunFnWithTimeout(c, timeout, call, fmt.Sprintf("get cache %v ", key))
|
ctx, cancel := context.WithTimeout(c, timeout)
|
||||||
if err == nil && er != nil {
|
defer cancel()
|
||||||
err = er
|
done := make(chan struct{}, 1)
|
||||||
|
go func() {
|
||||||
|
call()
|
||||||
|
done <- struct{}{}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
err = errors.New(fmt.Sprintf("get cache %v %s", key, ctx.Err().Error()))
|
||||||
|
var vv V
|
||||||
|
return vv, err
|
||||||
|
case <-done:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
call()
|
call()
|
||||||
|
@ -229,7 +186,7 @@ func (m *MapCache[K, V]) getBatchToMap(e Expend[K, V]) func(c context.Context, k
|
||||||
r, er := m.batchCacheFn(ctx, maps.FilterToSlice(needIndex, func(k K, v int) (K, bool) {
|
r, er := m.batchCacheFn(ctx, maps.FilterToSlice(needIndex, func(k K, v int) (K, bool) {
|
||||||
return k, true
|
return k, true
|
||||||
}), params...)
|
}), params...)
|
||||||
if er != nil {
|
if err != nil {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -296,7 +253,7 @@ func (m *MapCache[K, V]) getBatchToMapes(c context.Context, key []K, timeout tim
|
||||||
}
|
}
|
||||||
|
|
||||||
rr, er := m.batchCacheFn(c, needFlushs, params...)
|
rr, er := m.batchCacheFn(c, needFlushs, params...)
|
||||||
if er != nil {
|
if err != nil {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -361,7 +318,7 @@ func (m *MapCache[K, V]) getCacheBatchs(c context.Context, key []K, timeout time
|
||||||
}
|
}
|
||||||
|
|
||||||
r, er := m.batchCacheFn(c, needFlushs, params...)
|
r, er := m.batchCacheFn(c, needFlushs, params...)
|
||||||
if er != nil {
|
if err != nil {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -441,7 +398,7 @@ func (m *MapCache[K, V]) getBatches(e Expend[K, V]) func(ctx context.Context, ke
|
||||||
r, er := m.batchCacheFn(ctx, maps.FilterToSlice(needIndex, func(k K, v int) (K, bool) {
|
r, er := m.batchCacheFn(ctx, maps.FilterToSlice(needIndex, func(k K, v int) (K, bool) {
|
||||||
return k, true
|
return k, true
|
||||||
}), params...)
|
}), params...)
|
||||||
if er != nil {
|
if err != nil {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
11
cache/memorymapcache.go
vendored
11
cache/memorymapcache.go
vendored
|
@ -2,7 +2,6 @@ package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -98,13 +97,3 @@ func (m *MemoryMapCache[K, V]) ClearExpired(_ context.Context) {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MemoryMapCache[K, V]) Refresh(_ context.Context, k K, a ...any) {
|
|
||||||
v, ok := m.Load(k)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t := helper.ParseArgs(time.Now(), a...)
|
|
||||||
v.setTime = t
|
|
||||||
m.Store(k, v)
|
|
||||||
}
|
|
||||||
|
|
47
cache/reload/reload.go
vendored
47
cache/reload/reload.go
vendored
|
@ -261,6 +261,7 @@ func Push(fn func(), a ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Reload() {
|
func Reload() {
|
||||||
|
anyMap.Flush()
|
||||||
callsM.Flush()
|
callsM.Flush()
|
||||||
flushMapFn.Flush()
|
flushMapFn.Flush()
|
||||||
callll := calls.Load()
|
callll := calls.Load()
|
||||||
|
@ -272,49 +273,3 @@ func Reload() {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Any[T any] struct {
|
|
||||||
fn func() T
|
|
||||||
v *safety.Var[T]
|
|
||||||
isUseManger *safety.Var[bool]
|
|
||||||
}
|
|
||||||
|
|
||||||
func FnVal[T any](name string, t T, fn func() T) func() T {
|
|
||||||
if fn == nil {
|
|
||||||
fn = func() T {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t = fn()
|
|
||||||
}
|
|
||||||
p := safety.NewVar(t)
|
|
||||||
e := Any[T]{
|
|
||||||
fn: fn,
|
|
||||||
v: p,
|
|
||||||
isUseManger: safety.NewVar(false),
|
|
||||||
}
|
|
||||||
Push(func() {
|
|
||||||
if !e.isUseManger.Load() {
|
|
||||||
e.v.Store(fn())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
anyMap.Store(name, e)
|
|
||||||
return func() T {
|
|
||||||
return e.v.Load()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChangeFnVal[T any](name string, val T) {
|
|
||||||
v, ok := anyMap.Load(name)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
vv, ok := v.(Any[T])
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !vv.isUseManger.Load() {
|
|
||||||
vv.isUseManger.Store(true)
|
|
||||||
}
|
|
||||||
vv.v.Store(val)
|
|
||||||
}
|
|
||||||
|
|
67
cache/vars.go
vendored
67
cache/vars.go
vendored
|
@ -2,7 +2,8 @@ package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,54 +11,16 @@ import (
|
||||||
|
|
||||||
type VarCache[T any] struct {
|
type VarCache[T any] struct {
|
||||||
AnyCache[T]
|
AnyCache[T]
|
||||||
setCacheFunc func(context.Context, ...any) (T, error)
|
setCacheFunc func(context.Context, ...any) (T, error)
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
increaseUpdate IncreaseUpdateVar[T]
|
|
||||||
refresh RefreshVar[T]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type IncreaseUpdateVar[T any] struct {
|
|
||||||
CycleTime func() time.Duration
|
|
||||||
Fn IncreaseVarFn[T]
|
|
||||||
}
|
|
||||||
|
|
||||||
type IncreaseVarFn[T any] func(c context.Context, currentData T, t time.Time, a ...any) (data T, save bool, refresh bool, err error)
|
|
||||||
|
|
||||||
func (t *VarCache[T]) GetCache(ctx context.Context, timeout time.Duration, params ...any) (T, error) {
|
func (t *VarCache[T]) GetCache(ctx context.Context, timeout time.Duration, params ...any) (T, error) {
|
||||||
data, ok := t.Get(ctx)
|
data, ok := t.Get(ctx)
|
||||||
var err error
|
|
||||||
if ok {
|
if ok {
|
||||||
if t.increaseUpdate.Fn != nil && t.refresh != nil {
|
|
||||||
nowTime := time.Now()
|
|
||||||
if t.increaseUpdate.CycleTime() > nowTime.Sub(t.GetLastSetTime(ctx)) {
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
fn := func() {
|
|
||||||
t.mutex.Lock()
|
|
||||||
defer t.mutex.Unlock()
|
|
||||||
da, save, refresh, er := t.increaseUpdate.Fn(ctx, data, t.GetLastSetTime(ctx), params...)
|
|
||||||
if er != nil {
|
|
||||||
err = er
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if save {
|
|
||||||
t.Set(ctx, da)
|
|
||||||
}
|
|
||||||
if refresh {
|
|
||||||
t.refresh.Refresh(ctx, params...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if timeout > 0 {
|
|
||||||
er := helper.RunFnWithTimeout(ctx, timeout, fn, "increaseUpdate cache fail")
|
|
||||||
if err == nil && er != nil {
|
|
||||||
err = er
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
call := func() {
|
call := func() {
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
defer t.mutex.Unlock()
|
defer t.mutex.Unlock()
|
||||||
|
@ -75,9 +38,19 @@ func (t *VarCache[T]) GetCache(ctx context.Context, timeout time.Duration, param
|
||||||
data = r
|
data = r
|
||||||
}
|
}
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
er := helper.RunFnWithTimeout(ctx, timeout, call, "get cache fail")
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
if err == nil && er != nil {
|
defer cancel()
|
||||||
err = er
|
done := make(chan struct{}, 1)
|
||||||
|
go func() {
|
||||||
|
call()
|
||||||
|
done <- struct{}{}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
err = errors.New(fmt.Sprintf("get cache %s", ctx.Err().Error()))
|
||||||
|
case <-done:
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
call()
|
call()
|
||||||
|
@ -125,11 +98,9 @@ func (c *VarMemoryCache[T]) GetLastSetTime(_ context.Context) time.Time {
|
||||||
return c.v.Load().setTime
|
return c.v.Load().setTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVarCache[T any](cache AnyCache[T], fn func(context.Context, ...any) (T, error), inc IncreaseUpdateVar[T], ref RefreshVar[T]) *VarCache[T] {
|
func NewVarCache[T any](cache AnyCache[T], fn func(context.Context, ...any) (T, error)) *VarCache[T] {
|
||||||
return &VarCache[T]{
|
return &VarCache[T]{
|
||||||
AnyCache: cache, setCacheFunc: fn, mutex: sync.Mutex{},
|
AnyCache: cache, setCacheFunc: fn, mutex: sync.Mutex{},
|
||||||
increaseUpdate: inc,
|
|
||||||
refresh: ref,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,6 @@ cacheTime:
|
||||||
userInfoCacheTime: 24h
|
userInfoCacheTime: 24h
|
||||||
# 单独评论缓存时间
|
# 单独评论缓存时间
|
||||||
commentsCacheTime: 24h
|
commentsCacheTime: 24h
|
||||||
# 评论增量更新时间
|
|
||||||
commentsIncreaseUpdateTime: 30s
|
|
||||||
# 随机sleep时间
|
# 随机sleep时间
|
||||||
sleepTime: [ 1s,3s ]
|
sleepTime: [ 1s,3s ]
|
||||||
# 摘要字数 >0截取指定字数 =0输出出空字符 <0为不截取,原样输出
|
# 摘要字数 >0截取指定字数 =0输出出空字符 <0为不截取,原样输出
|
||||||
|
|
|
@ -2,7 +2,6 @@ package helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -10,7 +9,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToAny[T any](v T) any {
|
func ToAny[T any](v T) any {
|
||||||
|
@ -146,45 +144,3 @@ func ParseArgs[T any](defaults T, a ...any) T {
|
||||||
}
|
}
|
||||||
return defaults
|
return defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunFnWithTimeout(ctx context.Context, t time.Duration, call func(), a ...any) (err error) {
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, t)
|
|
||||||
defer cancel()
|
|
||||||
done := make(chan struct{}, 1)
|
|
||||||
go func() {
|
|
||||||
call()
|
|
||||||
done <- struct{}{}
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
msg := ParseArgs("", a...)
|
|
||||||
if msg != "" {
|
|
||||||
return errors.New(str.Join(msg, ":", ctx.Err().Error()))
|
|
||||||
}
|
|
||||||
return ctx.Err()
|
|
||||||
case <-done:
|
|
||||||
close(done)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunFnWithTimeouts[A, V any](ctx context.Context, t time.Duration, ar A, call func(A) (V, error), a ...any) (v V, err error) {
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, t)
|
|
||||||
defer cancel()
|
|
||||||
done := make(chan struct{}, 1)
|
|
||||||
go func() {
|
|
||||||
v, err = call(ar)
|
|
||||||
done <- struct{}{}
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
msg := ParseArgs("", a...)
|
|
||||||
if msg != "" {
|
|
||||||
return v, errors.New(str.Join(msg, ":", ctx.Err().Error()))
|
|
||||||
}
|
|
||||||
return v, ctx.Err()
|
|
||||||
case <-done:
|
|
||||||
close(done)
|
|
||||||
}
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
|
|
|
@ -58,15 +58,6 @@ func Filter[T any](arr []T, fn func(T, int) bool) []T {
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
func Filters[T any](arr []T, fn func(T) bool) []T {
|
|
||||||
var r []T
|
|
||||||
for _, t := range arr {
|
|
||||||
if fn(t) {
|
|
||||||
r = append(r, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func Reduce[R, T any](arr []T, fn func(T, R) R, r R) R {
|
func Reduce[R, T any](arr []T, fn func(T, R) R, r R) R {
|
||||||
for _, t := range arr {
|
for _, t := range arr {
|
||||||
|
@ -152,11 +143,13 @@ func Slice[T any](arr []T, offset, length int) (r []T) {
|
||||||
length = l - offset
|
length = l - offset
|
||||||
}
|
}
|
||||||
if l > offset && l >= offset+length {
|
if l > offset && l >= offset+length {
|
||||||
r = arr[offset : offset+length]
|
r = append(make([]T, 0, length), arr[offset:offset+length]...)
|
||||||
|
arr = append(arr[:offset], arr[offset+length:]...)
|
||||||
} else if l <= offset {
|
} else if l <= offset {
|
||||||
return
|
return
|
||||||
} else if l > offset && l < offset+length {
|
} else if l > offset && l < offset+length {
|
||||||
r = arr[offset:]
|
r = append(make([]T, 0, length), arr[offset:]...)
|
||||||
|
arr = arr[:offset]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,6 @@ func Splice[T any](a *[]T, offset, length int, replacement []T) []T {
|
||||||
}
|
}
|
||||||
if offset >= 0 {
|
if offset >= 0 {
|
||||||
if offset+length > l {
|
if offset+length > l {
|
||||||
if offset == 0 {
|
|
||||||
*a = []T{}
|
|
||||||
return arr[:l]
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
} else if l > offset && l < offset+length {
|
} else if l > offset && l < offset+length {
|
||||||
v := arr[offset:l]
|
v := arr[offset:l]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user