Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
8aeec60181 | |||
58d3e4f645 | |||
e592a753bf | |||
d598fb5ce5 | |||
63f769796f | |||
7cbfdf8601 | |||
9c60d10568 | |||
dcbe760f09 | |||
d220bb2a6c | |||
eb7ccd4f2d | |||
39c9dc1b09 | |||
68beb0fcbb | |||
1f5f7f465d | |||
b7c09cb5a2 | |||
5942f76972 | |||
1f40810b78 | |||
da858d55e0 | |||
166bb08ed0 | |||
5eaf798a6c | |||
e2e6bcc8ce | |||
daa7101493 | |||
6f51f1c295 | |||
a8d1dcdd5b | |||
9af2257650 | |||
63591899bb | |||
ee9ba3fcf0 | |||
a78815f3d3 | |||
6209f2b5e5 | |||
08d3bca39c | |||
9b8e597066 | |||
3215b0c8ea | |||
c7c97c469f | |||
b45ad0e54e | |||
a0c6e48e83 | |||
3c3ed73971 | |||
be58a35245 | |||
67bdf1e070 | |||
981e0ad85b | |||
74159940b5 | |||
206e5902d1 | |||
2d38b36525 | |||
af712f06a5 | |||
73575965d3 | |||
f49ad731e3 | |||
802c7c7dcc | |||
20ea36c727 | |||
fd3199a83c |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@
|
||||||
err.log
|
err.log
|
||||||
/plugins/
|
/plugins/
|
||||||
/config.json
|
/config.json
|
||||||
|
go.sum
|
|
@ -1,7 +1,6 @@
|
||||||
FROM golang:1.21.4-alpine as gobulidIso
|
FROM golang:1.22.2-alpine as gobulidIso
|
||||||
COPY ./ /go/src/wp-go
|
COPY ./ /go/src/wp-go
|
||||||
WORKDIR /go/src/wp-go
|
WORKDIR /go/src/wp-go
|
||||||
#ENV GOPROXY="https://goproxy.cn"
|
|
||||||
RUN go build -ldflags "-w" -tags netgo -o wp-go app/cmd/main.go
|
RUN go build -ldflags "-w" -tags netgo -o wp-go app/cmd/main.go
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
10
README.md
10
README.md
|
@ -20,6 +20,11 @@
|
||||||
- kill -SIGUSR1 PID 更新配置和清空缓存
|
- kill -SIGUSR1 PID 更新配置和清空缓存
|
||||||
- kill -SIGUSR2 PID 清空缓存
|
- kill -SIGUSR2 PID 清空缓存
|
||||||
|
|
||||||
|
#### 运行
|
||||||
|
```
|
||||||
|
go run app/cmd/main.go [-c configpath] [-p port]
|
||||||
|
```
|
||||||
|
|
||||||
#### 数据显示支持程度
|
#### 数据显示支持程度
|
||||||
|
|
||||||
| 页表 | 支持程度 |
|
| 页表 | 支持程度 |
|
||||||
|
@ -75,3 +80,8 @@
|
||||||
#### 其它
|
#### 其它
|
||||||
|
|
||||||
用的gin框架和sqlx,在外面封装了层查询的方法。
|
用的gin框架和sqlx,在外面封装了层查询的方法。
|
||||||
|
|
||||||
|
#### 鸣谢
|
||||||
|
|
||||||
|
<a href="https://jb.gg/OpenSourceSupport"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png" alt="JetBrains Logo (Main) logo." width="30%"></a>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
func ThemeHook(scene string) func(*gin.Context) {
|
func ThemeHook(scene string) func(*gin.Context) {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
t := theme.GetCurrentTemplateName()
|
t := theme.GetCurrentTheme()
|
||||||
h := wp.NewHandle(c, scene, t)
|
h := wp.NewHandle(c, scene, t)
|
||||||
theme.Hook(t, h)
|
theme.Hook(t, h)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/app/mail"
|
"github.com/fthvgb1/wp-go/app/ossigns"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/cache"
|
"github.com/fthvgb1/wp-go/app/pkg/cache"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/config"
|
"github.com/fthvgb1/wp-go/app/pkg/config"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/db"
|
"github.com/fthvgb1/wp-go/app/pkg/db"
|
||||||
|
@ -14,14 +14,10 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/app/theme"
|
"github.com/fthvgb1/wp-go/app/theme"
|
||||||
"github.com/fthvgb1/wp-go/app/wpconfig"
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -89,52 +85,6 @@ func cronClearCache() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func flushCache() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err := mail.SendMail([]string{config.GetConfig().Mail.User}, "清空缓存失败", fmt.Sprintf("err:[%s]", r))
|
|
||||||
logs.IfError(err, "发邮件失败")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
cachemanager.Flush()
|
|
||||||
log.Println("all cache flushed")
|
|
||||||
}
|
|
||||||
|
|
||||||
func reloads() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
log.Println(r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err := config.InitConfig(confPath)
|
|
||||||
logs.IfError(err, "获取配置文件失败", confPath)
|
|
||||||
err = logs.InitLogger()
|
|
||||||
logs.IfError(err, "日志配置错误")
|
|
||||||
_, err = db.InitDb()
|
|
||||||
logs.IfError(err, "重新读取db失败", config.GetConfig().Mysql)
|
|
||||||
err = wpconfig.InitOptions()
|
|
||||||
logs.IfError(err, "获取网站设置WpOption失败")
|
|
||||||
err = wpconfig.InitTerms()
|
|
||||||
logs.IfError(err, "获取WpTerms表失败")
|
|
||||||
wphandle.LoadPlugins()
|
|
||||||
reload.Reloads("themeArgAndConfig")
|
|
||||||
flushCache()
|
|
||||||
log.Println("reload complete")
|
|
||||||
}
|
|
||||||
|
|
||||||
func signalNotify() {
|
|
||||||
c := make(chan os.Signal)
|
|
||||||
signal.Notify(c, syscall.SIGUSR1, syscall.SIGUSR2)
|
|
||||||
for {
|
|
||||||
switch <-c {
|
|
||||||
case syscall.SIGUSR1:
|
|
||||||
go reloads()
|
|
||||||
case syscall.SIGUSR2:
|
|
||||||
go flushCache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -143,7 +93,8 @@ func main() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
inits()
|
inits()
|
||||||
go signalNotify()
|
ossigns.SetConfPath(confPath)
|
||||||
|
go ossigns.SignalNotify()
|
||||||
Gin := route.SetupRouter()
|
Gin := route.SetupRouter()
|
||||||
c := config.GetConfig()
|
c := config.GetConfig()
|
||||||
if c.Ssl.Key != "" && c.Ssl.Cert != "" {
|
if c.Ssl.Key != "" && c.Ssl.Cert != "" {
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"github.com/fthvgb1/wp-go/helper/httptool"
|
|
||||||
strings2 "github.com/fthvgb1/wp-go/helper/strings"
|
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
|
||||||
"github.com/fthvgb1/wp-go/taskPools"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var reg = regexp.MustCompile(`<a.*href="([^"]+?)".*?>`)
|
|
||||||
var m = safety.NewMap[string, bool]()
|
|
||||||
|
|
||||||
var mut = sync.Mutex{}
|
|
||||||
|
|
||||||
func parseHtml(ss string) {
|
|
||||||
r := reg.FindAllStringSubmatch(ss, -1)
|
|
||||||
|
|
||||||
for _, href := range r {
|
|
||||||
if href[1] == "/" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.ContainsAny(href[1], ".") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if string([]rune(href[1])[0:3]) == "http" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mut.Lock()
|
|
||||||
if _, ok := m.Load(href[1]); !ok {
|
|
||||||
m.Store(href[1], false)
|
|
||||||
}
|
|
||||||
mut.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func siteFetch(c int, u string) {
|
|
||||||
u = strings.TrimRight(u, "/")
|
|
||||||
ss, code, err := httptool.GetString(u, nil)
|
|
||||||
if err != nil || code != http.StatusOK {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
parseHtml(ss)
|
|
||||||
|
|
||||||
p := taskPools.NewPools(c)
|
|
||||||
for {
|
|
||||||
m.Range(func(key string, value bool) bool {
|
|
||||||
if value {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
u := strings2.Join(u, key)
|
|
||||||
p.Execute(func() {
|
|
||||||
ss, code, err := httptool.GetString(u, nil)
|
|
||||||
fmt.Println(u, code)
|
|
||||||
if err != nil || code != http.StatusOK {
|
|
||||||
panic(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
parseHtml(ss)
|
|
||||||
m.Store(key, true)
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
var x bool
|
|
||||||
m.Range(func(key string, value bool) bool {
|
|
||||||
if !value {
|
|
||||||
x = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
if !x {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.Wait()
|
|
||||||
m.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
var c int
|
|
||||||
var u string
|
|
||||||
var t int
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.IntVar(&c, "c", 10, "concurrency num")
|
|
||||||
flag.StringVar(&u, "url", "http://127.0.0.1:8081", "test url")
|
|
||||||
flag.IntVar(&t, "t", 1, "request full site times")
|
|
||||||
flag.Parse()
|
|
||||||
if u == "" {
|
|
||||||
fmt.Println("url can't emtpy")
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
if c < 1 {
|
|
||||||
fmt.Println("concurrency num must >= 1")
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
if t < 1 {
|
|
||||||
for {
|
|
||||||
siteFetch(c, u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := 0; i < t; i++ {
|
|
||||||
siteFetch(c, u)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
|
|
||||||
func SearchLimit(num int64) func(ctx *gin.Context) {
|
func SearchLimit(num int64) func(ctx *gin.Context) {
|
||||||
fn, reFn := IpLimit(num)
|
fn, reFn := IpLimit(num)
|
||||||
reload.Push(func() {
|
reload.Append(func() {
|
||||||
reFn(config.GetConfig().SingleIpSearchNum)
|
reFn(config.GetConfig().SingleIpSearchNum)
|
||||||
})
|
}, "search-ip-limit-number")
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
if c.Query("s") != "" {
|
if c.Query("s") != "" {
|
||||||
fn(c)
|
fn(c)
|
||||||
|
|
|
@ -19,7 +19,7 @@ func ValidateServerNames() func(ctx *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
})
|
}, "site-names")
|
||||||
|
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
m := sites.Load()
|
m := sites.Load()
|
||||||
|
|
69
app/ossigns/signs.go
Normal file
69
app/ossigns/signs.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package ossigns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/fthvgb1/wp-go/app/mail"
|
||||||
|
"github.com/fthvgb1/wp-go/app/pkg/config"
|
||||||
|
"github.com/fthvgb1/wp-go/app/pkg/db"
|
||||||
|
"github.com/fthvgb1/wp-go/app/pkg/logs"
|
||||||
|
"github.com/fthvgb1/wp-go/app/plugins/wphandle"
|
||||||
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
|
"github.com/fthvgb1/wp-go/signs"
|
||||||
|
"log"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var confPath string
|
||||||
|
|
||||||
|
func SetConfPath(path string) {
|
||||||
|
confPath = path
|
||||||
|
}
|
||||||
|
|
||||||
|
func FlushCache() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err := mail.SendMail([]string{config.GetConfig().Mail.User}, "清空缓存失败", fmt.Sprintf("err:[%s]", r))
|
||||||
|
logs.IfError(err, "发邮件失败")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cachemanager.Flush()
|
||||||
|
log.Println("all cache flushed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Reloads() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.Println(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err := config.InitConfig(confPath)
|
||||||
|
logs.IfError(err, "获取配置文件失败", confPath)
|
||||||
|
err = logs.InitLogger()
|
||||||
|
logs.IfError(err, "日志配置错误")
|
||||||
|
_, err = db.InitDb()
|
||||||
|
logs.IfError(err, "重新读取db失败", config.GetConfig().Mysql)
|
||||||
|
err = wpconfig.InitOptions()
|
||||||
|
logs.IfError(err, "获取网站设置WpOption失败")
|
||||||
|
err = wpconfig.InitTerms()
|
||||||
|
logs.IfError(err, "获取WpTerms表失败")
|
||||||
|
wphandle.LoadPlugins()
|
||||||
|
reload.Reloads("themeArgAndConfig")
|
||||||
|
FlushCache()
|
||||||
|
log.Println("reload complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignalNotify() {
|
||||||
|
rel := func() bool {
|
||||||
|
go Reloads()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
flu := func() bool {
|
||||||
|
go FlushCache()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
signs.Install(syscall.SIGUSR1, rel, "reload")
|
||||||
|
signs.Install(syscall.SIGUSR2, flu, "flush")
|
||||||
|
signs.Wait()
|
||||||
|
}
|
6
app/pkg/cache/cache.go
vendored
6
app/pkg/cache/cache.go
vendored
|
@ -7,7 +7,7 @@ import (
|
||||||
"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/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -102,9 +102,9 @@ type Arch struct {
|
||||||
month time.Month
|
month time.Month
|
||||||
}
|
}
|
||||||
|
|
||||||
var arch = safety.NewVar(Arch{
|
var arch = reload.Vars(Arch{
|
||||||
fn: dao.Archives,
|
fn: dao.Archives,
|
||||||
})
|
}, "archives-year-month-data")
|
||||||
|
|
||||||
func Archives(ctx context.Context) []models.PostArchive {
|
func Archives(ctx context.Context) []models.PostArchive {
|
||||||
a := arch.Load()
|
a := arch.Load()
|
||||||
|
|
|
@ -85,6 +85,14 @@ type Mysql struct {
|
||||||
Pool Pool `yaml:"pool" json:"pool"`
|
Pool Pool `yaml:"pool" json:"pool"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetCustomizedConfig[T any]() (T, error) {
|
||||||
|
var r T
|
||||||
|
err := yaml.Unmarshal(fileData.Load(), &r)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileData = safety.NewVar([]byte{})
|
||||||
|
|
||||||
func InitConfig(conf string) error {
|
func InitConfig(conf string) error {
|
||||||
if conf == "" {
|
if conf == "" {
|
||||||
conf = "config.yaml"
|
conf = "config.yaml"
|
||||||
|
@ -96,6 +104,7 @@ func InitConfig(conf string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer get.Body.Close()
|
||||||
file, err = io.ReadAll(get.Body)
|
file, err = io.ReadAll(get.Body)
|
||||||
} else {
|
} else {
|
||||||
file, err = os.ReadFile(conf)
|
file, err = os.ReadFile(conf)
|
||||||
|
@ -103,6 +112,7 @@ func InitConfig(conf string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
fileData.Store(file)
|
||||||
var c Config
|
var c Config
|
||||||
err = yaml.Unmarshal(file, &c)
|
err = yaml.Unmarshal(file, &c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,6 +15,10 @@ import (
|
||||||
var safeDb = safety.NewVar[*sqlx.DB](nil)
|
var safeDb = safety.NewVar[*sqlx.DB](nil)
|
||||||
var showQuerySql func() bool
|
var showQuerySql func() bool
|
||||||
|
|
||||||
|
func GetSqlxDB() *sqlx.DB {
|
||||||
|
return safeDb.Load()
|
||||||
|
}
|
||||||
|
|
||||||
func InitDb() (*safety.Var[*sqlx.DB], error) {
|
func InitDb() (*safety.Var[*sqlx.DB], error) {
|
||||||
c := config.GetConfig()
|
c := config.GetConfig()
|
||||||
dsn := c.Mysql.Dsn.GetDsn()
|
dsn := c.Mysql.Dsn.GetDsn()
|
||||||
|
|
|
@ -15,20 +15,24 @@ var logs = safety.NewVar[*log.Logger](nil)
|
||||||
var logFile = safety.NewVar[*os.File](nil)
|
var logFile = safety.NewVar[*os.File](nil)
|
||||||
|
|
||||||
func InitLogger() error {
|
func InitLogger() error {
|
||||||
|
c := config.GetConfig()
|
||||||
|
return SetLogger(c.LogOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLogger(loggerFile string) error {
|
||||||
|
if loggerFile == "" {
|
||||||
|
loggerFile = "stderr"
|
||||||
|
}
|
||||||
preFD := logFile.Load()
|
preFD := logFile.Load()
|
||||||
l := &log.Logger{}
|
l := &log.Logger{}
|
||||||
c := config.GetConfig()
|
|
||||||
if c.LogOutput == "" {
|
|
||||||
c.LogOutput = "stderr"
|
|
||||||
}
|
|
||||||
var out io.Writer
|
var out io.Writer
|
||||||
switch c.LogOutput {
|
switch loggerFile {
|
||||||
case "stdout":
|
case "stdout":
|
||||||
out = os.Stdout
|
out = os.Stdout
|
||||||
case "stderr":
|
case "stderr":
|
||||||
out = os.Stderr
|
out = os.Stderr
|
||||||
default:
|
default:
|
||||||
file, err := os.OpenFile(c.LogOutput, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0777)
|
file, err := os.OpenFile(loggerFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ type Comments struct {
|
||||||
CommentParent uint64 `gorm:"column:comment_parent" db:"comment_parent" json:"comment_parent" form:"comment_parent"`
|
CommentParent uint64 `gorm:"column:comment_parent" db:"comment_parent" json:"comment_parent" form:"comment_parent"`
|
||||||
UserId uint64 `gorm:"column:user_id" db:"user_id" json:"user_id" form:"user_id"`
|
UserId uint64 `gorm:"column:user_id" db:"user_id" json:"user_id" form:"user_id"`
|
||||||
//扩展字段
|
//扩展字段
|
||||||
PostTitle string `db:"post_title"`
|
PostTitle string `db:"post_title"`
|
||||||
|
UpdateTime time.Time `gorm:"update_time" form:"update_time" json:"update_time" db:"update_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Comments) PrimaryKey() string {
|
func (w Comments) PrimaryKey() string {
|
||||||
|
|
|
@ -6,14 +6,16 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/config"
|
"github.com/fthvgb1/wp-go/app/pkg/config"
|
||||||
"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/theme/wp"
|
"github.com/fthvgb1/wp-go/app/theme/wp"
|
||||||
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"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/helper/strings"
|
"github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"strconv"
|
"strconv"
|
||||||
strings2 "strings"
|
str "strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,7 +59,6 @@ func (r *RdmCache[K, V]) Set(ctx context.Context, key K, val V) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(result, err)
|
fmt.Println(result, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RdmCache[K, V]) GetExpireTime(ctx context.Context) time.Duration {
|
func (r *RdmCache[K, V]) GetExpireTime(ctx context.Context) time.Duration {
|
||||||
|
@ -73,7 +74,7 @@ func (r *RdmCache[K, V]) Ttl(ctx context.Context, key K) time.Duration {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RdmCache[K, V]) Flush(ctx context.Context) {
|
func (r *RdmCache[K, V]) Flush(ctx context.Context) {
|
||||||
|
fmt.Println("flush redis cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RdmCache[K, V]) Del(ctx context.Context, key ...K) {
|
func (r *RdmCache[K, V]) Del(ctx context.Context, key ...K) {
|
||||||
|
@ -81,12 +82,13 @@ func (r *RdmCache[K, V]) Del(ctx context.Context, key ...K) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RdmCache[K, V]) ClearExpired(ctx context.Context) {
|
func (r *RdmCache[K, V]) ClearExpired(ctx context.Context) {
|
||||||
|
fmt.Println("clear expired redis cache")
|
||||||
}
|
}
|
||||||
// use step:
|
|
||||||
//1 go build -gcflags all="-N -l" --race -buildmode=plugin -o redisCache.so main.go && cp ./redisCache.so wp-go/plugins/
|
// RedisCache use step:
|
||||||
//2 wp-go config add redisCache plugin
|
// 1 go build -gcflags all="-N -l" --race -buildmode=plugin -o redisCache.so main.go && cp ./redisCache.so ../wp-go/plugins/
|
||||||
func Re(h *wp.Handle) {
|
// 2 wp-go config add redisCache plugin
|
||||||
|
func RedisCache(h *wp.Handle) {
|
||||||
vv, ok := cachemanager.GetMapCache[string, dao.PostIds]("listPostIds")
|
vv, ok := cachemanager.GetMapCache[string, dao.PostIds]("listPostIds")
|
||||||
if ok {
|
if ok {
|
||||||
_, ok := any(vv.Cache).(*RdmCache[string, dao.PostIds])
|
_, ok := any(vv.Cache).(*RdmCache[string, dao.PostIds])
|
||||||
|
@ -94,6 +96,16 @@ func Re(h *wp.Handle) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reload.AppendOnceFn(func() {
|
||||||
|
err := cachemanager.SetMapCache("listPostIds", vv)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err, "set recovery listPostIds cache err")
|
||||||
|
} else {
|
||||||
|
cachemanager.PushOrSetFlush(cachemanager.Queue{Name: "listPostIds", Fn: vv.Flush})
|
||||||
|
cachemanager.PushOrSetClearExpired(cachemanager.Queue{Name: "listPostIds", Fn: vv.Flush})
|
||||||
|
fmt.Println("recovery listPostIds cache ok")
|
||||||
|
}
|
||||||
|
})
|
||||||
rdm := redis.NewClient(&redis.Options{
|
rdm := redis.NewClient(&redis.Options{
|
||||||
Addr: "localhost:6379",
|
Addr: "localhost:6379",
|
||||||
Password: "", // no password set
|
Password: "", // no password set
|
||||||
|
@ -110,14 +122,14 @@ func Re(h *wp.Handle) {
|
||||||
name: "",
|
name: "",
|
||||||
resFn: func(m map[string]string) dao.PostIds {
|
resFn: func(m map[string]string) dao.PostIds {
|
||||||
return dao.PostIds{
|
return dao.PostIds{
|
||||||
Ids: slice.Map(strings2.Split(m["ids"], ","), strings.ToInt[uint64]),
|
Ids: slice.Map(str.Split(m["ids"], ","), strings.ToInt[uint64]),
|
||||||
Length: strings.ToInt[int](m["length"]),
|
Length: strings.ToInt[int](m["length"]),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveData: func(ids dao.PostIds) map[string]string {
|
saveData: func(ids dao.PostIds) map[string]string {
|
||||||
t := slice.Map(ids.Ids, number.IntToString[uint64])
|
t := slice.Map(ids.Ids, number.IntToString[uint64])
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
"ids": strings2.Join(t, ","),
|
"ids": str.Join(t, ","),
|
||||||
"length": strconv.Itoa(ids.Length),
|
"length": strconv.Itoa(ids.Length),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,10 +4,15 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/config"
|
"github.com/fthvgb1/wp-go/app/pkg/config"
|
||||||
|
"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/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/maps"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/fthvgb1/wp-go/plugin/digest"
|
"github.com/fthvgb1/wp-go/plugin/digest"
|
||||||
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -18,10 +23,106 @@ var more = regexp.MustCompile("<!--more(.*?)?-->")
|
||||||
|
|
||||||
var removeWpBlock = regexp.MustCompile("<!-- /?wp:.*-->")
|
var removeWpBlock = regexp.MustCompile("<!-- /?wp:.*-->")
|
||||||
|
|
||||||
|
type DigestConfig struct {
|
||||||
|
DigestWordCount int `yaml:"digestWordCount"`
|
||||||
|
DigestAllowTag string `yaml:"digestAllowTag"`
|
||||||
|
DigestRegex string `yaml:"digestRegex"`
|
||||||
|
DigestTagOccupyNum []struct {
|
||||||
|
Tag string `yaml:"tag"`
|
||||||
|
Num int `yaml:"num"`
|
||||||
|
ChuckOvered bool `yaml:"chuckOvered"`
|
||||||
|
EscapeCharacter []struct {
|
||||||
|
Tags string `yaml:"tags"`
|
||||||
|
Character []string `yaml:"character"`
|
||||||
|
Num int `yaml:"num"`
|
||||||
|
ChuckOvered bool `yaml:"chuckOvered"`
|
||||||
|
} `yaml:"escapeCharacter"`
|
||||||
|
} `yaml:"digestTagOccupyNum"`
|
||||||
|
specialSolve map[string]digest.SpecialSolveConf
|
||||||
|
}
|
||||||
|
|
||||||
|
var digestConfig *safety.Var[DigestConfig]
|
||||||
|
|
||||||
func InitDigestCache() {
|
func InitDigestCache() {
|
||||||
cachemanager.NewMemoryMapCache(nil, digestRaw, config.GetConfig().CacheTime.DigestCacheTime, "digestPlugin", func() time.Duration {
|
cachemanager.NewMemoryMapCache(nil, digestRaw, config.GetConfig().CacheTime.DigestCacheTime, "digestPlugin", func() time.Duration {
|
||||||
return config.GetConfig().CacheTime.DigestCacheTime
|
return config.GetConfig().CacheTime.DigestCacheTime
|
||||||
})
|
})
|
||||||
|
|
||||||
|
digestConfig = reload.VarsBy(func() DigestConfig {
|
||||||
|
c, err := config.GetCustomizedConfig[DigestConfig]()
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err, "get digest config fail")
|
||||||
|
c.DigestWordCount = config.GetConfig().DigestWordCount
|
||||||
|
c.DigestAllowTag = config.GetConfig().DigestAllowTag
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c.DigestRegex != "" {
|
||||||
|
digest.SetQutos(c.DigestRegex)
|
||||||
|
}
|
||||||
|
if len(c.DigestTagOccupyNum) <= 1 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c.specialSolve = ParseDigestConf(c)
|
||||||
|
return c
|
||||||
|
}, "digestConfig")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseDigestConf(c DigestConfig) map[string]digest.SpecialSolveConf {
|
||||||
|
specialSolve := map[string]digest.SpecialSolveConf{}
|
||||||
|
for _, item := range c.DigestTagOccupyNum {
|
||||||
|
tags := strings.Split(strings.ReplaceAll(item.Tag, " ", ""), "<")
|
||||||
|
for _, tag := range tags {
|
||||||
|
if tag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ec := make(map[rune]digest.SpecialSolve)
|
||||||
|
specialTags := make(map[string]digest.SpecialSolve)
|
||||||
|
tag = str.Join("<", tag)
|
||||||
|
if len(item.EscapeCharacter) > 0 {
|
||||||
|
for _, esc := range item.EscapeCharacter {
|
||||||
|
for _, i := range esc.Character {
|
||||||
|
s := []rune(i)
|
||||||
|
if len(s) == 1 {
|
||||||
|
ec[s[0]] = digest.SpecialSolve{
|
||||||
|
Num: esc.Num,
|
||||||
|
ChuckOvered: esc.ChuckOvered,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if esc.Tags == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tagss := strings.Split(strings.ReplaceAll(esc.Tags, " ", ""), "<")
|
||||||
|
for _, t := range tagss {
|
||||||
|
if t == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
t = str.Join("<", t)
|
||||||
|
specialTags[t] = digest.SpecialSolve{
|
||||||
|
Num: esc.Num,
|
||||||
|
ChuckOvered: esc.ChuckOvered,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v, ok := specialSolve[tag]
|
||||||
|
if !ok {
|
||||||
|
specialSolve[tag] = digest.SpecialSolveConf{
|
||||||
|
Num: item.Num,
|
||||||
|
ChuckOvered: item.ChuckOvered,
|
||||||
|
EscapeCharacter: ec,
|
||||||
|
Tags: specialTags,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.Num = item.Num
|
||||||
|
v.ChuckOvered = item.ChuckOvered
|
||||||
|
v.EscapeCharacter = maps.Merge(v.EscapeCharacter, ec)
|
||||||
|
v.Tags = maps.Merge(v.Tags, specialTags)
|
||||||
|
specialSolve[tag] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return specialSolve
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveWpBlock(s string) string {
|
func RemoveWpBlock(s string) string {
|
||||||
|
@ -45,7 +146,8 @@ func digestRaw(ctx context.Context, id uint64, arg ...any) (string, error) {
|
||||||
func Digests(content string, id uint64, limit int, fn func(id uint64, content, closeTag string) string) string {
|
func Digests(content string, id uint64, limit int, fn func(id uint64, content, closeTag string) string) string {
|
||||||
closeTag := ""
|
closeTag := ""
|
||||||
content = RemoveWpBlock(content)
|
content = RemoveWpBlock(content)
|
||||||
tag := config.GetConfig().DigestAllowTag
|
c := digestConfig.Load()
|
||||||
|
tag := c.DigestAllowTag
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = "<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>"
|
tag = "<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>"
|
||||||
}
|
}
|
||||||
|
@ -54,7 +156,12 @@ func Digests(content string, id uint64, limit int, fn func(id uint64, content, c
|
||||||
if length <= limit {
|
if length <= limit {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
content, closeTag = digest.Html(content, limit)
|
if len(c.specialSolve) > 0 {
|
||||||
|
content, closeTag = digest.CustomizeHtml(content, limit, c.specialSolve)
|
||||||
|
} else {
|
||||||
|
content, closeTag = digest.Html(content, limit)
|
||||||
|
}
|
||||||
|
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
return PostsMore(id, content, closeTag)
|
return PostsMore(id, content, closeTag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,10 +62,6 @@ func (p PageEle) Dots() string {
|
||||||
return p.DotsEle
|
return p.DotsEle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PageEle) Step() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p PageEle) Middle(page int, url string) string {
|
func (p PageEle) Middle(page int, url string) string {
|
||||||
return fmt.Sprintf(p.MiddleEle, url, page)
|
return fmt.Sprintf(p.MiddleEle, url, page)
|
||||||
}
|
}
|
||||||
|
@ -142,10 +138,6 @@ func (p CommentPageEle) Prev(url string) string {
|
||||||
return fmt.Sprintf(p.PrevEle, url, helper.Or(wpconfig.GetOption("comment_order") == "asc", "较早评论", "较新评论"))
|
return fmt.Sprintf(p.PrevEle, url, helper.Or(wpconfig.GetOption("comment_order") == "asc", "较早评论", "较新评论"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p CommentPageEle) Step() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p CommentPageEle) Next(url string) string {
|
func (p CommentPageEle) Next(url string) string {
|
||||||
return fmt.Sprintf(p.NextEle, url, helper.Or(wpconfig.GetOption("comment_order") == "asc", "较新评论", "较早评论"))
|
return fmt.Sprintf(p.NextEle, url, helper.Or(wpconfig.GetOption("comment_order") == "asc", "较新评论", "较早评论"))
|
||||||
}
|
}
|
||||||
|
@ -157,7 +149,6 @@ type PaginationNav struct {
|
||||||
Dotss func() string
|
Dotss func() string
|
||||||
Middles func(page int, url string) string
|
Middles func(page int, url string) string
|
||||||
Urlss func(u url.URL, page int, isTLS bool) string
|
Urlss func(u url.URL, page int, isTLS bool) string
|
||||||
Steps func() int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PaginationNav) Current(page, totalPage, totalRows int) string {
|
func (p PaginationNav) Current(page, totalPage, totalRows int) string {
|
||||||
|
@ -183,7 +174,3 @@ func (p PaginationNav) Middle(page int, url string) string {
|
||||||
func (p PaginationNav) Urls(u url.URL, page int, isTLS bool) string {
|
func (p PaginationNav) Urls(u url.URL, page int, isTLS bool) string {
|
||||||
return p.Urlss(u, page, isTLS)
|
return p.Urlss(u, page, isTLS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PaginationNav) Step() int {
|
|
||||||
return p.Steps()
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,12 +2,29 @@ package apply
|
||||||
|
|
||||||
import "github.com/fthvgb1/wp-go/safety"
|
import "github.com/fthvgb1/wp-go/safety"
|
||||||
|
|
||||||
var fn safety.Var[any]
|
var contains = safety.NewMap[string, any]()
|
||||||
|
|
||||||
func SetFn(f any) {
|
func SetVal(key string, val any) {
|
||||||
fn.Store(f)
|
contains.Store(key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UsePlugins() any {
|
func DelVal(key string) {
|
||||||
return fn.Load()
|
contains.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVal[V any](key string) (V, bool) {
|
||||||
|
v, ok := contains.Load(key)
|
||||||
|
if !ok {
|
||||||
|
var vv V
|
||||||
|
return vv, ok
|
||||||
|
}
|
||||||
|
return v.(V), ok
|
||||||
|
}
|
||||||
|
func GetRawVal(key string) (any, bool) {
|
||||||
|
return contains.Load(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlugins() any {
|
||||||
|
v, _ := contains.Load("wp-plugins")
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Options struct {
|
||||||
Linehover bool `json:"linehover,omitempty"`
|
Linehover bool `json:"linehover,omitempty"`
|
||||||
RawcodeDbclick bool `json:"rawcodeDbclick,omitempty"`
|
RawcodeDbclick bool `json:"rawcodeDbclick,omitempty"`
|
||||||
TextOverflow string `json:"textOverflow,omitempty"`
|
TextOverflow string `json:"textOverflow,omitempty"`
|
||||||
Linenumbers int64 `json:"linenumbers,omitempty"`
|
Linenumbers bool `json:"linenumbers,omitempty"`
|
||||||
Theme string `json:"theme,omitempty"`
|
Theme string `json:"theme,omitempty"`
|
||||||
Language string `json:"language,omitempty"`
|
Language string `json:"language,omitempty"`
|
||||||
RetainCssClasses bool `json:"retainCssClasses,omitempty"`
|
RetainCssClasses bool `json:"retainCssClasses,omitempty"`
|
||||||
|
@ -58,7 +58,7 @@ func EnlighterJS(h *wp.Handle) {
|
||||||
Linehover: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-linehover", true),
|
Linehover: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-linehover", true),
|
||||||
RawcodeDbclick: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-rawcodedbclick", true),
|
RawcodeDbclick: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-rawcodedbclick", true),
|
||||||
TextOverflow: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-textoverflow", "break"),
|
TextOverflow: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-textoverflow", "break"),
|
||||||
Linenumbers: maps.GetStrAnyValWithDefaults[int64](opp, "enlighterjs-linenumbers", 1),
|
Linenumbers: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-linenumbers", true),
|
||||||
Theme: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-theme", "enlighter"),
|
Theme: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-theme", "enlighter"),
|
||||||
Language: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-language", "generic"),
|
Language: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-language", "generic"),
|
||||||
RetainCssClasses: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-retaincss", false),
|
RetainCssClasses: maps.GetStrAnyValWithDefaults(opp, "enlighterjs-retaincss", false),
|
||||||
|
|
|
@ -66,7 +66,7 @@ func LoadPlugins() {
|
||||||
}
|
}
|
||||||
RegisterPlugin(name, plu)
|
RegisterPlugin(name, plu)
|
||||||
}
|
}
|
||||||
apply.SetFn(func(h *wp.Handle) {
|
apply.SetVal("wp-plugins", func(h *wp.Handle) {
|
||||||
UsePlugins(h)
|
UsePlugins(h)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/app/theme"
|
"github.com/fthvgb1/wp-go/app/theme"
|
||||||
"github.com/fthvgb1/wp-go/app/wpconfig"
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/gin-contrib/gzip"
|
"github.com/gin-contrib/gzip"
|
||||||
"github.com/gin-contrib/pprof"
|
"github.com/gin-contrib/pprof"
|
||||||
|
@ -16,11 +18,26 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var hooker []func(r *gin.Engine)
|
type GinSetter func(*gin.Engine)
|
||||||
|
|
||||||
// Hook 方便插件在init时使用
|
var setters mockmap.Map[string, GinSetter]
|
||||||
func Hook(fn ...func(r *gin.Engine)) {
|
|
||||||
hooker = append(hooker, fn...)
|
var setterHooks []func(item mockmap.Item[string, GinSetter]) (mockmap.Item[string, GinSetter], bool)
|
||||||
|
|
||||||
|
// SetGinAction 方便插件在init时使用
|
||||||
|
func SetGinAction(name string, hook GinSetter, orders ...float64) {
|
||||||
|
setters.Set(name, hook, orders...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HookGinSetter(fn func(item mockmap.Item[string, GinSetter]) (mockmap.Item[string, GinSetter], bool)) {
|
||||||
|
setterHooks = append(setterHooks, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelGinSetter 方便插件在init时使用
|
||||||
|
func DelGinSetter(name string) {
|
||||||
|
setterHooks = append(setterHooks, func(item mockmap.Item[string, GinSetter]) (mockmap.Item[string, GinSetter], bool) {
|
||||||
|
return item, item.Name != name
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupRouter() *gin.Engine {
|
func SetupRouter() *gin.Engine {
|
||||||
|
@ -28,72 +45,103 @@ func SetupRouter() *gin.Engine {
|
||||||
// gin.DisableConsoleColor()
|
// gin.DisableConsoleColor()
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
c := config.GetConfig()
|
c := config.GetConfig()
|
||||||
if len(c.TrustIps) > 0 {
|
SetGinAction("initTrustIp", func(r *gin.Engine) {
|
||||||
err := r.SetTrustedProxies(c.TrustIps)
|
if len(c.TrustIps) > 0 {
|
||||||
if err != nil {
|
err := r.SetTrustedProxies(c.TrustIps)
|
||||||
panic(err)
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}, 99.5)
|
||||||
|
|
||||||
|
SetGinAction("setTemplate", func(r *gin.Engine) {
|
||||||
|
r.HTMLRender = theme.BuildTemplate()
|
||||||
|
wpconfig.SetTemplateFs(theme.TemplateFs)
|
||||||
|
}, 90.5)
|
||||||
|
|
||||||
r.HTMLRender = theme.Template()
|
|
||||||
wpconfig.SetTemplateFs(theme.TemplateFs)
|
|
||||||
siteFlowLimitMiddleware, siteFlow := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
|
siteFlowLimitMiddleware, siteFlow := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
|
||||||
r.Use(
|
reload.Append(func() {
|
||||||
gin.Logger(),
|
c = config.GetConfig()
|
||||||
middleware.ValidateServerNames(),
|
|
||||||
middleware.RecoverAndSendMail(gin.DefaultErrorWriter),
|
|
||||||
siteFlowLimitMiddleware,
|
|
||||||
middleware.SetStaticFileCache,
|
|
||||||
)
|
|
||||||
//gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用
|
|
||||||
if c.Gzip {
|
|
||||||
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{
|
|
||||||
"/wp-includes/", "/wp-content/",
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.WpDir == "" {
|
|
||||||
panic("wordpress path can't be empty")
|
|
||||||
}
|
|
||||||
r.Static("/wp-content/uploads", str.Join(c.WpDir, "/wp-content/uploads"))
|
|
||||||
r.Static("/wp-content/themes", str.Join(c.WpDir, "/wp-content/themes"))
|
|
||||||
r.Static("/wp-content/plugins", str.Join(c.WpDir, "/wp-content/plugins"))
|
|
||||||
r.Static("/wp-includes/css", str.Join(c.WpDir, "/wp-includes/css"))
|
|
||||||
r.Static("/wp-includes/fonts", str.Join(c.WpDir, "/wp-includes/fonts"))
|
|
||||||
r.Static("/wp-includes/js", str.Join(c.WpDir, "/wp-includes/js"))
|
|
||||||
|
|
||||||
store := cookie.NewStore([]byte("secret"))
|
|
||||||
r.Use(sessions.Sessions("go-wp", store))
|
|
||||||
r.GET("/", actions.Feed, middleware.SearchLimit(c.SingleIpSearchNum),
|
|
||||||
actions.ThemeHook(constraints.Home))
|
|
||||||
r.GET("/page/:page", actions.ThemeHook(constraints.Home))
|
|
||||||
r.GET("/p/category/:category", actions.ThemeHook(constraints.Category))
|
|
||||||
r.GET("/p/category/:category/page/:page", actions.ThemeHook(constraints.Category))
|
|
||||||
r.GET("/p/tag/:tag", actions.ThemeHook(constraints.Tag))
|
|
||||||
r.GET("/p/tag/:tag/page/:page", actions.ThemeHook(constraints.Tag))
|
|
||||||
r.GET("/p/date/:year/:month", actions.ThemeHook(constraints.Archive))
|
|
||||||
r.GET("/p/date/:year/:month/page/:page", actions.ThemeHook(constraints.Archive))
|
|
||||||
r.GET("/p/author/:author", actions.ThemeHook(constraints.Author))
|
|
||||||
r.GET("/p/author/:author/page/:page", actions.ThemeHook(constraints.Author))
|
|
||||||
r.POST("/login", actions.Login)
|
|
||||||
r.GET("/p/:id", actions.ThemeHook(constraints.Detail))
|
|
||||||
r.GET("/p/:id/comment-page-:page", actions.ThemeHook(constraints.Detail))
|
|
||||||
r.GET("/p/:id/feed", actions.PostFeed)
|
|
||||||
r.GET("/feed", actions.SiteFeed)
|
|
||||||
r.GET("/comments/feed", actions.CommentsFeed)
|
|
||||||
//r.NoRoute(actions.ThemeHook(constraints.NoRoute))
|
|
||||||
commentMiddleWare, _ := middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.CacheTime.SleepTime)
|
|
||||||
r.POST("/comment", commentMiddleWare, actions.PostComment)
|
|
||||||
if c.Pprof != "" {
|
|
||||||
pprof.Register(r, c.Pprof)
|
|
||||||
}
|
|
||||||
for _, fn := range hooker {
|
|
||||||
fn(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
reload.Push(func() {
|
|
||||||
c := config.GetConfig()
|
|
||||||
siteFlow(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
|
siteFlow(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
|
||||||
|
}, "site-flowLimit-config")
|
||||||
|
|
||||||
|
SetGinAction("setGlobalMiddleware", func(r *gin.Engine) {
|
||||||
|
r.Use(
|
||||||
|
gin.Logger(),
|
||||||
|
middleware.ValidateServerNames(),
|
||||||
|
middleware.RecoverAndSendMail(gin.DefaultErrorWriter),
|
||||||
|
siteFlowLimitMiddleware,
|
||||||
|
middleware.SetStaticFileCache,
|
||||||
|
)
|
||||||
|
}, 88.5)
|
||||||
|
|
||||||
|
SetGinAction("setGzip", func(r *gin.Engine) {
|
||||||
|
//gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用
|
||||||
|
if c.Gzip {
|
||||||
|
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{
|
||||||
|
"/wp-includes/", "/wp-content/",
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}, 87.6)
|
||||||
|
|
||||||
|
SetGinAction("setWpDir", func(r *gin.Engine) {
|
||||||
|
if c.WpDir == "" {
|
||||||
|
panic("wordpress path can't be empty")
|
||||||
|
}
|
||||||
|
r.Static("/wp-content/uploads", str.Join(c.WpDir, "/wp-content/uploads"))
|
||||||
|
r.Static("/wp-content/themes", str.Join(c.WpDir, "/wp-content/themes"))
|
||||||
|
r.Static("/wp-content/plugins", str.Join(c.WpDir, "/wp-content/plugins"))
|
||||||
|
r.Static("/wp-includes/css", str.Join(c.WpDir, "/wp-includes/css"))
|
||||||
|
r.Static("/wp-includes/fonts", str.Join(c.WpDir, "/wp-includes/fonts"))
|
||||||
|
r.Static("/wp-includes/js", str.Join(c.WpDir, "/wp-includes/js"))
|
||||||
|
}, 86.1)
|
||||||
|
|
||||||
|
SetGinAction("setSession", func(r *gin.Engine) {
|
||||||
|
store := cookie.NewStore([]byte("secret"))
|
||||||
|
r.Use(sessions.Sessions("go-wp", store))
|
||||||
|
}, 85.1)
|
||||||
|
|
||||||
|
SetGinAction("setRoute", func(r *gin.Engine) {
|
||||||
|
r.GET("/", actions.Feed, middleware.SearchLimit(c.SingleIpSearchNum),
|
||||||
|
actions.ThemeHook(constraints.Home))
|
||||||
|
r.GET("/page/:page", actions.ThemeHook(constraints.Home))
|
||||||
|
r.GET("/p/category/:category", actions.ThemeHook(constraints.Category))
|
||||||
|
r.GET("/p/category/:category/page/:page", actions.ThemeHook(constraints.Category))
|
||||||
|
r.GET("/p/tag/:tag", actions.ThemeHook(constraints.Tag))
|
||||||
|
r.GET("/p/tag/:tag/page/:page", actions.ThemeHook(constraints.Tag))
|
||||||
|
r.GET("/p/date/:year/:month", actions.ThemeHook(constraints.Archive))
|
||||||
|
r.GET("/p/date/:year/:month/page/:page", actions.ThemeHook(constraints.Archive))
|
||||||
|
r.GET("/p/author/:author", actions.ThemeHook(constraints.Author))
|
||||||
|
r.GET("/p/author/:author/page/:page", actions.ThemeHook(constraints.Author))
|
||||||
|
r.POST("/login", actions.Login)
|
||||||
|
r.GET("/p/:id", actions.ThemeHook(constraints.Detail))
|
||||||
|
r.GET("/p/:id/comment-page-:page", actions.ThemeHook(constraints.Detail))
|
||||||
|
r.GET("/p/:id/feed", actions.PostFeed)
|
||||||
|
r.GET("/feed", actions.SiteFeed)
|
||||||
|
r.GET("/comments/feed", actions.CommentsFeed)
|
||||||
|
commentMiddleWare, _ := middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.CacheTime.SleepTime)
|
||||||
|
r.POST("/comment", commentMiddleWare, actions.PostComment)
|
||||||
|
|
||||||
|
r.NoRoute(actions.ThemeHook(constraints.NoRoute))
|
||||||
|
}, 84.6)
|
||||||
|
|
||||||
|
SetGinAction("setpprof", func(r *gin.Engine) {
|
||||||
|
if c.Pprof != "" {
|
||||||
|
pprof.Register(r, c.Pprof)
|
||||||
|
}
|
||||||
|
}, 80.8)
|
||||||
|
|
||||||
|
for _, hook := range setterHooks {
|
||||||
|
setters = slice.FilterAndMap(setters, hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
slice.SimpleSort(setters, slice.DESC, func(t mockmap.Item[string, GinSetter]) float64 {
|
||||||
|
return t.Order
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for _, fn := range setters {
|
||||||
|
fn.Value(r)
|
||||||
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package theme
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"github.com/fthvgb1/wp-go/multipTemplate"
|
"github.com/fthvgb1/wp-go/multipTemplate"
|
||||||
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -12,20 +13,36 @@ import (
|
||||||
//go:embed *[^.go]
|
//go:embed *[^.go]
|
||||||
var TemplateFs embed.FS
|
var TemplateFs embed.FS
|
||||||
|
|
||||||
var templates map[string]*template.Template //方便外部获取模板render后的字符串,不然在gin中获取不了
|
var templates = safety.NewMap[string, *template.Template]() //方便外部获取模板render后的字符串,不然在gin中获取不了
|
||||||
|
|
||||||
func Template() *multipTemplate.MultipleFsTemplate {
|
var multiple *multipTemplate.MultipleFsTemplate
|
||||||
t := multipTemplate.NewFsTemplate(TemplateFs)
|
|
||||||
templates = t.Template
|
func BuildTemplate() *multipTemplate.MultipleFsTemplate {
|
||||||
t.FuncMap = FuncMap()
|
if multiple != nil {
|
||||||
commonTemplate(t)
|
tt := multipTemplate.NewFsTemplate(TemplateFs)
|
||||||
/*t.AddTemplate("twentyfifteen/*[^layout]/*.gohtml", FuncMap(), "twentyfifteen/layout/*.gohtml"). //单个主题设置
|
commonTemplate(tt)
|
||||||
AddTemplate("twentyseventeen/*[^layout]/*.gohtml", FuncMap(), "twentyseventeen/layout/*.gohtml")*/
|
for k, v := range map[string]*template.Template(any(tt.Template).(multipTemplate.TemplateMaps)) {
|
||||||
return t
|
multiple.Template.Store(k, v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
multiple = multipTemplate.NewFsTemplates(TemplateFs, templates)
|
||||||
|
commonTemplate(multiple)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*t.AddTemplate("twentyfifteen/*[^layout]/*.gohtml", FuncMap(), "twentyfifteen/layout/*.gohtml","wp/template.gohtml"). //单个主题设置
|
||||||
|
AddTemplate("twentyseventeen/*[^layout]/*.gohtml", FuncMap(), "twentyseventeen/layout/*.gohtml","wp/template.gohtml")*/
|
||||||
|
return multiple
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMultipleTemplate() *multipTemplate.MultipleFsTemplate {
|
||||||
|
if multiple == nil {
|
||||||
|
BuildTemplate()
|
||||||
|
}
|
||||||
|
return multiple
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTemplate(name string) (*template.Template, bool) {
|
func GetTemplate(name string) (*template.Template, bool) {
|
||||||
t, ok := templates[name]
|
t, ok := templates.Load(name)
|
||||||
return t, ok
|
return t, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +52,11 @@ func commonTemplate(t *multipTemplate.MultipleFsTemplate) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
funMap := FuncMap()
|
||||||
for _, main := range m {
|
for _, main := range m {
|
||||||
file := filepath.Base(main)
|
file := filepath.Base(main)
|
||||||
dir := strings.Split(main, "/")[0]
|
dir := strings.Split(main, "/")[0]
|
||||||
templ := template.Must(template.New(file).Funcs(t.FuncMap).ParseFS(t.Fs, main, filepath.Join(dir, "layout/*.gohtml"), "wp/template.gohtml"))
|
templ := template.Must(template.New(file).Funcs(funMap).ParseFS(t.Fs, main, filepath.Join(dir, "layout/*.gohtml"), "wp/template.gohtml"))
|
||||||
t.SetTemplate(main, templ)
|
t.SetTemplate(main, templ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +73,10 @@ func IsTemplateDirExists(tml string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsTemplateExists(tml string) bool {
|
func IsTemplateExists(tml string) bool {
|
||||||
t, ok := templates[tml]
|
t, ok := templates.Load(tml)
|
||||||
return ok && t != nil
|
return ok && t != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetTemplate(name string, val *template.Template) {
|
||||||
|
templates.Store(name, val)
|
||||||
|
}
|
||||||
|
|
|
@ -8,13 +8,18 @@ import (
|
||||||
|
|
||||||
var themeMap = safety.NewMap[string, func(*wp.Handle)]()
|
var themeMap = safety.NewMap[string, func(*wp.Handle)]()
|
||||||
|
|
||||||
func AddThemeHookFunc(name string, fn func(handle *wp.Handle)) {
|
func AddTheme(name string, fn func(handle *wp.Handle)) {
|
||||||
if _, ok := themeMap.Load(name); ok {
|
|
||||||
panic("exists same name theme")
|
|
||||||
}
|
|
||||||
themeMap.Store(name, fn)
|
themeMap.Store(name, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DelTheme(name string) {
|
||||||
|
themeMap.Delete(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTheme(name string) (func(*wp.Handle), bool) {
|
||||||
|
return themeMap.Load(name)
|
||||||
|
}
|
||||||
|
|
||||||
func IsThemeHookFuncExist(name string) bool {
|
func IsThemeHookFuncExist(name string) bool {
|
||||||
_, ok := themeMap.Load(name)
|
_, ok := themeMap.Load(name)
|
||||||
return ok
|
return ok
|
||||||
|
|
|
@ -7,40 +7,31 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var comFn = template.FuncMap{
|
|
||||||
"unescaped": func(s string) any {
|
|
||||||
return template.HTML(s)
|
|
||||||
},
|
|
||||||
"dateCh": func(t time.Time) any {
|
|
||||||
return t.Format("2006年 01月 02日")
|
|
||||||
},
|
|
||||||
"timeFormat": func(t time.Time, format string) any {
|
|
||||||
return t.Format(format)
|
|
||||||
},
|
|
||||||
"getOption": func(k string) string {
|
|
||||||
return wpconfig.GetOption(k)
|
|
||||||
},
|
|
||||||
"getLang": wpconfig.GetLang,
|
|
||||||
"postsFn": postsFn,
|
|
||||||
"exec": func(fn func() string) template.HTML {
|
|
||||||
return template.HTML(fn())
|
|
||||||
},
|
|
||||||
"callFuncString": func(fn func(string) string, s string) template.HTML {
|
|
||||||
return template.HTML(fn(s))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func postsFn(fn func(models.Posts) string, a models.Posts) string {
|
func postsFn(fn func(models.Posts) string, a models.Posts) string {
|
||||||
return fn(a)
|
return fn(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FuncMap() template.FuncMap {
|
func FuncMap() template.FuncMap {
|
||||||
return comFn
|
return template.FuncMap{
|
||||||
}
|
"unescaped": func(s string) any {
|
||||||
|
return template.HTML(s)
|
||||||
func addTemplateFunc(fnName string, fn any) {
|
},
|
||||||
if _, ok := comFn[fnName]; ok {
|
"dateCh": func(t time.Time) any {
|
||||||
panic("exists same name func")
|
return t.Format("2006年 01月 02日")
|
||||||
|
},
|
||||||
|
"timeFormat": func(t time.Time, format string) any {
|
||||||
|
return t.Format(format)
|
||||||
|
},
|
||||||
|
"getOption": func(k string) string {
|
||||||
|
return wpconfig.GetOption(k)
|
||||||
|
},
|
||||||
|
"getLang": wpconfig.GetLang,
|
||||||
|
"postsFn": postsFn,
|
||||||
|
"exec": func(fn func() string) template.HTML {
|
||||||
|
return template.HTML(fn())
|
||||||
|
},
|
||||||
|
"callFuncString": func(fn func(string) string, s string) template.HTML {
|
||||||
|
return template.HTML(fn(s))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
comFn[fnName] = fn
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitTheme() {
|
func InitTheme() {
|
||||||
AddThemeHookFunc(twentyfifteen.ThemeName, twentyfifteen.Hook)
|
AddTheme(twentyfifteen.ThemeName, twentyfifteen.Hook)
|
||||||
AddThemeHookFunc(twentyseventeen.ThemeName, twentyseventeen.Hook)
|
AddTheme(twentyseventeen.ThemeName, twentyseventeen.Hook)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCurrentTemplateName() string {
|
func GetCurrentTheme() string {
|
||||||
tmlp := config.GetConfig().Theme
|
themeName := config.GetConfig().Theme
|
||||||
if tmlp == "" {
|
if themeName == "" {
|
||||||
tmlp = wpconfig.GetOption("template")
|
themeName = wpconfig.GetOption("template")
|
||||||
}
|
}
|
||||||
if !IsTemplateDirExists(tmlp) {
|
if !IsTemplateDirExists(themeName) {
|
||||||
tmlp = "twentyfifteen"
|
themeName = "twentyfifteen"
|
||||||
}
|
}
|
||||||
return tmlp
|
return themeName
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ var imgStyle = `.site-header {
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
var header = reload.Vars(constraints.Defaults)
|
var header = reload.Vars(constraints.Defaults, "twentyfifteen-customheader")
|
||||||
|
|
||||||
func calCustomHeaderImg(h *wp.Handle) (r string, rand bool) {
|
func calCustomHeaderImg(h *wp.Handle) (r string, rand bool) {
|
||||||
img, rand := h.GetCustomHeaderImg()
|
img, rand := h.GetCustomHeaderImg()
|
||||||
|
|
|
@ -3,13 +3,11 @@ package twentyfifteen
|
||||||
import (
|
import (
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/constraints"
|
"github.com/fthvgb1/wp-go/app/pkg/constraints"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/constraints/widgets"
|
"github.com/fthvgb1/wp-go/app/pkg/constraints/widgets"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
|
||||||
"github.com/fthvgb1/wp-go/app/plugins"
|
"github.com/fthvgb1/wp-go/app/plugins"
|
||||||
"github.com/fthvgb1/wp-go/app/theme/wp"
|
"github.com/fthvgb1/wp-go/app/theme/wp"
|
||||||
"github.com/fthvgb1/wp-go/app/theme/wp/components"
|
"github.com/fthvgb1/wp-go/app/theme/wp/components"
|
||||||
"github.com/fthvgb1/wp-go/app/theme/wp/middleware"
|
"github.com/fthvgb1/wp-go/app/theme/wp/middleware"
|
||||||
"github.com/fthvgb1/wp-go/app/wpconfig"
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -56,16 +54,10 @@ func setPaginationAndRender(h *wp.Handle) {
|
||||||
func postThumb(h *wp.Handle) {
|
func postThumb(h *wp.Handle) {
|
||||||
d := h.GetDetailHandle()
|
d := h.GetDetailHandle()
|
||||||
if d.Post.Thumbnail.Path != "" {
|
if d.Post.Thumbnail.Path != "" {
|
||||||
d.Post.Thumbnail = getPostThumbs(d.Post.Id, d.Post)
|
d.Post.Thumbnail = wpconfig.Thumbnail(d.Post.Thumbnail.OriginAttachmentData, "post-thumbnail", "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var getPostThumbs = reload.BuildMapFn[uint64]("twentyFifteen-post-thumbnail", postThumbs)
|
|
||||||
|
|
||||||
func postThumbs(post models.Posts) models.PostThumbnail {
|
|
||||||
return wpconfig.Thumbnail(post.Thumbnail.OriginAttachmentData, "post-thumbnail", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderCustomHeader(h *wp.Handle) {
|
func renderCustomHeader(h *wp.Handle) {
|
||||||
h.SetData("customHeader", customHeader(h))
|
h.SetData("customHeader", customHeader(h))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,7 @@ var paginate = func() plugins.PageEle {
|
||||||
Nexts: p.Next,
|
Nexts: p.Next,
|
||||||
Dotss: p.Dots,
|
Dotss: p.Dots,
|
||||||
Middles: p.Middle,
|
Middles: p.Middle,
|
||||||
Steps: func() int {
|
Urlss: plugins.TwentyFifteenCommentPagination().Urls,
|
||||||
return 2
|
|
||||||
},
|
|
||||||
Urlss: plugins.TwentyFifteenCommentPagination().Urls,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return p
|
return p
|
||||||
|
@ -83,6 +80,7 @@ func setPaginationAndRender(h *wp.Handle) {
|
||||||
d := hh.GetDetailHandle()
|
d := hh.GetDetailHandle()
|
||||||
d.CommentRender = commentFormat
|
d.CommentRender = commentFormat
|
||||||
d.CommentPageEle = commentPageEle
|
d.CommentPageEle = commentPageEle
|
||||||
|
d.CommentStep = 2
|
||||||
}, 150, "setPaginationAndRender"))
|
}, 150, "setPaginationAndRender"))
|
||||||
wp.PushIndexHandler(constraints.PipeRender, h, wp.NewHandleFn(func(hh *wp.Handle) {
|
wp.PushIndexHandler(constraints.PipeRender, h, wp.NewHandleFn(func(hh *wp.Handle) {
|
||||||
i := hh.GetIndexHandle()
|
i := hh.GetIndexHandle()
|
||||||
|
@ -112,19 +110,13 @@ func errorsHandle(h *wp.Handle) {
|
||||||
func postThumb(h *wp.Handle) {
|
func postThumb(h *wp.Handle) {
|
||||||
d := h.GetDetailHandle()
|
d := h.GetDetailHandle()
|
||||||
if d.Post.Thumbnail.Path != "" {
|
if d.Post.Thumbnail.Path != "" {
|
||||||
d.Post.Thumbnail = getPostThumbs(d.Post.Id, d.Post)
|
img := wpconfig.Thumbnail(d.Post.Thumbnail.OriginAttachmentData, "full", "", "thumbnail", "post-thumbnail")
|
||||||
|
img.Sizes = "100vw"
|
||||||
|
img.Srcset = fmt.Sprintf("%s %dw, %s", img.Path, img.Width, img.Srcset)
|
||||||
|
d.Post.Thumbnail = img
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var getPostThumbs = reload.BuildMapFn[uint64]("post-thumbnail", postThumbs)
|
|
||||||
|
|
||||||
func postThumbs(post models.Posts) models.PostThumbnail {
|
|
||||||
img := wpconfig.Thumbnail(post.Thumbnail.OriginAttachmentData, "full", "", "thumbnail", "post-thumbnail")
|
|
||||||
img.Sizes = "100vw"
|
|
||||||
img.Srcset = fmt.Sprintf("%s %dw, %s", img.Path, img.Width, img.Srcset)
|
|
||||||
return img
|
|
||||||
}
|
|
||||||
|
|
||||||
var commentFormat = comment{}
|
var commentFormat = comment{}
|
||||||
|
|
||||||
type comment struct {
|
type comment struct {
|
||||||
|
@ -162,7 +154,7 @@ func postThumbnail(h *wp.Handle, posts *models.Posts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var header = reload.Vars(models.PostThumbnail{})
|
var header = reload.Vars(models.PostThumbnail{}, "twentyseventeen-headerImage")
|
||||||
|
|
||||||
func calCustomHeader(h *wp.Handle) {
|
func calCustomHeader(h *wp.Handle) {
|
||||||
h.SetData("HeaderImage", getHeaderImage(h))
|
h.SetData("HeaderImage", getHeaderImage(h))
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handle) DisplayHeaderText() bool {
|
func (h *Handle) DisplayHeaderText() bool {
|
||||||
|
@ -23,7 +24,7 @@ var GetCustomHeaderImgFn = reload.BuildValFnWithConfirm("headerImages", customHe
|
||||||
func customHeadImag(h *Handle) ([]models.PostThumbnail, bool) {
|
func customHeadImag(h *Handle) ([]models.PostThumbnail, bool) {
|
||||||
hs, err := h.GetHeaderImages(h.theme)
|
hs, err := h.GetHeaderImages(h.theme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.SetErr(err)
|
h.SetErr(fmt.Errorf("get customheadimage err: %v", err), Low)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
return hs, true
|
return hs, true
|
||||||
|
@ -33,7 +34,7 @@ func (h *Handle) GetCustomHeaderImg() (r models.PostThumbnail, isRand bool) {
|
||||||
var err error
|
var err error
|
||||||
img := GetCustomHeaderImgFn(h)
|
img := GetCustomHeaderImgFn(h)
|
||||||
err = h.Err()
|
err = h.Err()
|
||||||
if err != nil {
|
if err != nil && strings.Contains(err.Error(), "get customheadimage err") {
|
||||||
logs.Error(err, "获取页眉背景图失败")
|
logs.Error(err, "获取页眉背景图失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,16 @@ type DetailHandle struct {
|
||||||
CommentPageEle pagination.Render
|
CommentPageEle pagination.Render
|
||||||
TotalRaw int
|
TotalRaw int
|
||||||
TotalPage int
|
TotalPage int
|
||||||
|
CommentStep int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDetailHandle(handle *Handle) *DetailHandle {
|
func NewDetailHandle(handle *Handle) *DetailHandle {
|
||||||
return &DetailHandle{Handle: handle}
|
return &DetailHandle{
|
||||||
|
Handle: handle,
|
||||||
|
Page: 1,
|
||||||
|
Limit: 5,
|
||||||
|
CommentStep: 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DetailHandle) BuildDetailData() (err error) {
|
func (d *DetailHandle) BuildDetailData() (err error) {
|
||||||
|
@ -97,7 +103,7 @@ func (d *DetailHandle) CommentData() {
|
||||||
pageComments := wpconfig.GetOption("page_comments")
|
pageComments := wpconfig.GetOption("page_comments")
|
||||||
num, err := cachemanager.GetBy[int]("commentNumber", d.C, d.Post.Id, time.Second)
|
num, err := cachemanager.GetBy[int]("commentNumber", d.C, d.Post.Id, time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.SetErr(err)
|
d.SetErr(err, Low)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if num < 1 {
|
if num < 1 {
|
||||||
|
@ -105,7 +111,7 @@ func (d *DetailHandle) CommentData() {
|
||||||
}
|
}
|
||||||
topNum, err := cachemanager.GetBy[int]("postTopCommentsNum", d.C, d.Post.Id, time.Second)
|
topNum, err := cachemanager.GetBy[int]("postTopCommentsNum", d.C, d.Post.Id, time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.SetErr(err)
|
d.SetErr(err, Low)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.TotalPage = number.DivideCeil(topNum, d.Limit)
|
d.TotalPage = number.DivideCeil(topNum, d.Limit)
|
||||||
|
@ -127,12 +133,12 @@ func (d *DetailHandle) CommentData() {
|
||||||
d.ginH["page_comments"] = pageComments
|
d.ginH["page_comments"] = pageComments
|
||||||
d.ginH["totalCommentPage"] = d.TotalPage
|
d.ginH["totalCommentPage"] = d.TotalPage
|
||||||
if d.TotalPage < d.Page {
|
if d.TotalPage < d.Page {
|
||||||
d.SetErr(errors.New("curren page above total page"))
|
d.SetErr(errors.New("curren page above total page"), High)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := cache.PostTopLevelCommentIds(d.C, d.Post.Id, d.Page, d.Limit, topNum, order, key)
|
data, err := cache.PostTopLevelCommentIds(d.C, d.Post.Id, d.Page, d.Limit, topNum, order, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.SetErr(err)
|
d.SetErr(err, Low)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.TotalRaw = topNum
|
d.TotalRaw = topNum
|
||||||
|
@ -157,14 +163,14 @@ func (d *DetailHandle) RenderComment() {
|
||||||
var err error
|
var err error
|
||||||
d.ginH["comments"], err = RenderComment(d.C, d.Page, d.CommentRender, d.Comments, 2*time.Second, d.IsHttps())
|
d.ginH["comments"], err = RenderComment(d.C, d.Page, d.CommentRender, d.Comments, 2*time.Second, d.IsHttps())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.SetErr(err)
|
d.SetErr(err, High)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if d.CommentPageEle == nil {
|
if d.CommentPageEle == nil {
|
||||||
d.CommentPageEle = plugins.TwentyFifteenCommentPagination()
|
d.CommentPageEle = plugins.TwentyFifteenCommentPagination()
|
||||||
}
|
}
|
||||||
if wpconfig.GetOption("page_comments") == "1" && d.TotalPage > 1 {
|
if wpconfig.GetOption("page_comments") == "1" && d.TotalPage > 1 {
|
||||||
d.ginH["commentPageNav"] = pagination.Paginate(d.CommentPageEle, d.TotalRaw, d.Limit, d.Page, 1, *d.C.Request.URL, d.IsHttps())
|
d.ginH["commentPageNav"] = pagination.Paginate(d.CommentPageEle, d.TotalRaw, d.Limit, d.Page, d.CommentStep, *d.C.Request.URL, d.IsHttps())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +195,7 @@ func Detail(h *Handle) {
|
||||||
d := h.GetDetailHandle()
|
d := h.GetDetailHandle()
|
||||||
err := d.BuildDetailData()
|
err := d.BuildDetailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.SetErr(err)
|
d.SetErr(err, High)
|
||||||
}
|
}
|
||||||
h.SetData("scene", h.Scene())
|
h.SetData("scene", h.Scene())
|
||||||
}
|
}
|
||||||
|
|
8
app/theme/wp/errorlevel.go
Normal file
8
app/theme/wp/errorlevel.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package wp
|
||||||
|
|
||||||
|
const (
|
||||||
|
None = iota
|
||||||
|
Low
|
||||||
|
High
|
||||||
|
Fatal
|
||||||
|
)
|
|
@ -173,7 +173,7 @@ func Index(h *Handle) {
|
||||||
i := h.GetIndexHandle()
|
i := h.GetIndexHandle()
|
||||||
err := i.BuildIndexData()
|
err := i.BuildIndexData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.SetErr(err)
|
i.SetErr(err, High)
|
||||||
}
|
}
|
||||||
h.SetData("scene", h.Scene())
|
h.SetData("scene", h.Scene())
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ func PostsPlugins(initial PostsPlugin, calls ...func(PostsPlugin, *Handle, *mode
|
||||||
var pluginFns = reload.Vars(map[string]func(PostsPlugin, *Handle, *models.Posts){
|
var pluginFns = reload.Vars(map[string]func(PostsPlugin, *Handle, *models.Posts){
|
||||||
"passwordProject": PasswordProject,
|
"passwordProject": PasswordProject,
|
||||||
"digest": Digest,
|
"digest": Digest,
|
||||||
})
|
}, "list-post-plugins-fns")
|
||||||
|
|
||||||
func (h *Handle) PushPostsPlugin(name string, fn func(PostsPlugin, *Handle, *models.Posts)) {
|
func (h *Handle) PushPostsPlugin(name string, fn func(PostsPlugin, *Handle, *models.Posts)) {
|
||||||
m := pluginFns.Load()
|
m := pluginFns.Load()
|
||||||
|
@ -53,7 +53,7 @@ func Digest(next PostsPlugin, h *Handle, post *models.Posts) {
|
||||||
next(h, post)
|
next(h, post)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ordinaryPlugin = reload.Vars([]PostsPlugin{})
|
var ordinaryPlugin = reload.Vars([]PostsPlugin{}, "ordinaryPlugin")
|
||||||
|
|
||||||
func (h *Handle) PushPostPlugin(plugin ...PostsPlugin) {
|
func (h *Handle) PushPostPlugin(plugin ...PostsPlugin) {
|
||||||
p := ordinaryPlugin.Load()
|
p := ordinaryPlugin.Load()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/constraints"
|
"github.com/fthvgb1/wp-go/app/pkg/constraints"
|
||||||
"github.com/fthvgb1/wp-go/app/theme/wp"
|
"github.com/fthvgb1/wp-go/app/theme/wp"
|
||||||
"github.com/fthvgb1/wp-go/app/theme/wp/components/widget"
|
"github.com/fthvgb1/wp-go/app/theme/wp/components/widget"
|
||||||
|
"github.com/fthvgb1/wp-go/app/theme/wp/route"
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"github.com/fthvgb1/wp-go/helper/maps"
|
"github.com/fthvgb1/wp-go/helper/maps"
|
||||||
"github.com/fthvgb1/wp-go/helper/number"
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
|
@ -81,7 +82,7 @@ var plainRouteParam = reload.Vars([]Plain{
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, "plainRouteParam")
|
||||||
|
|
||||||
var GetUsersIds = reload.BuildValFnWithConfirm("usersIds", func(h *wp.Handle) (map[uint64]string, bool) {
|
var GetUsersIds = reload.BuildValFnWithConfirm("usersIds", func(h *wp.Handle) (map[uint64]string, bool) {
|
||||||
users, err := cache.GetAllUsername(h.C)
|
users, err := cache.GetAllUsername(h.C)
|
||||||
|
@ -160,4 +161,7 @@ func CommonMiddleware(h *wp.Handle) {
|
||||||
h.PushHandler(constraints.PipeMiddleware, constraints.Detail,
|
h.PushHandler(constraints.PipeMiddleware, constraints.Detail,
|
||||||
wp.NewHandleFn(ShowPreComment, 100, "middleware.ShowPreComment"),
|
wp.NewHandleFn(ShowPreComment, 100, "middleware.ShowPreComment"),
|
||||||
)
|
)
|
||||||
|
h.PushHandler(constraints.PipeMiddleware, constraints.NoRoute,
|
||||||
|
wp.NewHandleFn(route.ResolveRoute, 100, "route.ResolveRoute"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,11 @@ func (h *Handle) PushDataHandler(scene string, fns ...HandleCall) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildHandlers(pipeScene string, keyFn func(*Handle, string) string,
|
func BuildHandlers(pipeScene string, keyFn func(*Handle, string) string,
|
||||||
handleHook func(*Handle, map[string][]func(HandleCall) (HandleCall, bool)) []func(HandleCall) (HandleCall, bool),
|
handleHookFn func(*Handle, string,
|
||||||
handlesFn func(*Handle, map[string][]HandleCall, string) []HandleCall) func(HandleFn[*Handle], *Handle) {
|
map[string][]func(HandleCall) (HandleCall, bool),
|
||||||
|
map[string][]HandleCall) []HandleCall) func(HandleFn[*Handle], *Handle) {
|
||||||
|
|
||||||
pipeHandlerFn := reload.BuildMapFn[string]("pipeHandlers", BuildHandler(pipeScene, keyFn, handleHook, handlesFn))
|
pipeHandlerFn := reload.BuildMapFn[string]("pipeHandlers", BuildHandler(pipeScene, keyFn, handleHookFn))
|
||||||
|
|
||||||
return func(next HandleFn[*Handle], h *Handle) {
|
return func(next HandleFn[*Handle], h *Handle) {
|
||||||
key := keyFn(h, pipeScene)
|
key := keyFn(h, pipeScene)
|
||||||
|
@ -88,8 +89,9 @@ func BuildHandlers(pipeScene string, keyFn func(*Handle, string) string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildHandler(pipeScene string, keyFn func(*Handle, string) string,
|
func BuildHandler(pipeScene string, keyFn func(*Handle, string) string,
|
||||||
handleHook func(*Handle, map[string][]func(HandleCall) (HandleCall, bool)) []func(HandleCall) (HandleCall, bool),
|
handleHook func(*Handle, string,
|
||||||
handlesFn func(*Handle, map[string][]HandleCall, string) []HandleCall) func(*Handle) []HandleCall {
|
map[string][]func(HandleCall) (HandleCall, bool),
|
||||||
|
map[string][]HandleCall) []HandleCall) func(*Handle) []HandleCall {
|
||||||
|
|
||||||
return func(h *Handle) []HandleCall {
|
return func(h *Handle) []HandleCall {
|
||||||
key := keyFn(h, pipeScene)
|
key := keyFn(h, pipeScene)
|
||||||
|
@ -98,18 +100,7 @@ func BuildHandler(pipeScene string, keyFn func(*Handle, string) string,
|
||||||
pipeHookers, _ := handleHooks.Load(pipeScene)
|
pipeHookers, _ := handleHooks.Load(pipeScene)
|
||||||
pipeHandlers, _ := handlerss.Load(pipeScene)
|
pipeHandlers, _ := handlerss.Load(pipeScene)
|
||||||
mut.Unlock()
|
mut.Unlock()
|
||||||
hookers := handleHook(h, pipeHookers)
|
calls := handleHook(h, key, pipeHookers, pipeHandlers)
|
||||||
calls := handlesFn(h, pipeHandlers, key)
|
|
||||||
calls = slice.FilterAndMap(calls, func(call HandleCall) (HandleCall, bool) {
|
|
||||||
ok := true
|
|
||||||
for _, hook := range hookers {
|
|
||||||
call, ok = hook(call)
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return call, ok
|
|
||||||
})
|
|
||||||
slice.SimpleSort(calls, slice.DESC, func(t HandleCall) float64 {
|
slice.SimpleSort(calls, slice.DESC, func(t HandleCall) float64 {
|
||||||
return t.Order
|
return t.Order
|
||||||
})
|
})
|
||||||
|
@ -117,6 +108,19 @@ func BuildHandler(pipeScene string, keyFn func(*Handle, string) string,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HookHandles(hooks map[string][]func(HandleCall) (HandleCall, bool),
|
||||||
|
handlers map[string][]HandleCall, sceneOrStats ...string) []HandleCall {
|
||||||
|
|
||||||
|
hookedHandlers := slice.FilterAndMap(sceneOrStats, func(k string) ([]HandleCall, bool) {
|
||||||
|
r := handlers[k]
|
||||||
|
for _, hook := range hooks[k] {
|
||||||
|
r = slice.FilterAndMap(r, hook)
|
||||||
|
}
|
||||||
|
return r, true
|
||||||
|
})
|
||||||
|
return slice.Decompress(hookedHandlers)
|
||||||
|
}
|
||||||
|
|
||||||
func PipeKey(h *Handle, pipScene string) string {
|
func PipeKey(h *Handle, pipScene string) string {
|
||||||
key := str.Join("pipekey", "-", pipScene, "-", h.scene, "-", h.Stats)
|
key := str.Join("pipekey", "-", pipScene, "-", h.scene, "-", h.Stats)
|
||||||
return h.DoActionFilter("pipeKey", key, pipScene)
|
return h.DoActionFilter("pipeKey", key, pipScene)
|
||||||
|
@ -163,36 +167,25 @@ func MiddlewareKey(h *Handle, pipScene string) string {
|
||||||
return h.DoActionFilter("middleware", str.Join("pipe-middleware-", h.scene), pipScene)
|
return h.DoActionFilter("middleware", str.Join("pipe-middleware-", h.scene), pipScene)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PipeMiddlewareHandle(h *Handle, middlewares map[string][]HandleCall, key string) (handlers []HandleCall) {
|
func PipeMiddlewareHandle(h *Handle, key string,
|
||||||
handlers = append(handlers, middlewares[h.scene]...)
|
hooks map[string][]func(HandleCall) (HandleCall, bool),
|
||||||
handlers = append(handlers, middlewares[constraints.AllScene]...)
|
handlers map[string][]HandleCall) []HandleCall {
|
||||||
handlers = h.PipeHandleHook("PipeMiddlewareHandle", handlers, middlewares, key)
|
hookedHandles := HookHandles(hooks, handlers, h.scene, constraints.AllScene)
|
||||||
return
|
return h.PipeHandleHook("PipeMiddlewareHandle", hookedHandles, handlers, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PipeDataHandle(h *Handle, dataHandlers map[string][]HandleCall, key string) (handlers []HandleCall) {
|
func PipeDataHandle(h *Handle, key string,
|
||||||
handlers = append(handlers, dataHandlers[h.scene]...)
|
hooks map[string][]func(HandleCall) (HandleCall, bool),
|
||||||
handlers = append(handlers, dataHandlers[constraints.AllScene]...)
|
handlers map[string][]HandleCall) []HandleCall {
|
||||||
handlers = h.PipeHandleHook("PipeDataHandle", handlers, dataHandlers, key)
|
hookedHandles := HookHandles(hooks, handlers, h.scene, constraints.AllScene)
|
||||||
return
|
return h.PipeHandleHook("PipeDataHandle", hookedHandles, handlers, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PipeRender(h *Handle, renders map[string][]HandleCall, key string) (handlers []HandleCall) {
|
func PipeRender(h *Handle, key string,
|
||||||
handlers = append(handlers, renders[h.Stats]...)
|
hooks map[string][]func(HandleCall) (HandleCall, bool),
|
||||||
handlers = append(handlers, renders[h.scene]...)
|
handlers map[string][]HandleCall) []HandleCall {
|
||||||
handlers = append(handlers, renders[constraints.AllStats]...)
|
hookedHandles := HookHandles(hooks, handlers, h.scene, h.Stats, constraints.AllScene, constraints.AllStats)
|
||||||
handlers = append(handlers, renders[constraints.AllScene]...)
|
return h.PipeHandleHook("PipeRender", hookedHandles, handlers, key)
|
||||||
handlers = h.PipeHandleHook("PipeRender", handlers, renders, key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleHook(h *Handle, hooks map[string][]func(HandleCall) (HandleCall, bool)) []func(HandleCall) (HandleCall, bool) {
|
|
||||||
var r []func(HandleCall) (HandleCall, bool)
|
|
||||||
r = append(r, hooks[h.scene]...)
|
|
||||||
r = append(r, hooks[h.Stats]...)
|
|
||||||
r = append(r, hooks[constraints.AllScene]...)
|
|
||||||
r = append(r, hooks[constraints.AllStats]...)
|
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteHandle 写插件的时候用
|
// DeleteHandle 写插件的时候用
|
||||||
|
@ -245,10 +238,10 @@ func (h *Handle) PipeHandleHook(name string, calls []HandleCall, m map[string][]
|
||||||
|
|
||||||
func InitPipe(h *Handle) {
|
func InitPipe(h *Handle) {
|
||||||
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeMiddleware, 300,
|
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeMiddleware, 300,
|
||||||
BuildHandlers(constraints.PipeMiddleware, MiddlewareKey, HandleHook, PipeMiddlewareHandle)))
|
BuildHandlers(constraints.PipeMiddleware, MiddlewareKey, PipeMiddlewareHandle)))
|
||||||
|
|
||||||
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeData, 200,
|
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeData, 200,
|
||||||
BuildHandlers(constraints.PipeData, PipeKey, HandleHook, PipeDataHandle)))
|
BuildHandlers(constraints.PipeData, PipeKey, PipeDataHandle)))
|
||||||
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeRender, 100,
|
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeRender, 100,
|
||||||
BuildHandlers(constraints.PipeRender, PipeKey, HandleHook, PipeRender)))
|
BuildHandlers(constraints.PipeRender, PipeKey, PipeRender)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,12 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"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"
|
||||||
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Route
|
||||||
|
// Type value equal const or reg
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Path string
|
Path string
|
||||||
Scene string
|
Scene string
|
||||||
|
@ -20,18 +23,18 @@ var routeHook []func(Route) (Route, bool)
|
||||||
var regRoutes *safety.Map[string, *regexp.Regexp]
|
var regRoutes *safety.Map[string, *regexp.Regexp]
|
||||||
var routes = func() *safety.Map[string, Route] {
|
var routes = func() *safety.Map[string, Route] {
|
||||||
r := safety.NewMap[string, Route]()
|
r := safety.NewMap[string, Route]()
|
||||||
reload.Push(func() {
|
reload.Append(func() {
|
||||||
r.Flush()
|
r.Flush()
|
||||||
regRoutes.Flush()
|
regRoutes.Flush()
|
||||||
})
|
}, "wp-routers")
|
||||||
regRoutes = safety.NewMap[string, *regexp.Regexp]()
|
regRoutes = safety.NewMap[string, *regexp.Regexp]()
|
||||||
return r
|
return r
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// PushRoute path can be const or regex string
|
// PushRoute path can be const or regex string
|
||||||
//
|
//
|
||||||
// eg: `(?P<control>\w+)/(?P<method>\w+)`, route.Route{
|
// eg: `(?P<controller>\w+)/(?P<method>\w+)`, route.Route{
|
||||||
// Path: `(?P<control>\w+)/(?P<method>\w+)`,
|
// Path: `(?P<controller>\w+)/(?P<method>\w+)`,
|
||||||
// Scene: constraints.Home,
|
// Scene: constraints.Home,
|
||||||
// Method: []string{"GET"},
|
// Method: []string{"GET"},
|
||||||
// Type: "reg",
|
// Type: "reg",
|
||||||
|
@ -118,17 +121,26 @@ func ResolveRoute(h *wp.Handle) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for path, reg := range rrs {
|
for path, reg := range rrs {
|
||||||
r := reg.FindAllStringSubmatch(requestURI, -1)
|
r := reg.FindStringSubmatch(requestURI)
|
||||||
if len(r) < 1 {
|
if len(r) < 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rr := rs[path]
|
rr := rs[path]
|
||||||
if slice.IsContained(rr.Method, h.C.Request.Method) {
|
if slice.IsContained(rr.Method, h.C.Request.Method) {
|
||||||
h.SetScene(rr.Scene)
|
h.SetScene(rr.Scene)
|
||||||
h.C.Set("route", r)
|
for i, name := range reg.SubexpNames() {
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
h.C.AddParam(name, r[i])
|
||||||
|
}
|
||||||
|
h.C.Set("regRoute", reg)
|
||||||
|
h.C.Set("regRouteRes", r)
|
||||||
wp.Run(h, nil)
|
wp.Run(h, nil)
|
||||||
h.Abort()
|
h.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
h.C.Status(http.StatusNotFound)
|
||||||
|
h.Abort()
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ type Handle struct {
|
||||||
templ string
|
templ string
|
||||||
themeMods wpconfig.ThemeMods
|
themeMods wpconfig.ThemeMods
|
||||||
err error
|
err error
|
||||||
|
errLevel int8
|
||||||
abort bool
|
abort bool
|
||||||
stopPipe bool
|
stopPipe bool
|
||||||
}
|
}
|
||||||
|
@ -86,6 +87,8 @@ type HandleCall struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isFirstRequest = true
|
||||||
|
|
||||||
func SetConfigHandle(a ...any) Handle {
|
func SetConfigHandle(a ...any) Handle {
|
||||||
configFn := a[0].(func(*Handle))
|
configFn := a[0].(func(*Handle))
|
||||||
hh := a[1].(*Handle)
|
hh := a[1].(*Handle)
|
||||||
|
@ -99,27 +102,29 @@ func SetConfigHandle(a ...any) Handle {
|
||||||
h.ginH = gin.H{}
|
h.ginH = gin.H{}
|
||||||
fnMap.Flush()
|
fnMap.Flush()
|
||||||
fnHook.Flush()
|
fnHook.Flush()
|
||||||
|
if isFirstRequest {
|
||||||
|
isFirstRequest = false
|
||||||
|
} else {
|
||||||
|
reload.Reload()
|
||||||
|
}
|
||||||
h.C = hh.C
|
h.C = hh.C
|
||||||
h.theme = hh.theme
|
h.theme = hh.theme
|
||||||
configFn(h)
|
configFn(h)
|
||||||
v := apply.UsePlugins()
|
v := apply.GetPlugins()
|
||||||
pluginFn, ok := v.(func(*Handle))
|
pluginFn, ok := v.(func(*Handle))
|
||||||
if ok {
|
if ok {
|
||||||
pluginFn(h)
|
pluginFn(h)
|
||||||
}
|
}
|
||||||
reload.Reload()
|
|
||||||
return *h
|
return *h
|
||||||
}
|
}
|
||||||
|
|
||||||
var GetInitHandleFn = reload.BuildValFnWithAnyParams("themeArgAndConfig", SetConfigHandle, false)
|
var GetInitHandleFn = reload.BuildValFnWithAnyParams("themeArgAndConfig", SetConfigHandle, false)
|
||||||
|
|
||||||
type ConfigParm struct {
|
|
||||||
ConfigFn func(*Handle)
|
|
||||||
H *Handle
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitHandle(configFn func(*Handle), h *Handle) {
|
func InitHandle(configFn func(*Handle), h *Handle) {
|
||||||
hh := GetInitHandleFn(configFn, h)
|
hh := GetInitHandleFn(configFn, h)
|
||||||
|
mods, err := wpconfig.GetThemeMods(h.theme)
|
||||||
|
logs.IfError(err, "获取mods失败")
|
||||||
|
h.themeMods = mods
|
||||||
h.ginH = maps.Copy(hh.ginH)
|
h.ginH = maps.Copy(hh.ginH)
|
||||||
h.ginH["calPostClass"] = postClass(h)
|
h.ginH["calPostClass"] = postClass(h)
|
||||||
h.ginH["calBodyClass"] = bodyClass(h)
|
h.ginH["calBodyClass"] = bodyClass(h)
|
||||||
|
@ -147,8 +152,17 @@ func (h *Handle) Err() error {
|
||||||
return h.err
|
return h.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) SetErr(err error) {
|
func (h *Handle) SetErr(err error, level int8) {
|
||||||
h.err = errors.Join(err)
|
h.err = errors.Join(err)
|
||||||
|
h.errLevel = level
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) ErrLevel() int8 {
|
||||||
|
return h.errLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) SetErrLevel(errLevel int8) {
|
||||||
|
h.errLevel = errLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) SetTempl(templ string) {
|
func (h *Handle) SetTempl(templ string) {
|
||||||
|
@ -170,15 +184,12 @@ func (h *Handle) SetData(k string, v any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandle(c *gin.Context, scene string, theme string) *Handle {
|
func NewHandle(c *gin.Context, scene string, theme string) *Handle {
|
||||||
mods, err := wpconfig.GetThemeMods(theme)
|
|
||||||
logs.IfError(err, "获取mods失败")
|
|
||||||
return &Handle{
|
return &Handle{
|
||||||
C: c,
|
C: c,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
Session: sessions.Default(c),
|
Session: sessions.Default(c),
|
||||||
scene: scene,
|
scene: scene,
|
||||||
Stats: constraints.Ok,
|
Stats: constraints.Ok,
|
||||||
themeMods: mods,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +234,12 @@ func (h *Handle) RenderHtml(t *template.Template, statsCode int, name string) {
|
||||||
header["Content-Type"] = htmlContentType
|
header["Content-Type"] = htmlContentType
|
||||||
}
|
}
|
||||||
h.C.Status(statsCode)
|
h.C.Status(statsCode)
|
||||||
err := t.ExecuteTemplate(h.C.Writer, name, h.ginH)
|
var err error
|
||||||
|
if name == "" {
|
||||||
|
err = t.Execute(h.C.Writer, h.ginH)
|
||||||
|
} else {
|
||||||
|
err = t.ExecuteTemplate(h.C.Writer, name, h.ginH)
|
||||||
|
}
|
||||||
h.Abort()
|
h.Abort()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -73,6 +73,7 @@ func Thumbnail(metadata models.WpAttachmentMetadata, Type, host string, except .
|
||||||
up := strings.Split(metadata.File, "/")
|
up := strings.Split(metadata.File, "/")
|
||||||
if metadata.File != "" && Type == "full" {
|
if metadata.File != "" && Type == "full" {
|
||||||
mimeType := metadata.Sizes["thumbnail"].MimeType
|
mimeType := metadata.Sizes["thumbnail"].MimeType
|
||||||
|
metadata.Sizes = maps.Copy(metadata.Sizes)
|
||||||
metadata.Sizes["full"] = models.MetaDataFileSize{
|
metadata.Sizes["full"] = models.MetaDataFileSize{
|
||||||
File: filepath.Base(metadata.File),
|
File: filepath.Base(metadata.File),
|
||||||
Width: metadata.Width,
|
Width: metadata.Width,
|
||||||
|
@ -111,10 +112,10 @@ func Thumbnail(metadata models.WpAttachmentMetadata, Type, host string, except .
|
||||||
var themeModes = func() *safety.Map[string, ThemeMods] {
|
var themeModes = func() *safety.Map[string, ThemeMods] {
|
||||||
m := safety.NewMap[string, ThemeMods]()
|
m := safety.NewMap[string, ThemeMods]()
|
||||||
themeModsRaw = safety.NewMap[string, map[string]any]()
|
themeModsRaw = safety.NewMap[string, map[string]any]()
|
||||||
reload.Push(func() {
|
reload.Append(func() {
|
||||||
m.Flush()
|
m.Flush()
|
||||||
themeModsRaw.Flush()
|
themeModsRaw.Flush()
|
||||||
})
|
}, "theme-modes")
|
||||||
|
|
||||||
return m
|
return m
|
||||||
}()
|
}()
|
||||||
|
|
317
cache/cachemanager/manger.go
vendored
317
cache/cachemanager/manger.go
vendored
|
@ -2,156 +2,50 @@ package cachemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"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"
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
|
||||||
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"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mapFlush = safety.NewMap[string, func(any)]()
|
var mutex sync.Mutex
|
||||||
var anyFlush = safety.NewMap[string, func()]()
|
|
||||||
|
|
||||||
var varCache = safety.NewMap[string, any]()
|
type Fn func(context.Context)
|
||||||
var mapCache = safety.NewMap[string, any]()
|
|
||||||
|
|
||||||
func SetVarCache[T any](name string, v *cache.VarCache[T]) error {
|
|
||||||
vv, ok := varCache.Load(name)
|
|
||||||
if !ok {
|
|
||||||
varCache.Store(name, v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, ok = vv.(*cache.VarCache[T])
|
|
||||||
if ok {
|
|
||||||
varCache.Store(name, v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New(str.Join("cache ", name, " type err"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetMapCache[K comparable, V any](name string, ca *cache.MapCache[K, V]) error {
|
|
||||||
v, ok := mapCache.Load(name)
|
|
||||||
if !ok {
|
|
||||||
mapCache.Store(name, ca)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, ok = v.(*cache.MapCache[K, V])
|
|
||||||
if !ok {
|
|
||||||
return errors.New(str.Join("cache ", name, " type err"))
|
|
||||||
}
|
|
||||||
mapCache.Store(name, ca)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type flush interface {
|
|
||||||
Flush(ctx context.Context)
|
|
||||||
}
|
|
||||||
|
|
||||||
type clearExpired interface {
|
type clearExpired interface {
|
||||||
ClearExpired(ctx context.Context)
|
ClearExpired(ctx context.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
var clears []clearExpired
|
var clears = safety.NewVar(mockmap.Map[string, Fn]{})
|
||||||
|
|
||||||
var flushes []flush
|
var flushes = safety.NewVar(mockmap.Map[string, Fn]{})
|
||||||
|
|
||||||
func Flush() {
|
func Flush() {
|
||||||
ctx := context.WithValue(context.Background(), "execFlushBy", "mangerFlushFn")
|
ctx := context.WithValue(context.Background(), "execFlushBy", "mangerFlushFn")
|
||||||
for _, f := range flushes {
|
for _, f := range flushes.Load() {
|
||||||
f.Flush(ctx)
|
f.Value(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FlushMapVal[T any](name string, keys ...T) {
|
func Flushes(ctx context.Context, names ...string) {
|
||||||
v, ok := mapFlush.Load(name)
|
execute(ctx, flushes, names...)
|
||||||
if !ok || len(keys) < 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v(keys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func FlushAnyVal(name ...string) {
|
func execute(ctx context.Context, q *safety.Var[mockmap.Map[string, Fn]], names ...string) {
|
||||||
for _, s := range name {
|
queues := q.Load()
|
||||||
v, ok := anyFlush.Load(s)
|
for _, name := range names {
|
||||||
if ok {
|
queue := queues.Get(name)
|
||||||
v()
|
if queue.Value != nil {
|
||||||
|
queue.Value(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PushMangerMap[K comparable, V any](name string, m *cache.MapCache[K, V]) {
|
|
||||||
if name == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mapCache.Store(name, m)
|
|
||||||
anyFlush.Store(name, func() {
|
|
||||||
ctx := context.WithValue(context.Background(), "ctx", "registerFlush")
|
|
||||||
m.Flush(ctx)
|
|
||||||
})
|
|
||||||
mapFlush.Store(name, func(a any) {
|
|
||||||
k, ok := a.([]K)
|
|
||||||
if ok && len(k) > 0 {
|
|
||||||
ctx := context.WithValue(context.Background(), "ctx", "registerFlush")
|
|
||||||
m.Del(ctx, k...)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBy[T any, K comparable](name string, ct context.Context, key K, timeout time.Duration, params ...any) (r T, err error) {
|
|
||||||
ct = context.WithValue(ct, "getCache", name)
|
|
||||||
ca, err := getMap[K, T](name)
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
vv, err := ca.GetCache(ct, key, timeout, params...)
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
r = vv
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMap[K comparable, T any](name string) (*cache.MapCache[K, T], error) {
|
|
||||||
m, ok := mapCache.Load(name)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
|
||||||
}
|
|
||||||
vk, ok := m.(*cache.MapCache[K, T])
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New(str.Join("cache ", name, " type error"))
|
|
||||||
}
|
|
||||||
return vk, nil
|
|
||||||
}
|
|
||||||
func GetBatchBy[T any, K comparable](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r []T, err error) {
|
|
||||||
ct = context.WithValue(ct, "getCache", name)
|
|
||||||
ca, err := getMap[K, T](name)
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
vv, err := ca.GetCacheBatch(ct, key, timeout, params...)
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
r = vv
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func GetBatchByToMap[T any, K comparable](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r map[K]T, err error) {
|
|
||||||
ct = context.WithValue(ct, "getCache", name)
|
|
||||||
ca, err := getMap[K, T](name)
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
vv, err := ca.GetBatchToMap(ct, key, timeout, params...)
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
r = vv
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseArgs(args ...any) (string, func() time.Duration) {
|
func parseArgs(args ...any) (string, func() time.Duration) {
|
||||||
var name string
|
var name string
|
||||||
var fn func() time.Duration
|
var fn func() time.Duration
|
||||||
|
@ -170,42 +64,6 @@ func parseArgs(args ...any) (string, func() time.Duration) {
|
||||||
return name, fn
|
return name, fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPaginationCache[K comparable, V any](m *cache.MapCache[string, helper.PaginationData[V]], maxNum int,
|
|
||||||
dbFn cache.DbFn[K, V], localFn cache.LocalFn[K, V], dbKeyFn, localKeyFn func(K, ...any) string, fetchNum int, name string, a ...any) *cache.Pagination[K, V] {
|
|
||||||
fn := helper.ParseArgs([]func() int(nil), a...)
|
|
||||||
var ma, fet func() int
|
|
||||||
if len(fn) > 0 {
|
|
||||||
ma = fn[0]
|
|
||||||
if len(fn) > 1 {
|
|
||||||
fet = fn[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ma == nil {
|
|
||||||
ma = reload.BuildFnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, nil)
|
|
||||||
}
|
|
||||||
if fet == nil {
|
|
||||||
fet = reload.BuildFnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil)
|
|
||||||
}
|
|
||||||
p := cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name)
|
|
||||||
mapCache.Store(name, p)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
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])(nil), args...)
|
|
||||||
m := cache.NewMapCache[K, V](data, fn, batchFn, inc, buildLockFn[K](args...), args...)
|
|
||||||
FlushPush(m)
|
|
||||||
ClearPush(m)
|
|
||||||
name, f := parseArgs(args...)
|
|
||||||
if name != "" {
|
|
||||||
PushMangerMap(name, m)
|
|
||||||
}
|
|
||||||
if f != nil && name != "" {
|
|
||||||
SetExpireTime(any(data).(cache.SetTime), name, 0, f)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
|
func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
|
||||||
lockFn := helper.ParseArgs(cache.LockFn[K](nil), args...)
|
lockFn := helper.ParseArgs(cache.LockFn[K](nil), args...)
|
||||||
name := helper.ParseArgs("", args...)
|
name := helper.ParseArgs("", args...)
|
||||||
|
@ -228,20 +86,15 @@ func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
|
||||||
} else {
|
} else {
|
||||||
lo := cache.NewLocks[K](loFn)
|
lo := cache.NewLocks[K](loFn)
|
||||||
lockFn = lo.GetLock
|
lockFn = lo.GetLock
|
||||||
FlushPush(lo)
|
PushOrSetFlush(mockmap.Item[string, Fn]{
|
||||||
|
Name: name,
|
||||||
|
Value: lo.Flush,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return lockFn
|
return lockFn
|
||||||
}
|
}
|
||||||
func NewMemoryMapCache[K comparable, V any](batchFn cache.MapBatchFn[K, V],
|
|
||||||
fn cache.MapSingleFn[K, V], expireTime time.Duration, args ...any) *cache.MapCache[K, V] {
|
|
||||||
|
|
||||||
c := NewMapCache[K, V](cache.NewMemoryMapCache[K, V](func() time.Duration {
|
|
||||||
return expireTime
|
|
||||||
}), batchFn, fn, args...)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetExpireTime(c cache.SetTime, name string, expireTime time.Duration, expireTimeFn func() time.Duration) {
|
func SetExpireTime(c cache.SetTime, name string, expireTime time.Duration, expireTimeFn func() time.Duration) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
@ -256,95 +109,55 @@ func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) {
|
||||||
reload.SetFnVal(s, t, coverConf)
|
reload.SetFnVal(s, t, coverConf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func pushOrSet(q *safety.Var[mockmap.Map[string, Fn]], queues ...mockmap.Item[string, Fn]) {
|
||||||
func FlushPush(f ...flush) {
|
mutex.Lock()
|
||||||
flushes = append(flushes, f...)
|
defer mutex.Unlock()
|
||||||
|
qu := q.Load()
|
||||||
|
for _, queue := range queues {
|
||||||
|
v := qu.Get(queue.Name)
|
||||||
|
if v.Value != nil {
|
||||||
|
qu.Set(queue.Name, queue.Value)
|
||||||
|
} else {
|
||||||
|
qu = append(qu, queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q.Store(qu)
|
||||||
}
|
}
|
||||||
func ClearPush(c ...clearExpired) {
|
|
||||||
clears = append(clears, c...)
|
// PushOrSetFlush will execute flush func when call Flush or Flushes
|
||||||
|
func PushOrSetFlush(queues ...mockmap.Item[string, Fn]) {
|
||||||
|
pushOrSet(flushes, queues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushOrSetClearExpired will execute clearExpired func when call ClearExpired or ClearExpireds
|
||||||
|
func PushOrSetClearExpired(queues ...mockmap.Item[string, Fn]) {
|
||||||
|
pushOrSet(clears, queues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func del(q *safety.Var[mockmap.Map[string, Fn]], names ...string) {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
queues := q.Load()
|
||||||
|
for _, name := range names {
|
||||||
|
queues.Del(name)
|
||||||
|
}
|
||||||
|
q.Store(queues)
|
||||||
|
}
|
||||||
|
func DelFlush(names ...string) {
|
||||||
|
del(flushes, names...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelClearExpired(names ...string) {
|
||||||
|
del(clears, names...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearExpireds(ctx context.Context, names ...string) {
|
||||||
|
execute(ctx, clears, names...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClearExpired() {
|
func ClearExpired() {
|
||||||
ctx := context.WithValue(context.Background(), "execClearExpired", "mangerClearExpiredFn")
|
ctx := context.WithValue(context.Background(), "execClearExpired", "mangerClearExpiredFn")
|
||||||
for _, c := range clears {
|
for _, queue := range clears.Load() {
|
||||||
c.ClearExpired(ctx)
|
queue.Value(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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])(nil), a...)
|
|
||||||
ref := helper.ParseArgs(cache.RefreshVar[T](nil), a...)
|
|
||||||
v := cache.NewVarCache(c, fn, inc, ref, a...)
|
|
||||||
FlushPush(v)
|
|
||||||
name, _ := parseArgs(a...)
|
|
||||||
if name != "" {
|
|
||||||
varCache.Store(name, v)
|
|
||||||
}
|
|
||||||
cc, ok := any(c).(clearExpired)
|
|
||||||
if ok {
|
|
||||||
ClearPush(cc)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetVarVal[T any](name string, ctx context.Context, duration time.Duration, a ...any) (r T, err error) {
|
|
||||||
ctx = context.WithValue(ctx, "getCache", name)
|
|
||||||
ca, ok := GetVarCache[T](name)
|
|
||||||
if !ok {
|
|
||||||
err = errors.New(str.Join("cache ", name, " is not exist"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v, err := ca.GetCache(ctx, duration, a...)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r = v
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewVarMemoryCache[T any](fn func(context.Context, ...any) (T, error), expired time.Duration, a ...any) *cache.VarCache[T] {
|
|
||||||
c := cache.NewVarMemoryCache[T](nil)
|
|
||||||
name, e := parseArgs(a...)
|
|
||||||
SetExpireTime(c, name, expired, e)
|
|
||||||
v := NewVarCache[T](c, fn, a...)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetVarCache[T any](name string) (*cache.VarCache[T], bool) {
|
|
||||||
v, ok := varCache.Load(name)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
vv, ok := v.(*cache.VarCache[T])
|
|
||||||
return vv, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMapCache[K comparable, V any](name string) (*cache.MapCache[K, V], bool) {
|
|
||||||
vv, err := getMap[K, V](name)
|
|
||||||
return vv, err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPaginationCache[K comparable, V any](name string) (*cache.Pagination[K, V], bool) {
|
|
||||||
v, err := getPagination[K, V](name)
|
|
||||||
return v, err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Pagination[V any, K comparable](name string, ctx context.Context, timeout time.Duration, k K, page, limit int, a ...any) ([]V, int, error) {
|
|
||||||
v, err := getPagination[K, V](name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
return v.Pagination(ctx, timeout, k, page, limit, a...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPagination[K comparable, T any](name string) (*cache.Pagination[K, T], error) {
|
|
||||||
m, ok := mapCache.Load(name)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
|
||||||
}
|
|
||||||
vk, ok := m.(*cache.Pagination[K, T])
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New(str.Join("cache ", name, " type error"))
|
|
||||||
}
|
|
||||||
return vk, nil
|
|
||||||
}
|
|
||||||
|
|
4
cache/cachemanager/manger_test.go
vendored
4
cache/cachemanager/manger_test.go
vendored
|
@ -45,7 +45,7 @@ func TestFlushMapVal(t *testing.T) {
|
||||||
}
|
}
|
||||||
p.Wait()
|
p.Wait()
|
||||||
fmt.Println(gets, count)
|
fmt.Println(gets, count)
|
||||||
FlushMapVal("test", 3, 4)
|
DelMapCacheVal("test", 3, 4)
|
||||||
fmt.Println(vv.Get(ctx, 3))
|
fmt.Println(vv.Get(ctx, 3))
|
||||||
fmt.Println(vv.Get(ctx, 4))
|
fmt.Println(vv.Get(ctx, 4))
|
||||||
get, err := GetBy[int]("test", ctx, 3, time.Second)
|
get, err := GetBy[int]("test", ctx, 3, time.Second)
|
||||||
|
@ -54,7 +54,7 @@ func TestFlushMapVal(t *testing.T) {
|
||||||
}
|
}
|
||||||
fmt.Println(get, count)
|
fmt.Println(get, count)
|
||||||
fmt.Println(vv.Get(ctx, 5))
|
fmt.Println(vv.Get(ctx, 5))
|
||||||
FlushAnyVal("test")
|
Flushes(ctx, "test")
|
||||||
fmt.Println(vv.Get(ctx, 5))
|
fmt.Println(vv.Get(ctx, 5))
|
||||||
fmt.Println(vv.Get(ctx, 6))
|
fmt.Println(vv.Get(ctx, 6))
|
||||||
//fmt.Println(GetVarCache("test"))
|
//fmt.Println(GetVarCache("test"))
|
||||||
|
|
148
cache/cachemanager/mapcache.go
vendored
Normal file
148
cache/cachemanager/mapcache.go
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
package cachemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mapDelFuncs = safety.NewMap[string, func(any)]()
|
||||||
|
|
||||||
|
var mapCache = safety.NewMap[string, any]()
|
||||||
|
|
||||||
|
func SetMapCache[K comparable, V any](name string, ca *cache.MapCache[K, V]) error {
|
||||||
|
v, ok := mapCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
mapCache.Store(name, ca)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, ok = v.(*cache.MapCache[K, V])
|
||||||
|
if !ok {
|
||||||
|
return errors.New(str.Join("cache ", name, " type err"))
|
||||||
|
}
|
||||||
|
mapCache.Store(name, ca)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushMangerMap will del mapCache val with name When call DelMapCacheVal
|
||||||
|
func PushMangerMap[K comparable, V any](name string, m *cache.MapCache[K, V]) {
|
||||||
|
if name == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapCache.Store(name, m)
|
||||||
|
mapDelFuncs.Store(name, func(a any) {
|
||||||
|
k, ok := a.([]K)
|
||||||
|
if ok && len(k) > 0 {
|
||||||
|
mm, ok := mapCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, ok := mm.(*cache.MapCache[K, V])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(context.Background(), "ctx", "registerFlush")
|
||||||
|
c.Del(ctx, k...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBy[T any, K comparable](name string, ct context.Context, key K, timeout time.Duration, params ...any) (r T, err error) {
|
||||||
|
ct = context.WithValue(ct, "getCache", name)
|
||||||
|
ca, err := getMap[K, T](name)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
vv, err := ca.GetCache(ct, key, timeout, params...)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r = vv
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMap[K comparable, T any](name string) (*cache.MapCache[K, T], error) {
|
||||||
|
m, ok := mapCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
||||||
|
}
|
||||||
|
vk, ok := m.(*cache.MapCache[K, T])
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(str.Join("cache ", name, " type error"))
|
||||||
|
}
|
||||||
|
return vk, nil
|
||||||
|
}
|
||||||
|
func GetBatchBy[T any, K comparable](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r []T, err error) {
|
||||||
|
ct = context.WithValue(ct, "getCache", name)
|
||||||
|
ca, err := getMap[K, T](name)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
vv, err := ca.GetCacheBatch(ct, key, timeout, params...)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r = vv
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func GetBatchByToMap[T any, K comparable](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r map[K]T, err error) {
|
||||||
|
ct = context.WithValue(ct, "getCache", name)
|
||||||
|
ca, err := getMap[K, T](name)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
vv, err := ca.GetBatchToMap(ct, key, timeout, params...)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r = vv
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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])(nil), args...)
|
||||||
|
m := cache.NewMapCache[K, V](data, fn, batchFn, inc, buildLockFn[K](args...), args...)
|
||||||
|
name, f := parseArgs(args...)
|
||||||
|
if name != "" {
|
||||||
|
PushMangerMap(name, m)
|
||||||
|
}
|
||||||
|
PushOrSetFlush(mockmap.Item[string, Fn]{
|
||||||
|
Name: name,
|
||||||
|
Value: m.Flush,
|
||||||
|
})
|
||||||
|
PushOrSetClearExpired(mockmap.Item[string, Fn]{
|
||||||
|
Name: name,
|
||||||
|
Value: m.ClearExpired,
|
||||||
|
})
|
||||||
|
if f != nil && name != "" {
|
||||||
|
SetExpireTime(any(data).(cache.SetTime), name, 0, f)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMemoryMapCache[K comparable, V any](batchFn cache.MapBatchFn[K, V],
|
||||||
|
fn cache.MapSingleFn[K, V], expireTime time.Duration, args ...any) *cache.MapCache[K, V] {
|
||||||
|
|
||||||
|
c := NewMapCache[K, V](cache.NewMemoryMapCache[K, V](func() time.Duration {
|
||||||
|
return expireTime
|
||||||
|
}), batchFn, fn, args...)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMapCache[K comparable, V any](name string) (*cache.MapCache[K, V], bool) {
|
||||||
|
vv, err := getMap[K, V](name)
|
||||||
|
return vv, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelMapCacheVal[T any](name string, keys ...T) {
|
||||||
|
v, ok := mapDelFuncs.Load(name)
|
||||||
|
if !ok || len(keys) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v(keys)
|
||||||
|
}
|
57
cache/cachemanager/pagination.go
vendored
Normal file
57
cache/cachemanager/pagination.go
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package cachemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewPaginationCache[K comparable, V any](m *cache.MapCache[string, helper.PaginationData[V]], maxNum int,
|
||||||
|
dbFn cache.DbFn[K, V], localFn cache.LocalFn[K, V], dbKeyFn, localKeyFn func(K, ...any) string, fetchNum int, name string, a ...any) *cache.Pagination[K, V] {
|
||||||
|
fn := helper.ParseArgs([]func() int(nil), a...)
|
||||||
|
var ma, fet func() int
|
||||||
|
if len(fn) > 0 {
|
||||||
|
ma = fn[0]
|
||||||
|
if len(fn) > 1 {
|
||||||
|
fet = fn[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ma == nil {
|
||||||
|
ma = reload.BuildFnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, nil)
|
||||||
|
}
|
||||||
|
if fet == nil {
|
||||||
|
fet = reload.BuildFnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil)
|
||||||
|
}
|
||||||
|
p := cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name)
|
||||||
|
mapCache.Store(name, p)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationCache[K comparable, V any](name string) (*cache.Pagination[K, V], bool) {
|
||||||
|
v, err := getPagination[K, V](name)
|
||||||
|
return v, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pagination[V any, K comparable](name string, ctx context.Context, timeout time.Duration, k K, page, limit int, a ...any) ([]V, int, error) {
|
||||||
|
v, err := getPagination[K, V](name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return v.Pagination(ctx, timeout, k, page, limit, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPagination[K comparable, T any](name string) (*cache.Pagination[K, T], error) {
|
||||||
|
m, ok := mapCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
||||||
|
}
|
||||||
|
vk, ok := m.(*cache.Pagination[K, T])
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(str.Join("cache ", name, " type error"))
|
||||||
|
}
|
||||||
|
return vk, nil
|
||||||
|
}
|
83
cache/cachemanager/varcache.go
vendored
Normal file
83
cache/cachemanager/varcache.go
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package cachemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var varCache = safety.NewMap[string, any]()
|
||||||
|
|
||||||
|
func SetVarCache[T any](name string, v *cache.VarCache[T]) error {
|
||||||
|
vv, ok := varCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
varCache.Store(name, v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, ok = vv.(*cache.VarCache[T])
|
||||||
|
if ok {
|
||||||
|
varCache.Store(name, v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(str.Join("cache ", name, " type err"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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])(nil), a...)
|
||||||
|
ref := helper.ParseArgs(cache.RefreshVar[T](nil), a...)
|
||||||
|
v := cache.NewVarCache(c, fn, inc, ref, a...)
|
||||||
|
|
||||||
|
name, _ := parseArgs(a...)
|
||||||
|
if name != "" {
|
||||||
|
varCache.Store(name, v)
|
||||||
|
}
|
||||||
|
PushOrSetFlush(mockmap.Item[string, Fn]{
|
||||||
|
Name: name,
|
||||||
|
Value: v.Flush,
|
||||||
|
})
|
||||||
|
cc, ok := any(c).(clearExpired)
|
||||||
|
if ok {
|
||||||
|
PushOrSetClearExpired(mockmap.Item[string, Fn]{
|
||||||
|
Name: name,
|
||||||
|
Value: cc.ClearExpired,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVarVal[T any](name string, ctx context.Context, duration time.Duration, a ...any) (r T, err error) {
|
||||||
|
ctx = context.WithValue(ctx, "getCache", name)
|
||||||
|
ca, ok := GetVarCache[T](name)
|
||||||
|
if !ok {
|
||||||
|
err = errors.New(str.Join("cache ", name, " is not exist"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v, err := ca.GetCache(ctx, duration, a...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r = v
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVarMemoryCache[T any](fn func(context.Context, ...any) (T, error), expired time.Duration, a ...any) *cache.VarCache[T] {
|
||||||
|
c := cache.NewVarMemoryCache[T](nil)
|
||||||
|
name, e := parseArgs(a...)
|
||||||
|
SetExpireTime(c, name, expired, e)
|
||||||
|
v := NewVarCache[T](c, fn, a...)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVarCache[T any](name string) (*cache.VarCache[T], bool) {
|
||||||
|
v, ok := varCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
vv, ok := v.(*cache.VarCache[T])
|
||||||
|
return vv, ok
|
||||||
|
}
|
177
cache/reload/reload.go
vendored
177
cache/reload/reload.go
vendored
|
@ -2,16 +2,19 @@ package reload
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type queue struct {
|
type Queue struct {
|
||||||
fn func()
|
Fn func()
|
||||||
order float64
|
Order float64
|
||||||
name string
|
Name string
|
||||||
|
AutoExec bool
|
||||||
|
Once bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var mut = &sync.Mutex{}
|
var mut = &sync.Mutex{}
|
||||||
|
@ -20,11 +23,55 @@ func GetGlobeMutex() *sync.Mutex {
|
||||||
return mut
|
return mut
|
||||||
}
|
}
|
||||||
|
|
||||||
var waitReloadCalls = safety.NewSlice(make([]queue, 0))
|
var reloadQueues = safety.NewSlice[Queue]()
|
||||||
var callMap = safety.NewMap[string, func()]()
|
|
||||||
|
var reloadQueueHookFns = safety.NewVar[[]func(queue Queue) (Queue, bool)](nil)
|
||||||
|
|
||||||
var setFnVal = safety.NewMap[string, any]()
|
var setFnVal = safety.NewMap[string, any]()
|
||||||
|
|
||||||
|
func DeleteReloadQueue(names ...string) {
|
||||||
|
hooks := reloadQueueHookFns.Load()
|
||||||
|
for _, name := range names {
|
||||||
|
hooks = append(hooks, func(queue Queue) (Queue, bool) {
|
||||||
|
if name != queue.Name {
|
||||||
|
return queue, true
|
||||||
|
}
|
||||||
|
return queue, false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
reloadQueueHookFns.Store(hooks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HookReloadQueue(fn func(queue Queue) (Queue, bool)) {
|
||||||
|
a := reloadQueueHookFns.Load()
|
||||||
|
a = append(a, fn)
|
||||||
|
reloadQueueHookFns.Store(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetReloadFn(name string) func() {
|
||||||
|
hookQueue()
|
||||||
|
i, queue := slice.SearchFirst(reloadQueues.Load(), func(queue Queue) bool {
|
||||||
|
return queue.Name == name
|
||||||
|
})
|
||||||
|
if i > -1 && queue.Fn != nil {
|
||||||
|
return queue.Fn
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hookQueue() {
|
||||||
|
hooks := reloadQueueHookFns.Load()
|
||||||
|
queues := reloadQueues.Load()
|
||||||
|
length := len(queues)
|
||||||
|
for _, hook := range hooks {
|
||||||
|
queues = slice.FilterAndMap(queues, hook)
|
||||||
|
}
|
||||||
|
if len(queues) != length {
|
||||||
|
reloadQueues.Store(queues)
|
||||||
|
}
|
||||||
|
reloadQueueHookFns.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
type SafetyVar[T, A any] struct {
|
type SafetyVar[T, A any] struct {
|
||||||
Val *safety.Var[Val[T]]
|
Val *safety.Var[Val[T]]
|
||||||
Mutex sync.Mutex
|
Mutex sync.Mutex
|
||||||
|
@ -64,12 +111,20 @@ func DeleteMapVal[T any](namespace string, key ...T) {
|
||||||
func Reloads(namespaces ...string) {
|
func Reloads(namespaces ...string) {
|
||||||
mut.Lock()
|
mut.Lock()
|
||||||
defer mut.Unlock()
|
defer mut.Unlock()
|
||||||
for _, namespace := range namespaces {
|
hookQueue()
|
||||||
fn, ok := callMap.Load(namespace)
|
queues := reloadQueues.Load()
|
||||||
if !ok {
|
for _, name := range namespaces {
|
||||||
|
i, queue := slice.SearchFirst(queues, func(queue Queue) bool {
|
||||||
|
return name == queue.Name
|
||||||
|
})
|
||||||
|
if i < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fn()
|
queue.Fn()
|
||||||
|
if queue.Once {
|
||||||
|
slice.Delete(&queues, i)
|
||||||
|
reloadQueues.Store(queues)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +220,7 @@ func BuildSafetyMap[K comparable, V, A any](namespace string, args ...any) *Safe
|
||||||
m.Val.Delete(key)
|
m.Val.Delete(key)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Push(m.Val.Flush, args...)
|
Append(m.Val.Flush, args...)
|
||||||
safetyMaps.Store(namespace, m)
|
safetyMaps.Store(namespace, m)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
@ -189,7 +244,7 @@ func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn fun
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildAnyVal[T, A any](namespace string, counter bool, args ...any) *SafetyVar[T, A] {
|
func BuildAnyVal[T, A any](namespace string, args ...any) *SafetyVar[T, A] {
|
||||||
var vv *SafetyVar[T, A]
|
var vv *SafetyVar[T, A]
|
||||||
vvv, ok := safetyMaps.Load(namespace)
|
vvv, ok := safetyMaps.Load(namespace)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -205,13 +260,13 @@ func BuildAnyVal[T, A any](namespace string, counter bool, args ...any) *SafetyV
|
||||||
v := Val[T]{}
|
v := Val[T]{}
|
||||||
vv = &SafetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
|
vv = &SafetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
|
||||||
args = append(args, namespace)
|
args = append(args, namespace)
|
||||||
Push(vv.Val.Flush, args...)
|
Append(vv.Val.Flush, args...)
|
||||||
safetyMaps.Store(namespace, vv)
|
safetyMaps.Store(namespace, vv)
|
||||||
return vv
|
return vv
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
|
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
|
||||||
var vv = BuildAnyVal[T, A](namespace, false, args...)
|
var vv = BuildAnyVal[T, A](namespace, args...)
|
||||||
v := vv.Val.Load()
|
v := vv.Val.Load()
|
||||||
if v.Ok {
|
if v.Ok {
|
||||||
return v.V
|
return v.V
|
||||||
|
@ -231,11 +286,13 @@ func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ..
|
||||||
//
|
//
|
||||||
// if give a int and value bigger than 1 will be a times which built fn called return false
|
// if give a int and value bigger than 1 will be a times which built fn called return false
|
||||||
func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), args ...any) func(A) T {
|
func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), args ...any) func(A) T {
|
||||||
var vv = BuildAnyVal[T, A](namespace, false, args...)
|
var vv = BuildAnyVal[T, A](namespace, args...)
|
||||||
tryTimes := helper.ParseArgs(1, args...)
|
tryTimes := helper.ParseArgs(1, args...)
|
||||||
var counter func() int
|
var counter int64
|
||||||
if tryTimes > 1 {
|
if tryTimes > 1 {
|
||||||
counter = number.Counters[int]()
|
Append(func() {
|
||||||
|
atomic.StoreInt64(&counter, 0)
|
||||||
|
}, str.Join("reload-valFn-counter-", namespace))
|
||||||
}
|
}
|
||||||
return func(a A) T {
|
return func(a A) T {
|
||||||
v := vv.Val.Load()
|
v := vv.Val.Load()
|
||||||
|
@ -253,11 +310,11 @@ func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), arg
|
||||||
vv.Val.Store(v)
|
vv.Val.Store(v)
|
||||||
return v.V
|
return v.V
|
||||||
}
|
}
|
||||||
if counter == nil {
|
if atomic.LoadInt64(&counter) <= 1 {
|
||||||
return v.V
|
return v.V
|
||||||
}
|
}
|
||||||
times := counter()
|
atomic.AddInt64(&counter, 1)
|
||||||
if times >= tryTimes {
|
if atomic.LoadInt64(&counter) >= int64(tryTimes) {
|
||||||
v.Ok = true
|
v.Ok = true
|
||||||
vv.Val.Store(v)
|
vv.Val.Store(v)
|
||||||
}
|
}
|
||||||
|
@ -274,7 +331,7 @@ func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), arg
|
||||||
//
|
//
|
||||||
// if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually
|
// if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually
|
||||||
func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T {
|
func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T {
|
||||||
var vv = BuildAnyVal[T, A](namespace, false, args...)
|
var vv = BuildAnyVal[T, A](namespace, args...)
|
||||||
return func(a A) T {
|
return func(a A) T {
|
||||||
v := vv.Val.Load()
|
v := vv.Val.Load()
|
||||||
if v.Ok {
|
if v.Ok {
|
||||||
|
@ -295,7 +352,7 @@ func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T
|
||||||
|
|
||||||
// BuildValFnWithAnyParams same as BuildValFn use multiple params
|
// BuildValFnWithAnyParams same as BuildValFn use multiple params
|
||||||
func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ...any) func(...any) T {
|
func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ...any) func(...any) T {
|
||||||
var vv = BuildAnyVal[T, any](namespace, false, args...)
|
var vv = BuildAnyVal[T, any](namespace, args...)
|
||||||
return func(a ...any) T {
|
return func(a ...any) T {
|
||||||
v := vv.Val.Load()
|
v := vv.Val.Load()
|
||||||
if v.Ok {
|
if v.Ok {
|
||||||
|
@ -316,17 +373,19 @@ func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ..
|
||||||
|
|
||||||
// Vars get default value and whenever reloaded assign default value
|
// Vars get default value and whenever reloaded assign default value
|
||||||
//
|
//
|
||||||
// args same as Push
|
// args same as Append
|
||||||
//
|
//
|
||||||
// if give a name, then can be flushed by calls Reloads
|
// if give a name, then can be flushed by calls Reloads
|
||||||
//
|
//
|
||||||
// if give a float then can be reloaded early or lately, more bigger more earlier
|
// if give a float then can be reloaded early or lately, more bigger more earlier
|
||||||
//
|
//
|
||||||
// if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually
|
// if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually
|
||||||
|
//
|
||||||
|
// if give a int 1 will only execute once when called Reload or Reloads and then delete the flush fn
|
||||||
func Vars[T any](defaults T, args ...any) *safety.Var[T] {
|
func Vars[T any](defaults T, args ...any) *safety.Var[T] {
|
||||||
ss := safety.NewVar(defaults)
|
ss := safety.NewVar(defaults)
|
||||||
|
|
||||||
Push(func() {
|
Append(func() {
|
||||||
ss.Store(defaults)
|
ss.Store(defaults)
|
||||||
}, args...)
|
}, args...)
|
||||||
return ss
|
return ss
|
||||||
|
@ -350,11 +409,11 @@ func parseArgs(a ...any) (ord float64, name string) {
|
||||||
|
|
||||||
// VarsBy
|
// VarsBy
|
||||||
//
|
//
|
||||||
// args same as Push
|
// args same as Append
|
||||||
// if give a name, then can be flushed by calls Reloads
|
// if give a name, then can be flushed by calls Reloads
|
||||||
func VarsBy[T any](fn func() T, args ...any) *safety.Var[T] {
|
func VarsBy[T any](fn func() T, args ...any) *safety.Var[T] {
|
||||||
ss := safety.NewVar(fn())
|
ss := safety.NewVar(fn())
|
||||||
Push(func() {
|
Append(func() {
|
||||||
ss.Store(fn())
|
ss.Store(fn())
|
||||||
}, args...)
|
}, args...)
|
||||||
return ss
|
return ss
|
||||||
|
@ -364,7 +423,7 @@ func MapBy[K comparable, T any](fn func(*safety.Map[K, T]), args ...any) *safety
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
fn(m)
|
fn(m)
|
||||||
}
|
}
|
||||||
Push(func() {
|
Append(func() {
|
||||||
m.Flush()
|
m.Flush()
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
fn(m)
|
fn(m)
|
||||||
|
@ -375,42 +434,66 @@ func MapBy[K comparable, T any](fn func(*safety.Map[K, T]), args ...any) *safety
|
||||||
|
|
||||||
func SafeMap[K comparable, T any](args ...any) *safety.Map[K, T] {
|
func SafeMap[K comparable, T any](args ...any) *safety.Map[K, T] {
|
||||||
m := safety.NewMap[K, T]()
|
m := safety.NewMap[K, T]()
|
||||||
Push(m.Flush, args...)
|
Append(m.Flush, args...)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the func that will be called whenever Reload called
|
// Append the func that will be called whenever Reload called
|
||||||
//
|
//
|
||||||
// if give a name, then can be called by called Reloads
|
// if give a name, then can be called by called Reloads
|
||||||
//
|
//
|
||||||
// if give a float then can be called early or lately when called Reload, more bigger more earlier
|
// if give a float then can be called early or lately when called Reload, more bigger more earlier
|
||||||
//
|
//
|
||||||
// if give a bool false will not flushed when called Reload, then can called GetValMap to flush manually
|
// if give a bool false will not execute when called Reload, then can called Reloads to execute manually
|
||||||
func Push(fn func(), a ...any) {
|
//
|
||||||
|
// if give a int 1 will only execute once when called Reload or Reloads and then delete the Queue
|
||||||
|
func Append(fn func(), a ...any) {
|
||||||
ord, name := parseArgs(a...)
|
ord, name := parseArgs(a...)
|
||||||
auto := helper.ParseArgs(true, a...)
|
autoExec := helper.ParseArgs(true, a...)
|
||||||
if name != "" && !auto {
|
once := helper.ParseArgs(0, a...)
|
||||||
callMap.Store(name, fn)
|
queues := reloadQueues.Load()
|
||||||
return
|
queue := Queue{fn, ord, name, autoExec, once == 1}
|
||||||
}
|
|
||||||
waitReloadCalls.Append(queue{fn, ord, name})
|
|
||||||
if name != "" {
|
if name != "" {
|
||||||
callMap.Store(name, fn)
|
i, _ := slice.SearchFirst(queues, func(queue Queue) bool {
|
||||||
|
return queue.Name == name
|
||||||
|
})
|
||||||
|
if i > -1 {
|
||||||
|
queues[i] = queue
|
||||||
|
reloadQueues.Store(queues)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
reloadQueues.Append(queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendOnceFn function and args same as Append, but func will execute only once when called Reload or Reloads and then will be deleted. Especially suitable for using to develop plugins, when uninstall plugin can clean or recover some progress's self relative data or behavior which was changed by plugin.
|
||||||
|
func AppendOnceFn(fn func(), a ...any) {
|
||||||
|
a = append([]any{1}, a...)
|
||||||
|
Append(fn, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Reload() {
|
func Reload() {
|
||||||
mut.Lock()
|
mut.Lock()
|
||||||
defer mut.Unlock()
|
defer mut.Unlock()
|
||||||
deleteMapFn.Flush()
|
deleteMapFn.Flush()
|
||||||
reloadCalls := waitReloadCalls.Load()
|
hookQueue()
|
||||||
slice.SimpleSort(reloadCalls, slice.DESC, func(t queue) float64 {
|
queues := reloadQueues.Load()
|
||||||
return t.order
|
length := len(queues)
|
||||||
|
slice.SimpleSort(queues, slice.DESC, func(t Queue) float64 {
|
||||||
|
return t.Order
|
||||||
})
|
})
|
||||||
for _, call := range reloadCalls {
|
for i, queue := range queues {
|
||||||
call.fn()
|
if !queue.AutoExec {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
queue.Fn()
|
||||||
|
if queue.Once {
|
||||||
|
slice.Delete(&queues, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if length != len(queues) {
|
||||||
|
reloadQueues.Store(queues)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Any[T any] struct {
|
type Any[T any] struct {
|
||||||
|
@ -434,11 +517,11 @@ func BuildFnVal[T any](name string, t T, fn func() T) func() T {
|
||||||
v: p,
|
v: p,
|
||||||
isManual: safety.NewVar(false),
|
isManual: safety.NewVar(false),
|
||||||
}
|
}
|
||||||
Push(func() {
|
Append(func() {
|
||||||
if !e.isManual.Load() {
|
if !e.isManual.Load() {
|
||||||
e.v.Store(fn())
|
e.v.Store(fn())
|
||||||
}
|
}
|
||||||
})
|
}, str.Join("fnval-", name))
|
||||||
setFnVal.Store(name, e)
|
setFnVal.Store(name, e)
|
||||||
return func() T {
|
return func() T {
|
||||||
return e.v.Load()
|
return e.v.Load()
|
||||||
|
|
|
@ -66,6 +66,48 @@ cacheTime:
|
||||||
digestWordCount: 300
|
digestWordCount: 300
|
||||||
# 摘要允许的标签 默认为<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>
|
# 摘要允许的标签 默认为<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>
|
||||||
digestTag: "<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>"
|
digestTag: "<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>"
|
||||||
|
|
||||||
|
# 设置html转义实体正则 the html coded character set regex file: plugin/digest/digest.go:12
|
||||||
|
#digestRegex: ""*|&*|<*|>*| *|[*|]*| *"
|
||||||
|
|
||||||
|
# 可以设置每个标签或者转义字符占用的字数,默认都为0 set tag or escape character occupied num, default every tag occupied 0
|
||||||
|
#digestTagOccupyNum: [
|
||||||
|
# {
|
||||||
|
# tag: "<top>", # 最外层固定tag outermost immovable tag
|
||||||
|
# num: 0,
|
||||||
|
# chuckOvered: false,
|
||||||
|
# escapeCharacter: [
|
||||||
|
# {
|
||||||
|
# character: [ "\n","\r","\t" ],
|
||||||
|
# num: 0
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
# },{
|
||||||
|
# tag: "<img>",
|
||||||
|
# num: 1,
|
||||||
|
# chuckOvered: false
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# tag: "<pre><code>",
|
||||||
|
# num: 0,
|
||||||
|
# escapeCharacter: [
|
||||||
|
# {
|
||||||
|
# character: ["\t"],
|
||||||
|
# num: 4,
|
||||||
|
# chuckOvered: false,
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# character: ["\n","\r"],
|
||||||
|
# num: 1
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# tags: "<br>",
|
||||||
|
# num: 1
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
#]
|
||||||
|
|
||||||
# 到达指定并发请求数时随机sleep
|
# 到达指定并发请求数时随机sleep
|
||||||
maxRequestSleepNum: 100
|
maxRequestSleepNum: 100
|
||||||
# 全局最大请求数,超过直接403
|
# 全局最大请求数,超过直接403
|
||||||
|
@ -79,13 +121,13 @@ gzip: false
|
||||||
# 提交评论url host需为ip形式
|
# 提交评论url host需为ip形式
|
||||||
postCommentUrl: http://127.0.0.1/wp-comments-post.php
|
postCommentUrl: http://127.0.0.1/wp-comments-post.php
|
||||||
# TrustIps
|
# TrustIps
|
||||||
trustIps: []
|
trustIps: [ ]
|
||||||
# 分页器间隔数
|
# 分页器间隔数
|
||||||
paginationStep: 1
|
paginationStep: 1
|
||||||
# 显示查询的sql语句
|
# 显示查询的sql语句
|
||||||
showQuerySql: false
|
showQuerySql: false
|
||||||
# trust servername 信任的域名
|
# trust servername 信任的域名
|
||||||
trustServerNames: ["xy.test","blog.xy.test"]
|
trustServerNames: [ "xy.test","blog.xy.test" ]
|
||||||
# 主题 为空值为option template,没有就默认为twentyfifteen
|
# 主题 为空值为option template,没有就默认为twentyfifteen
|
||||||
theme: "twentyfifteen"
|
theme: "twentyfifteen"
|
||||||
# 文档排序默认升序还是降序
|
# 文档排序默认升序还是降序
|
||||||
|
@ -95,10 +137,10 @@ wpDir: "/var/www/html/wordpress"
|
||||||
# pprof route path 为空表示不开启pprof,否则为pprof的路由
|
# pprof route path 为空表示不开启pprof,否则为pprof的路由
|
||||||
pprof: "/debug/pprof"
|
pprof: "/debug/pprof"
|
||||||
# 要使用的程序插件名
|
# 要使用的程序插件名
|
||||||
plugins: ["enlightjs"]
|
plugins: [ "enlightjs" ]
|
||||||
# 插件存放路径
|
# 插件存放路径
|
||||||
pluginPath: "./plugins"
|
pluginPath: "./plugins"
|
||||||
# 列表页面post使用的插件
|
# 列表页面post使用的插件
|
||||||
listPagePlugins: ["digest"]
|
listPagePlugins: [ "digest" ]
|
||||||
# 额外引入的脚本 第一个为head 第二个为footer
|
# 额外引入的脚本 第一个为head 第二个为footer
|
||||||
externScript: ["",""]
|
externScript: [ "","" ]
|
58
go.mod
58
go.mod
|
@ -1,49 +1,53 @@
|
||||||
module github.com/fthvgb1/wp-go
|
module github.com/fthvgb1/wp-go
|
||||||
|
|
||||||
go 1.20
|
go 1.21.0
|
||||||
|
|
||||||
|
toolchain go1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dlclark/regexp2 v1.10.0
|
github.com/dlclark/regexp2 v1.11.4
|
||||||
github.com/elliotchance/phpserialize v1.3.3
|
github.com/elliotchance/phpserialize v1.4.0
|
||||||
github.com/gin-contrib/gzip v0.0.6
|
github.com/gin-contrib/gzip v1.0.1
|
||||||
github.com/gin-contrib/pprof v1.4.0
|
github.com/gin-contrib/pprof v1.5.0
|
||||||
github.com/gin-contrib/sessions v0.0.5
|
github.com/gin-contrib/sessions v1.0.1
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.10.0
|
||||||
github.com/go-playground/locales v0.14.1
|
github.com/go-playground/locales v0.14.1
|
||||||
github.com/go-playground/universal-translator v0.18.1
|
github.com/go-playground/universal-translator v0.18.1
|
||||||
github.com/go-playground/validator/v10 v10.16.0
|
github.com/go-playground/validator/v10 v10.22.0
|
||||||
github.com/go-sql-driver/mysql v1.7.1
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.3
|
||||||
github.com/jmoiron/sqlx v1.3.5
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
golang.org/x/crypto v0.15.0
|
golang.org/x/crypto v0.26.0
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.10.2 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
github.com/bytedance/sonic v1.12.2 // indirect
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/gorilla/context v1.1.2 // indirect
|
github.com/gorilla/context v1.1.2 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/gorilla/sessions v1.2.2 // indirect
|
github.com/gorilla/sessions v1.3.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
golang.org/x/arch v0.6.0 // indirect
|
golang.org/x/arch v0.9.0 // indirect
|
||||||
golang.org/x/net v0.18.0 // indirect
|
golang.org/x/net v0.28.0 // indirect
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
golang.org/x/sys v0.24.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.17.0 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
209
go.sum
209
go.sum
|
@ -1,209 +0,0 @@
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
|
||||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
|
||||||
github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk=
|
|
||||||
github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
|
||||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
|
||||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
|
||||||
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
|
|
||||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
|
||||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
|
||||||
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
|
||||||
github.com/elliotchance/phpserialize v1.3.3 h1:hV4QVmGdCiYgoBbw+ADt6fNgyZ2mYX0OgpnON1adTCM=
|
|
||||||
github.com/elliotchance/phpserialize v1.3.3/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
|
||||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
|
||||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
|
||||||
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=
|
|
||||||
github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90=
|
|
||||||
github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE=
|
|
||||||
github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY=
|
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
|
||||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
|
||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
|
||||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
|
||||||
github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM=
|
|
||||||
github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
|
||||||
github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
|
|
||||||
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
|
||||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
|
||||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
|
||||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
|
||||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
|
||||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
|
||||||
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
|
||||||
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
|
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
|
||||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
|
||||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
|
||||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
|
||||||
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
|
||||||
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
|
||||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
|
||||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
|
||||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
|
||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
|
||||||
golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
|
|
||||||
golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
|
||||||
golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y=
|
|
||||||
golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
|
||||||
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
|
|
||||||
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
|
||||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
|
||||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|
||||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
|
||||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
|
||||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
|
@ -2,11 +2,13 @@ package helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -51,12 +53,14 @@ func CutUrlHost(u string) string {
|
||||||
return ur.String()
|
return ur.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Defaults[T comparable](v, defaults T) T {
|
func Defaults[T comparable](vals ...T) T {
|
||||||
var zero T
|
var val T
|
||||||
if v == zero {
|
for _, v := range vals {
|
||||||
return defaults
|
if v != val {
|
||||||
|
return v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return v
|
return val
|
||||||
}
|
}
|
||||||
func DefaultVal[T any](v, defaults T) T {
|
func DefaultVal[T any](v, defaults T) T {
|
||||||
var zero T
|
var zero T
|
||||||
|
@ -129,6 +133,11 @@ func FileExist(path string) bool {
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsFile(file string) bool {
|
||||||
|
info, err := os.Stat(file)
|
||||||
|
return err == nil && !info.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
func GetAnyVal[T any](v any, defaults T) T {
|
func GetAnyVal[T any](v any, defaults T) T {
|
||||||
vv, ok := v.(T)
|
vv, ok := v.(T)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -188,3 +197,46 @@ func RunFnWithTimeouts[A, V any](ctx context.Context, t time.Duration, ar A, cal
|
||||||
}
|
}
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JsonDecode[T any](byts []byte) (T, error) {
|
||||||
|
var v T
|
||||||
|
err := json.Unmarshal(byts, &v)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsError[T any](err error) (T, bool) {
|
||||||
|
var v T
|
||||||
|
ok := errors.As(err, &v)
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsDirExistAndMkdir(dir string, perm os.FileMode) error {
|
||||||
|
stat, err := os.Stat(dir)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return os.MkdirAll(dir, perm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !stat.IsDir() {
|
||||||
|
return fmt.Errorf("%s is exist but not dir", dir)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadDir(dir string) ([]string, error) {
|
||||||
|
fii, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var files []string
|
||||||
|
for _, entry := range fii {
|
||||||
|
name := entry.Name()
|
||||||
|
if name == "." || name == ".." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
files = append(files, filepath.Join(dir, name))
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
|
@ -133,6 +133,13 @@ func StripTagsX(str, allowable string) string {
|
||||||
|
|
||||||
var selfCloseTags = map[string]string{"area": "", "base": "", "basefont": "", "br": "", "col": "", "command": "", "fecolormatrix": "", "embed": "", "frame": "", "hr": "", "img": "", "input": "", "isindex": "", "link": "", "fecomposite": "", "fefuncr": "", "fefuncg": "", "fefuncb": "", "fefunca": "", "meta": "", "param": "", "!doctype": "", "source": "", "track": "", "wbr": ""}
|
var selfCloseTags = map[string]string{"area": "", "base": "", "basefont": "", "br": "", "col": "", "command": "", "fecolormatrix": "", "embed": "", "frame": "", "hr": "", "img": "", "input": "", "isindex": "", "link": "", "fecomposite": "", "fefuncr": "", "fefuncg": "", "fefuncb": "", "fefunca": "", "meta": "", "param": "", "!doctype": "", "source": "", "track": "", "wbr": ""}
|
||||||
|
|
||||||
|
func GetSelfCloseTags() map[string]string {
|
||||||
|
return selfCloseTags
|
||||||
|
}
|
||||||
|
func SetSelfCloseTags(m map[string]string) {
|
||||||
|
selfCloseTags = m
|
||||||
|
}
|
||||||
|
|
||||||
func CloseTag(str string) string {
|
func CloseTag(str string) string {
|
||||||
tags := tag.FindAllString(str, -1)
|
tags := tag.FindAllString(str, -1)
|
||||||
if len(tags) < 1 {
|
if len(tags) < 1 {
|
||||||
|
|
|
@ -36,7 +36,7 @@ func GetString(u string, q map[string]any, a ...any) (r string, code int, err er
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(u string, q map[string]any, a ...any) (res *http.Response, err error) {
|
func Get(u string, q map[string]any, a ...any) (res *http.Response, err error) {
|
||||||
cli, req, err := GetClient(u, q, a...)
|
cli, req, err := BuildClient(u, "get", q, a...)
|
||||||
res, err = cli.Do(req)
|
res, err = cli.Do(req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func GetToJsonAny[T any](u string, q map[string]any, a ...any) (r T, code int, e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rr.Body.Close()
|
defer rr.Body.Close()
|
||||||
err = json.Unmarshal(b, &r)
|
err = json.Unmarshal(b, &r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ func PostWwwString(u string, form map[string]any, a ...any) (r string, code int,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", code, err
|
return "", code, err
|
||||||
}
|
}
|
||||||
rr.Body.Close()
|
defer rr.Body.Close()
|
||||||
r = string(rs)
|
r = string(rs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -80,12 +80,12 @@ func PostFormDataString(u string, form map[string]any, a ...any) (r string, code
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", code, err
|
return "", code, err
|
||||||
}
|
}
|
||||||
rr.Body.Close()
|
defer rr.Body.Close()
|
||||||
r = string(rs)
|
r = string(rs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetClient(u string, q map[string]any, a ...any) (res *http.Client, req *http.Request, err error) {
|
func BuildClient(u, method string, q map[string]any, a ...any) (res *http.Client, req *http.Request, err error) {
|
||||||
parse, err := url.Parse(u)
|
parse, err := url.Parse(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -95,10 +95,10 @@ func GetClient(u string, q map[string]any, a ...any) (res *http.Client, req *htt
|
||||||
setValue(q, values)
|
setValue(q, values)
|
||||||
parse.RawQuery = values.Encode()
|
parse.RawQuery = values.Encode()
|
||||||
req = &http.Request{
|
req = &http.Request{
|
||||||
Method: "GET",
|
Method: strings.ToUpper(method),
|
||||||
URL: parse,
|
URL: parse,
|
||||||
}
|
}
|
||||||
setArgs(&cli, req, a...)
|
SetArgs(&cli, req, a...)
|
||||||
return &cli, req, err
|
return &cli, req, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,17 +113,9 @@ func Post(u string, types int, form map[string]any, a ...any) (res *http.Respons
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostClient(u string, types int, form map[string]any, a ...any) (cli *http.Client, req *http.Request, err error) {
|
// SetBody
|
||||||
parse, err := url.Parse(u)
|
// types 1 x-www-form-urlencoded, 2 form-data, 3 json, 4 binary
|
||||||
if err != nil {
|
func SetBody(req *http.Request, types int, form map[string]any) (err error) {
|
||||||
return
|
|
||||||
}
|
|
||||||
cli = &http.Client{}
|
|
||||||
req = &http.Request{
|
|
||||||
Method: "POST",
|
|
||||||
URL: parse,
|
|
||||||
Header: http.Header{},
|
|
||||||
}
|
|
||||||
switch types {
|
switch types {
|
||||||
case 1:
|
case 1:
|
||||||
values := url.Values{}
|
values := url.Values{}
|
||||||
|
@ -147,20 +139,104 @@ func PostClient(u string, types int, form map[string]any, a ...any) (cli *http.C
|
||||||
case 3:
|
case 3:
|
||||||
fo, err := json.Marshal(form)
|
fo, err := json.Marshal(form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return err
|
||||||
}
|
}
|
||||||
b := bytes.NewReader(fo)
|
b := bytes.NewReader(fo)
|
||||||
req.Body = io.NopCloser(b)
|
req.Body = io.NopCloser(b)
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
case 4:
|
case 4:
|
||||||
b, ok := maps.GetStrAnyVal[[]byte](form, "binary")
|
b, ok := maps.GetStrAnyVal[[]byte](form, "binary")
|
||||||
if !ok {
|
if ok {
|
||||||
return nil, nil, errors.New("no binary value")
|
req.Body = io.NopCloser(bytes.NewReader(b))
|
||||||
|
req.Header.Add("Content-Type", "application/octet-stream")
|
||||||
|
req.ContentLength = int64(len(b))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
req.Body = io.NopCloser(bytes.NewReader(b))
|
bb, ok := maps.GetStrAnyVal[*[]byte](form, "binary")
|
||||||
req.Header.Add("Content-Type", "application/octet-stream")
|
if ok {
|
||||||
|
req.Body = io.NopCloser(NewBodyBuffer(bb))
|
||||||
|
req.Header.Add("Content-Type", "application/octet-stream")
|
||||||
|
req.ContentLength = int64(len(*bb))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bf, ok := maps.GetStrAnyVal[*BodyBuffer](form, "binary")
|
||||||
|
if ok {
|
||||||
|
req.Body = bf
|
||||||
|
req.Header.Add("Content-Type", "application/octet-stream")
|
||||||
|
req.ContentLength = int64(len(*bf.Data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return errors.New("no binary value")
|
||||||
|
|
||||||
}
|
}
|
||||||
setArgs(cli, req, a...)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type BodyBuffer struct {
|
||||||
|
Offset int
|
||||||
|
Data *[]byte
|
||||||
|
ReadFn func([]byte) (int, error)
|
||||||
|
CloseFn func() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyBuffer) Close() error {
|
||||||
|
if b.CloseFn != nil {
|
||||||
|
return b.CloseFn()
|
||||||
|
}
|
||||||
|
b.Offset = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyBuffer) Read(p []byte) (int, error) {
|
||||||
|
return b.ReadFn(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyBuffer) Reads(p []byte) (int, error) {
|
||||||
|
data := (*b.Data)[b.Offset:]
|
||||||
|
if len(p) <= len(data) {
|
||||||
|
copy(p, data[0:len(p)])
|
||||||
|
b.Offset += len(p)
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
if len(data) <= 0 {
|
||||||
|
b.Offset = 0
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
copy(p, data)
|
||||||
|
b.Offset = 0
|
||||||
|
return len(data), io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBodyBuffer(byt *[]byte, readFn ...func(*BodyBuffer, []byte) (int, error)) *BodyBuffer {
|
||||||
|
var fn func([]byte) (int, error)
|
||||||
|
b := &BodyBuffer{Data: byt}
|
||||||
|
if len(readFn) > 1 {
|
||||||
|
fn = func(p []byte) (int, error) {
|
||||||
|
return readFn[0](b, p)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fn = b.Reads
|
||||||
|
}
|
||||||
|
b.ReadFn = fn
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostClient(u string, types int, form map[string]any, a ...any) (cli *http.Client, req *http.Request, err error) {
|
||||||
|
parse, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cli = &http.Client{}
|
||||||
|
req = &http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: parse,
|
||||||
|
Header: http.Header{},
|
||||||
|
}
|
||||||
|
err = SetBody(req, types, form)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
SetArgs(cli, req, a...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,18 +250,44 @@ func PostToJsonAny[T any](u string, types int, form map[string]any, a ...any) (r
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rr.Body.Close()
|
defer rr.Body.Close()
|
||||||
err = json.Unmarshal(b, &r)
|
err = json.Unmarshal(b, &r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func setArgs(cli *http.Client, req *http.Request, a ...any) {
|
func SetUrl(u string, req *http.Request) error {
|
||||||
|
parse, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.URL = parse
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RequestToJSON[T any](client *http.Client, req *http.Request, a ...any) (res *http.Response, r T, err error) {
|
||||||
|
SetArgs(client, req, a...)
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bt, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(bt, &r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetArgs(cli *http.Client, req *http.Request, a ...any) {
|
||||||
if len(a) < 1 {
|
if len(a) < 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, arg := range a {
|
for _, arg := range a {
|
||||||
h, ok := arg.(map[string]string)
|
h, ok := arg.(map[string]string)
|
||||||
if ok && len(h) > 0 {
|
if ok && len(h) > 0 {
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(http.Header)
|
||||||
|
}
|
||||||
for k, v := range h {
|
for k, v := range h {
|
||||||
req.Header.Add(k, v)
|
req.Header.Add(k, v)
|
||||||
}
|
}
|
||||||
|
@ -208,6 +310,9 @@ func setArgs(cli *http.Client, req *http.Request, a ...any) {
|
||||||
}
|
}
|
||||||
c, ok := arg.(string)
|
c, ok := arg.(string)
|
||||||
if ok && c != "" {
|
if ok && c != "" {
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(http.Header)
|
||||||
|
}
|
||||||
req.Header.Add("cookie", c)
|
req.Header.Add("cookie", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,10 @@ func Divide[T constraints.Integer | constraints.Float](i, j T) T {
|
||||||
return i / j
|
return i / j
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Ceil[T constraints.Integer](num1, num2 T) int {
|
||||||
|
return int((num1 + num2 - 1) / num2)
|
||||||
|
}
|
||||||
|
|
||||||
func DivideCeil[T constraints.Integer](num1, num2 T) T {
|
func DivideCeil[T constraints.Integer](num1, num2 T) T {
|
||||||
return T(math.Ceil(float64(num1) / float64(num2)))
|
return T(math.Ceil(float64(num1) / float64(num2)))
|
||||||
}
|
}
|
||||||
|
@ -113,8 +117,3 @@ func Counters[T constraints.Integer]() func() T {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Round(f float64, precision int) float64 {
|
|
||||||
p := math.Pow10(precision)
|
|
||||||
return math.Floor(f*p+0.5) / p
|
|
||||||
}
|
|
||||||
|
|
47
helper/slice/mockmap/map.go
Normal file
47
helper/slice/mockmap/map.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package mockmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Item[K comparable, T any] struct {
|
||||||
|
Name K
|
||||||
|
Value T
|
||||||
|
Order float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Map[K comparable, T any] []Item[K, T]
|
||||||
|
|
||||||
|
func (q *Map[K, T]) Get(name K) Item[K, T] {
|
||||||
|
_, v := slice.SearchFirst(*q, func(t Item[K, T]) bool {
|
||||||
|
return name == t.Name
|
||||||
|
})
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Map[K, T]) Set(name K, value T, orders ...float64) {
|
||||||
|
i := slice.IndexOfBy(*q, func(t Item[K, T]) bool {
|
||||||
|
return name == t.Name
|
||||||
|
})
|
||||||
|
if i > -1 {
|
||||||
|
(*q)[i].Value = value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
order := float64(0)
|
||||||
|
if len(orders) > 0 {
|
||||||
|
order = orders[0]
|
||||||
|
}
|
||||||
|
*q = append(*q, Item[K, T]{name, value, order})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Map[K, T]) Del(name K) {
|
||||||
|
i := slice.IndexOfBy(*q, func(t Item[K, T]) bool {
|
||||||
|
return name == t.Name
|
||||||
|
})
|
||||||
|
if i > -1 {
|
||||||
|
slice.Delete((*[]Item[K, T])(q), i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (q *Map[K, T]) DelByIndex(i int) {
|
||||||
|
slice.Delete((*[]Item[K, T])(q), i)
|
||||||
|
}
|
|
@ -22,6 +22,15 @@ func FilterAndMap[N any, T any](arr []T, fn func(T) (N, bool)) (r []N) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func FilterAndMaps[N any, T any](arr []T, fn func(int, T) (N, bool)) (r []N) {
|
||||||
|
for i, t := range arr {
|
||||||
|
x, ok := fn(i, t)
|
||||||
|
if ok {
|
||||||
|
r = append(r, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func Walk[T any](arr []T, fn func(*T)) {
|
func Walk[T any](arr []T, fn func(*T)) {
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
|
@ -298,6 +307,15 @@ func IndexOf[T comparable](a []T, v T) int {
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
func IndexOfBy[T any](a []T, fn func(T) bool) int {
|
||||||
|
for i, t := range a {
|
||||||
|
ok := fn(t)
|
||||||
|
if ok {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
func ForEach[T any](a []T, fn func(i int, v T)) {
|
func ForEach[T any](a []T, fn func(i int, v T)) {
|
||||||
for i, t := range a {
|
for i, t := range a {
|
||||||
|
|
|
@ -102,3 +102,9 @@ func DecompressBy[T, R any](a [][]T, fn func(T) (R, bool)) (r []R) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Replace[T any](a []T, offset int, replacement []T) {
|
||||||
|
aa := a[offset:]
|
||||||
|
aa = aa[:0]
|
||||||
|
aa = append(aa, replacement...)
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (r anyArr[T]) Less(i, j int) bool {
|
||||||
return r.fn(r.data[i], r.data[j])
|
return r.fn(r.data[i], r.data[j])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort fn i>j 为降序 desc,反之为升序 asc
|
// Sort fn i>j desc ↓,i<j asc ↑
|
||||||
func Sort[T any](arr []T, fn func(i, j T) bool) {
|
func Sort[T any](arr []T, fn func(i, j T) bool) {
|
||||||
slice := anyArr[T]{
|
slice := anyArr[T]{
|
||||||
data: arr,
|
data: arr,
|
||||||
|
@ -84,3 +84,16 @@ func SimpleSort[T any, O constraints.Ordered](a []T, order string, fn func(t T)
|
||||||
}
|
}
|
||||||
sort.Sort(slice)
|
sort.Sort(slice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SimpleSorts[T constraints.Ordered](a []T, order string) {
|
||||||
|
slice := anyArr[T]{
|
||||||
|
data: a,
|
||||||
|
fn: func(i, j T) bool {
|
||||||
|
if order == DESC {
|
||||||
|
return i > j
|
||||||
|
}
|
||||||
|
return i < j
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sort.Sort(slice)
|
||||||
|
}
|
||||||
|
|
|
@ -41,14 +41,14 @@ func (r *SqlxQuery) Selects(ctx context.Context, dest any, sql string, params ..
|
||||||
if v != "" {
|
if v != "" {
|
||||||
switch v {
|
switch v {
|
||||||
case "string":
|
case "string":
|
||||||
return ToMapSlice(db, dest.(*[]map[string]string), sql, params...)
|
return ToMapSlice(ctx, db, dest.(*[]map[string]string), sql, params...)
|
||||||
case "scanner":
|
case "scanner":
|
||||||
fn := ctx.Value("fn")
|
fn := ctx.Value("fn")
|
||||||
return Scanner[any](db, dest, sql, params...)(fn.(func(any)))
|
return Scanner[any](ctx, db, dest, sql, params...)(fn.(func(any)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Select(dest, sql, params...)
|
return db.SelectContext(ctx, dest, sql, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SqlxQuery) Gets(ctx context.Context, dest any, sql string, params ...any) error {
|
func (r *SqlxQuery) Gets(ctx context.Context, dest any, sql string, params ...any) error {
|
||||||
|
@ -57,15 +57,15 @@ func (r *SqlxQuery) Gets(ctx context.Context, dest any, sql string, params ...an
|
||||||
if v != "" {
|
if v != "" {
|
||||||
switch v {
|
switch v {
|
||||||
case "string":
|
case "string":
|
||||||
return GetToMap(db, dest.(*map[string]string), sql, params...)
|
return GetToMap(ctx, db, dest.(*map[string]string), sql, params...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return db.Get(dest, sql, params...)
|
return db.GetContext(ctx, dest, sql, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Scanner[T any](db *sqlx.DB, v T, s string, params ...any) func(func(T)) error {
|
func Scanner[T any](ctx context.Context, db *sqlx.DB, v T, s string, params ...any) func(func(T)) error {
|
||||||
return func(fn func(T)) error {
|
return func(fn func(T)) error {
|
||||||
rows, err := db.Queryx(s, params...)
|
rows, err := db.QueryxContext(ctx, s, params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,8 @@ func Scanner[T any](db *sqlx.DB, v T, s string, params ...any) func(func(T)) err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToMapSlice[V any](db *sqlx.DB, dest *[]map[string]V, sql string, params ...any) (err error) {
|
func ToMapSlice[V any](ctx context.Context, db *sqlx.DB, dest *[]map[string]V, sql string, params ...any) (err error) {
|
||||||
rows, err := db.Query(sql, params...)
|
rows, err := db.QueryContext(ctx, sql, params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,8 @@ func ToMapSlice[V any](db *sqlx.DB, dest *[]map[string]V, sql string, params ...
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetToMap[V any](db *sqlx.DB, dest *map[string]V, sql string, params ...any) (err error) {
|
func GetToMap[V any](ctx context.Context, db *sqlx.DB, dest *map[string]V, sql string, params ...any) (err error) {
|
||||||
rows := db.QueryRowx(sql, params...)
|
rows := db.QueryRowxContext(ctx, sql, params...)
|
||||||
columns, err := rows.Columns()
|
columns, err := rows.Columns()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -9,51 +9,69 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MultipleFileTemplate struct {
|
type MultipleFileTemplate struct {
|
||||||
Template map[string]*template.Template
|
Template maps
|
||||||
FuncMap template.FuncMap
|
|
||||||
}
|
}
|
||||||
type MultipleFsTemplate struct {
|
type MultipleFsTemplate struct {
|
||||||
MultipleFileTemplate
|
MultipleFileTemplate
|
||||||
Fs embed.FS
|
Fs embed.FS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TemplateMaps map[string]*template.Template
|
||||||
|
|
||||||
|
func (m TemplateMaps) Load(name string) (*template.Template, bool) {
|
||||||
|
v, ok := m[name]
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m TemplateMaps) Store(name string, v *template.Template) {
|
||||||
|
m[name] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
type maps interface {
|
||||||
|
Load(name string) (*template.Template, bool)
|
||||||
|
Store(name string, v *template.Template)
|
||||||
|
}
|
||||||
|
|
||||||
func (t *MultipleFileTemplate) AppendTemplate(name string, templates ...string) *MultipleFileTemplate {
|
func (t *MultipleFileTemplate) AppendTemplate(name string, templates ...string) *MultipleFileTemplate {
|
||||||
tmpl, ok := t.Template[name]
|
tmpl, ok := t.Template.Load(name)
|
||||||
if ok {
|
if ok {
|
||||||
t.Template[name] = template.Must(tmpl.ParseFiles(templates...))
|
t.Template.Store(name, template.Must(tmpl.ParseFiles(templates...)))
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MultipleFsTemplate) AppendTemplate(name string, templates ...string) *MultipleFsTemplate {
|
func (t *MultipleFsTemplate) AppendTemplate(name string, templates ...string) *MultipleFsTemplate {
|
||||||
tmpl, ok := t.Template[name]
|
tmpl, ok := t.Template.Load(name)
|
||||||
if ok {
|
if ok {
|
||||||
t.Template[name] = template.Must(tmpl.ParseFS(t.Fs, templates...))
|
t.Template.Store(name, template.Must(tmpl.ParseFS(t.Fs, templates...)))
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileTemplate() *MultipleFileTemplate {
|
func NewFileTemplates(m maps) *MultipleFileTemplate {
|
||||||
return &MultipleFileTemplate{
|
return &MultipleFileTemplate{
|
||||||
Template: make(map[string]*template.Template),
|
Template: m,
|
||||||
FuncMap: make(template.FuncMap),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func NewFsTemplate(f embed.FS) *MultipleFsTemplate {
|
func NewFsTemplate(f embed.FS) *MultipleFsTemplate {
|
||||||
return &MultipleFsTemplate{
|
return &MultipleFsTemplate{
|
||||||
MultipleFileTemplate: MultipleFileTemplate{
|
MultipleFileTemplate: MultipleFileTemplate{
|
||||||
Template: make(map[string]*template.Template),
|
Template: TemplateMaps(make(map[string]*template.Template)),
|
||||||
FuncMap: make(template.FuncMap),
|
},
|
||||||
|
Fs: f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func NewFsTemplates(f embed.FS, m maps) *MultipleFsTemplate {
|
||||||
|
return &MultipleFsTemplate{
|
||||||
|
MultipleFileTemplate: MultipleFileTemplate{
|
||||||
|
Template: m,
|
||||||
},
|
},
|
||||||
Fs: f,
|
Fs: f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MultipleFileTemplate) SetTemplate(name string, templ *template.Template) *MultipleFileTemplate {
|
func (t *MultipleFileTemplate) SetTemplate(name string, templ *template.Template) *MultipleFileTemplate {
|
||||||
if _, ok := t.Template[name]; ok {
|
t.Template.Store(name, templ)
|
||||||
panic("exists same template " + name)
|
|
||||||
}
|
|
||||||
t.Template[name] = templ
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,14 +83,15 @@ func (t *MultipleFileTemplate) AddTemplate(mainTemplatePattern string, fnMap tem
|
||||||
for _, mainTemplate := range mainTemplates {
|
for _, mainTemplate := range mainTemplates {
|
||||||
file := filepath.Base(mainTemplate)
|
file := filepath.Base(mainTemplate)
|
||||||
pattern := append([]string{mainTemplate}, layoutTemplatePattern...)
|
pattern := append([]string{mainTemplate}, layoutTemplatePattern...)
|
||||||
t.Template[mainTemplate] = template.Must(template.New(file).Funcs(fnMap).ParseFiles(pattern...))
|
t.Template.Store(mainTemplate, template.Must(template.New(file).Funcs(fnMap).ParseFiles(pattern...)))
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MultipleFileTemplate) Instance(name string, data any) render.Render {
|
func (t *MultipleFileTemplate) Instance(name string, data any) render.Render {
|
||||||
|
v, _ := t.Template.Load(name)
|
||||||
return render.HTML{
|
return render.HTML{
|
||||||
Template: t.Template[name],
|
Template: v,
|
||||||
Data: data,
|
Data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,12 +102,9 @@ func (t *MultipleFsTemplate) AddTemplate(mainTemplatePattern string, fnMap templ
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
for _, mainTemplate := range mainTemplates {
|
for _, mainTemplate := range mainTemplates {
|
||||||
if _, ok := t.Template[mainTemplate]; ok {
|
|
||||||
panic("exists same Template " + mainTemplate)
|
|
||||||
}
|
|
||||||
file := filepath.Base(mainTemplate)
|
file := filepath.Base(mainTemplate)
|
||||||
pattern := append([]string{mainTemplate}, layoutTemplatePattern...)
|
pattern := append([]string{mainTemplate}, layoutTemplatePattern...)
|
||||||
t.Template[mainTemplate] = template.Must(template.New(file).Funcs(fnMap).ParseFS(t.Fs, pattern...))
|
t.Template.Store(mainTemplate, template.Must(template.New(file).Funcs(fnMap).ParseFS(t.Fs, pattern...)))
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,28 @@ package digest
|
||||||
import (
|
import (
|
||||||
"github.com/fthvgb1/wp-go/helper/html"
|
"github.com/fthvgb1/wp-go/helper/html"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
var quto = regexp.MustCompile(`" *|& *|< *|> ?| *`)
|
var quto = regexp.MustCompile(`"*|&*|<*|>*| *|[*|]*| *`)
|
||||||
|
|
||||||
|
func SetQutos(reg string) {
|
||||||
|
quto = regexp.MustCompile(reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpecialSolveConf struct {
|
||||||
|
Num int
|
||||||
|
ChuckOvered bool
|
||||||
|
EscapeCharacter map[rune]SpecialSolve
|
||||||
|
Tags map[string]SpecialSolve
|
||||||
|
}
|
||||||
|
type SpecialSolve struct {
|
||||||
|
Num int
|
||||||
|
ChuckOvered bool
|
||||||
|
}
|
||||||
|
|
||||||
func StripTags(content, allowTag string) string {
|
func StripTags(content, allowTag string) string {
|
||||||
content = strings.Trim(content, " \t\n\r\000\x0B")
|
content = strings.Trim(content, " \t\n\r\000\x0B")
|
||||||
|
@ -24,6 +40,14 @@ func Html(content string, limit int) (string, string) {
|
||||||
return content, ""
|
return content, ""
|
||||||
}
|
}
|
||||||
index := quto.FindAllStringIndex(content, -1)
|
index := quto.FindAllStringIndex(content, -1)
|
||||||
|
var runeIndex [][]int
|
||||||
|
if len(index) > 0 {
|
||||||
|
runeIndex = slice.Map(index, func(t []int) []int {
|
||||||
|
return slice.Map(t, func(i int) int {
|
||||||
|
return utf8.RuneCountInString(content[:i])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
end := 0
|
end := 0
|
||||||
ru := []rune(content)
|
ru := []rune(content)
|
||||||
tagIn := false
|
tagIn := false
|
||||||
|
@ -32,18 +56,14 @@ func Html(content string, limit int) (string, string) {
|
||||||
i := -1
|
i := -1
|
||||||
for {
|
for {
|
||||||
i++
|
i++
|
||||||
for len(index) > 0 {
|
if end >= limit || i >= total {
|
||||||
ints := slice.Map(index[0], func(t int) int {
|
break
|
||||||
return utf8.RuneCountInString(content[:t])
|
}
|
||||||
})
|
for len(runeIndex) > 0 && i == runeIndex[0][0] {
|
||||||
if ints[0] <= i {
|
i = runeIndex[0][1]
|
||||||
i = i + i - ints[0] + ints[1] - ints[0]
|
runeIndex = runeIndex[1:]
|
||||||
index = index[1:]
|
end++
|
||||||
end++
|
continue
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if end >= limit || i >= total {
|
if end >= limit || i >= total {
|
||||||
|
@ -67,3 +87,120 @@ func Html(content string, limit int) (string, string) {
|
||||||
closeTag = html.CloseTag(content)
|
closeTag = html.CloseTag(content)
|
||||||
return content, closeTag
|
return content, closeTag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CustomizeHtml(content string, limit int, m map[string]SpecialSolveConf) (string, string) {
|
||||||
|
closeTag := ""
|
||||||
|
length := utf8.RuneCountInString(content) + 1
|
||||||
|
if length <= limit {
|
||||||
|
return content, ""
|
||||||
|
}
|
||||||
|
index := quto.FindAllStringIndex(content, -1)
|
||||||
|
var runeIndex [][]int
|
||||||
|
if len(index) > 0 {
|
||||||
|
runeIndex = slice.Map(index, func(t []int) []int {
|
||||||
|
return slice.Map(t, func(i int) int {
|
||||||
|
return utf8.RuneCountInString(content[:i])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
runeContent := []rune(content)
|
||||||
|
tagIn := false
|
||||||
|
runeTotal := len(runeContent)
|
||||||
|
l, r := '<', '>'
|
||||||
|
i := -1
|
||||||
|
selfCloseTags := html.GetSelfCloseTags()
|
||||||
|
var currentTag, parentTag string
|
||||||
|
var allTags = []string{"<top>"}
|
||||||
|
var tag []rune
|
||||||
|
var tagLocal = 0
|
||||||
|
for {
|
||||||
|
i++
|
||||||
|
if count >= limit || i >= runeTotal {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for len(runeIndex) > 0 && i == runeIndex[0][0] {
|
||||||
|
i = runeIndex[0][1]
|
||||||
|
runeIndex = runeIndex[1:]
|
||||||
|
count++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if count >= limit || i >= runeTotal {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if runeContent[i] == l {
|
||||||
|
tagLocal = i
|
||||||
|
tagIn = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tagIn && runeContent[i] == r {
|
||||||
|
tagIn = false
|
||||||
|
tags := str.Join("<", string(tag), ">")
|
||||||
|
if strings.Contains(tags, " ") {
|
||||||
|
tags = str.Join("<", strings.Split(string(tag), " ")[0], ">")
|
||||||
|
}
|
||||||
|
currentTag = tags
|
||||||
|
rawTag := strings.ReplaceAll(strings.Trim(tags, "<>"), "/", "")
|
||||||
|
_, ok := selfCloseTags[rawTag]
|
||||||
|
if !ok {
|
||||||
|
if '/' == tags[1] {
|
||||||
|
parentTag = allTags[len(allTags)-2]
|
||||||
|
allTags = allTags[:len(allTags)-1]
|
||||||
|
} else {
|
||||||
|
parentTag = allTags[len(allTags)-1]
|
||||||
|
allTags = append(allTags, currentTag)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentTag = allTags[len(allTags)-1]
|
||||||
|
}
|
||||||
|
tag = tag[:0]
|
||||||
|
if len(m) > 0 {
|
||||||
|
nn, ok := m[parentTag]
|
||||||
|
if ok {
|
||||||
|
if n, ok := nn.Tags[tags]; ok {
|
||||||
|
if (count+n.Num) > limit && n.ChuckOvered {
|
||||||
|
i = tagLocal
|
||||||
|
break
|
||||||
|
}
|
||||||
|
count += n.Num
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n, ok := m[tags]; ok {
|
||||||
|
if (count+n.Num) > limit && n.ChuckOvered {
|
||||||
|
i = tagLocal
|
||||||
|
break
|
||||||
|
}
|
||||||
|
count += n.Num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tagIn {
|
||||||
|
tag = append(tag, runeContent[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentTags := allTags[len(allTags)-1]
|
||||||
|
mm, ok := m[currentTags]
|
||||||
|
if !ok || len(mm.EscapeCharacter) < 1 {
|
||||||
|
count++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if n, ok := mm.EscapeCharacter[runeContent[i]]; ok {
|
||||||
|
if (count+n.Num) > limit && n.ChuckOvered {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
count += n.Num
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i > runeTotal {
|
||||||
|
i = runeTotal
|
||||||
|
}
|
||||||
|
content = string(runeContent[:i])
|
||||||
|
closeTag = html.CloseTag(content)
|
||||||
|
return content, closeTag
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ type Render interface {
|
||||||
Dots() string
|
Dots() string
|
||||||
Middle(page int, url string) string
|
Middle(page int, url string) string
|
||||||
Urls(u url.URL, page int, isTLS bool) string
|
Urls(u url.URL, page int, isTLS bool) string
|
||||||
Step() int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type parser struct {
|
type parser struct {
|
||||||
|
@ -28,10 +27,6 @@ type parser struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Paginate(e Render, totalRaw int, pageSize int, currentPage, step int, u url.URL, isTLS bool) string {
|
func Paginate(e Render, totalRaw int, pageSize int, currentPage, step int, u url.URL, isTLS bool) string {
|
||||||
st := e.Step()
|
|
||||||
if st > 0 {
|
|
||||||
step = st
|
|
||||||
}
|
|
||||||
return parser{
|
return parser{
|
||||||
Render: e,
|
Render: e,
|
||||||
TotalPage: number.DivideCeil(totalRaw, pageSize),
|
TotalPage: number.DivideCeil(totalRaw, pageSize),
|
||||||
|
|
12
readme_en.md
12
readme_en.md
|
@ -20,6 +20,12 @@ A WordPress front-end written in Go, with relatively simple functions, only the
|
||||||
- kill -SIGUSR1 PID update configuration and clear cache
|
- kill -SIGUSR1 PID update configuration and clear cache
|
||||||
- kill -SIGUSR2 PID clear cache
|
- kill -SIGUSR2 PID clear cache
|
||||||
|
|
||||||
|
|
||||||
|
#### start up
|
||||||
|
```
|
||||||
|
go run app/cmd/main.go [-c configpath] [-p port]
|
||||||
|
```
|
||||||
|
|
||||||
#### The data show the degree of support
|
#### The data show the degree of support
|
||||||
|
|
||||||
| page table | Support |
|
| page table | Support |
|
||||||
|
@ -71,6 +77,10 @@ It is divided into plug-ins that modify the data of list pages and plug-ins that
|
||||||
| digest Automatically generate a digest of the specified length | Enlighter code highlighting (enlighterjs plug-in needs to be installed in the background) |
|
| digest Automatically generate a digest of the specified length | Enlighter code highlighting (enlighterjs plug-in needs to be installed in the background) |
|
||||||
| | hiddenLogin hidden login entry |
|
| | hiddenLogin hidden login entry |
|
||||||
|
|
||||||
#### other
|
#### Others
|
||||||
|
|
||||||
The gin framework and sqlx used encapsulate the layer query method outside.
|
The gin framework and sqlx used encapsulate the layer query method outside.
|
||||||
|
|
||||||
|
#### Thanks
|
||||||
|
|
||||||
|
<a href="https://jb.gg/OpenSourceSupport"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png" alt="JetBrains Logo (Main) logo." width="30%"></a>
|
||||||
|
|
71
safety/rwmap.go
Normal file
71
safety/rwmap.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package safety
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type RWMap[K comparable, V any] struct {
|
||||||
|
m map[K]V
|
||||||
|
mux sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRWMap[K comparable, V any](val ...map[K]V) *RWMap[K, V] {
|
||||||
|
var m map[K]V
|
||||||
|
if len(val) < 1 {
|
||||||
|
m = make(map[K]V)
|
||||||
|
} else {
|
||||||
|
m = val[0]
|
||||||
|
}
|
||||||
|
return &RWMap[K, V]{m: m, mux: sync.RWMutex{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Store(key K, val V) {
|
||||||
|
v.mux.Lock()
|
||||||
|
defer v.mux.Unlock()
|
||||||
|
v.m[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Load(key K) (V, bool) {
|
||||||
|
v.mux.RLock()
|
||||||
|
defer v.mux.RUnlock()
|
||||||
|
val, ok := v.m[key]
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Delete(keys ...K) {
|
||||||
|
v.mux.Lock()
|
||||||
|
defer v.mux.Unlock()
|
||||||
|
for _, key := range keys {
|
||||||
|
delete(v.m, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Copy() map[K]V {
|
||||||
|
v.mux.RLock()
|
||||||
|
defer v.mux.RUnlock()
|
||||||
|
var m = make(map[K]V)
|
||||||
|
for k, val := range v.m {
|
||||||
|
m[k] = val
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Len() int {
|
||||||
|
v.mux.RLock()
|
||||||
|
defer v.mux.RUnlock()
|
||||||
|
return len(v.m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Range(fn func(K, V) bool) {
|
||||||
|
v.mux.RLock()
|
||||||
|
defer v.mux.RUnlock()
|
||||||
|
for key, val := range v.m {
|
||||||
|
if !fn(key, val) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *RWMap[K, V]) Set(m map[K]V) {
|
||||||
|
v.mux.Lock()
|
||||||
|
defer v.mux.Unlock()
|
||||||
|
v.m = m
|
||||||
|
}
|
|
@ -3,21 +3,37 @@ package safety
|
||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
type Slice[T any] struct {
|
type Slice[T any] struct {
|
||||||
*Var[[]T]
|
Var []T
|
||||||
mu sync.Mutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSlice[T any](a []T) *Slice[T] {
|
func NewSlice[T any](a ...[]T) *Slice[T] {
|
||||||
|
var s []T
|
||||||
|
if len(a) > 0 {
|
||||||
|
s = a[0]
|
||||||
|
}
|
||||||
return &Slice[T]{
|
return &Slice[T]{
|
||||||
NewVar(a),
|
s,
|
||||||
sync.Mutex{},
|
sync.RWMutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Slice[T]) Append(t ...T) {
|
func (r *Slice[T]) Append(t ...T) {
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
ts := append(r.Load(), t...)
|
r.Var = append(r.Var, t...)
|
||||||
r.Store(ts)
|
}
|
||||||
|
|
||||||
|
func (r *Slice[T]) Store(a []T) {
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
r.Var = a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Slice[T]) Load() (a []T) {
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
|
a = make([]T, len(r.Var))
|
||||||
|
copy(a, r.Var)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ func TestSlice_Append(t *testing.T) {
|
||||||
tests := []testCase[int]{
|
tests := []testCase[int]{
|
||||||
{
|
{
|
||||||
name: "t1",
|
name: "t1",
|
||||||
r: *NewSlice([]int{}),
|
r: *NewSlice[int](),
|
||||||
args: args[int]{number.Range(1, 10, 1)},
|
args: args[int]{number.Range(1, 10, 1)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,12 @@ type Var[T any] struct {
|
||||||
p unsafe.Pointer
|
p unsafe.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVar[T any](val T) *Var[T] {
|
func NewVar[T any](vals ...T) *Var[T] {
|
||||||
return &Var[T]{val: val, p: unsafe.Pointer(&val)}
|
var v T
|
||||||
|
if len(vals) > 0 {
|
||||||
|
v = vals[0]
|
||||||
|
}
|
||||||
|
return &Var[T]{val: v, p: unsafe.Pointer(&v)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Var[T]) Load() T {
|
func (r *Var[T]) Load() T {
|
||||||
|
|
135
signs/signs.go
Normal file
135
signs/signs.go
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
package signs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Call func() bool
|
||||||
|
|
||||||
|
type HookFn func(mockmap.Item[string, Call]) (os.Signal, mockmap.Item[string, Call], bool)
|
||||||
|
|
||||||
|
var queues = map[os.Signal]mockmap.Map[string, Call]{}
|
||||||
|
|
||||||
|
var ch = make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
var stopCh = make(chan struct{}, 1)
|
||||||
|
|
||||||
|
var hooks = map[os.Signal][]HookFn{}
|
||||||
|
|
||||||
|
var mux = sync.Mutex{}
|
||||||
|
|
||||||
|
func GetChannel() chan os.Signal {
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func Cancel(sings ...os.Signal) {
|
||||||
|
if len(sings) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
for _, sing := range sings {
|
||||||
|
delete(queues, sing)
|
||||||
|
}
|
||||||
|
signal.Reset(sings...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Hook(sign os.Signal, fn HookFn) {
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
hooks[sign] = append(hooks[sign], fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hook(item []mockmap.Item[string, Call], sign os.Signal) []mockmap.Item[string, Call] {
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
if len(item) < 1 {
|
||||||
|
delete(hooks, sign)
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
hooksFn, ok := hooks[sign]
|
||||||
|
if !ok {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
for _, fn := range hooksFn {
|
||||||
|
item = slice.FilterAndMap(item, func(t mockmap.Item[string, Call]) (mockmap.Item[string, Call], bool) {
|
||||||
|
s, c, ok := fn(t)
|
||||||
|
if sign != s {
|
||||||
|
install(s, t.Value, t.Name, t.Order)
|
||||||
|
return t, false
|
||||||
|
}
|
||||||
|
return c, ok
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
delete(hooks, sign)
|
||||||
|
slice.SimpleSort(item, slice.DESC, func(t mockmap.Item[string, Call]) float64 {
|
||||||
|
return t.Order
|
||||||
|
})
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
func Install(sign os.Signal, fn Call, a ...any) {
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
arr := helper.ParseArgs([]os.Signal{}, a...)
|
||||||
|
if len(arr) > 0 {
|
||||||
|
for _, o := range arr {
|
||||||
|
install(o, fn, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
install(sign, fn, a...)
|
||||||
|
}
|
||||||
|
func install(sign os.Signal, fn Call, a ...any) {
|
||||||
|
m, ok := queues[sign]
|
||||||
|
if !ok {
|
||||||
|
queues[sign] = make(mockmap.Map[string, Call], 0)
|
||||||
|
signal.Notify(ch, sign)
|
||||||
|
}
|
||||||
|
m.Set(helper.ParseArgs("", a...), fn, helper.ParseArgs[float64](0, a...))
|
||||||
|
queues[sign] = m
|
||||||
|
}
|
||||||
|
|
||||||
|
func del(queue mockmap.Map[string, Call], sign os.Signal, i int) {
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
queue.DelByIndex(i)
|
||||||
|
queues[sign] = queue
|
||||||
|
}
|
||||||
|
|
||||||
|
func Stop() {
|
||||||
|
stopCh <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Wait() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-stopCh:
|
||||||
|
break
|
||||||
|
case sign := <-ch:
|
||||||
|
queue, ok := queues[sign]
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
queue = hook(queue, sign)
|
||||||
|
queues[sign] = queue
|
||||||
|
if len(queue) < 1 {
|
||||||
|
signal.Reset(sign)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i, item := range queue {
|
||||||
|
if !item.Value() {
|
||||||
|
del(queue, sign, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(queues[sign]) < 1 {
|
||||||
|
signal.Reset(sign)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,8 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParallelFilterAndMap[R, T any](a Stream[T], fn func(T) (R, bool), c int) Stream[R] {
|
func ParallelFilterAndMap[R, T any](a Stream[T], fn func(T) (R, bool), c int) Stream[R] {
|
||||||
var x []R
|
rr := safety.NewSlice[R]()
|
||||||
rr := safety.NewSlice(x)
|
|
||||||
a.ParallelForEach(func(t T) {
|
a.ParallelForEach(func(t T) {
|
||||||
y, ok := fn(t)
|
y, ok := fn(t)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -84,7 +83,7 @@ func (r Stream[T]) ParallelForEach(fn func(T), c int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Stream[T]) ParallelFilterAndMap(fn func(T) (T, bool), c int) Stream[T] {
|
func (r Stream[T]) ParallelFilterAndMap(fn func(T) (T, bool), c int) Stream[T] {
|
||||||
rr := safety.NewSlice([]T{})
|
rr := safety.NewSlice[T]()
|
||||||
r.ParallelForEach(func(t T) {
|
r.ParallelForEach(func(t T) {
|
||||||
v, ok := fn(t)
|
v, ok := fn(t)
|
||||||
if ok {
|
if ok {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user