diff --git a/actions/comment.go b/actions/comment.go index a4eecea..e05ee65 100644 --- a/actions/comment.go +++ b/actions/comment.go @@ -45,7 +45,7 @@ func PostComment(c *gin.Context) { m := c.PostForm("email") comment := c.PostForm("comment") c.Request.Body = io.NopCloser(bytes.NewBuffer(data)) - req, err := http.NewRequest("POST", config.Conf.PostCommentUrl, strings.NewReader(c.Request.PostForm.Encode())) + req, err := http.NewRequest("POST", config.Conf.Load().PostCommentUrl, strings.NewReader(c.Request.PostForm.Encode())) if err != nil { return } @@ -70,7 +70,7 @@ func PostComment(c *gin.Context) { err = er return } - cu, er := url.Parse(config.Conf.PostCommentUrl) + cu, er := url.Parse(config.Conf.Load().PostCommentUrl) if er != nil { err = er return @@ -104,8 +104,8 @@ func PostComment(c *gin.Context) { return } su := fmt.Sprintf("%s: %s[%s]发表了评论对文档[%v]的评论", config.Options.Value("siteurl"), author, m, post.PostTitle) - err = mail.SendMail([]string{config.Conf.Mail.User}, su, comment) - logs.ErrPrintln(err, "发送邮件", config.Conf.Mail.User, su, comment) + err = mail.SendMail([]string{config.Conf.Load().Mail.User}, su, comment) + logs.ErrPrintln(err, "发送邮件", config.Conf.Load().Mail.User, su, comment) }() s, er := io.ReadAll(ress.Body) diff --git a/actions/common/common.go b/actions/common/common.go index 48b208c..03a8ae0 100644 --- a/actions/common/common.go +++ b/actions/common/common.go @@ -28,34 +28,35 @@ var usersCache *cache.MapCache[uint64, wp.Users] var commentsCache *cache.MapCache[uint64, wp.Comments] func InitActionsCommonCache() { + c := config.Conf.Load() archivesCaches = &Arch{ mutex: &sync.Mutex{}, setCacheFunc: archives, } - searchPostIdsCache = cache.NewMapCacheByFn[string, PostIds](searchPostIds, config.Conf.SearchPostCacheTime) + searchPostIdsCache = cache.NewMapCacheByFn[string, PostIds](searchPostIds, c.SearchPostCacheTime) - postListIdsCache = cache.NewMapCacheByFn[string, PostIds](searchPostIds, config.Conf.PostListCacheTime) + postListIdsCache = cache.NewMapCacheByFn[string, PostIds](searchPostIds, c.PostListCacheTime) - monthPostsCache = cache.NewMapCacheByFn[string, []uint64](monthPost, config.Conf.MonthPostCacheTime) + monthPostsCache = cache.NewMapCacheByFn[string, []uint64](monthPost, c.MonthPostCacheTime) - postContextCache = cache.NewMapCacheByFn[uint64, PostContext](getPostContext, config.Conf.ContextPostCacheTime) + postContextCache = cache.NewMapCacheByFn[uint64, PostContext](getPostContext, c.ContextPostCacheTime) - postsCache = cache.NewMapCacheByBatchFn[uint64, wp.Posts](getPostsByIds, config.Conf.PostDataCacheTime) + postsCache = cache.NewMapCacheByBatchFn[uint64, wp.Posts](getPostsByIds, c.PostDataCacheTime) - categoryCaches = cache.NewSliceCache[wp.WpTermsMy](categories, config.Conf.CategoryCacheTime) + categoryCaches = cache.NewSliceCache[wp.WpTermsMy](categories, c.CategoryCacheTime) - recentPostsCaches = cache.NewSliceCache[wp.Posts](recentPosts, config.Conf.RecentPostCacheTime) + recentPostsCaches = cache.NewSliceCache[wp.Posts](recentPosts, c.RecentPostCacheTime) - recentCommentsCaches = cache.NewSliceCache[wp.Comments](recentComments, config.Conf.RecentCommentsCacheTime) + recentCommentsCaches = cache.NewSliceCache[wp.Comments](recentComments, c.RecentCommentsCacheTime) - postCommentCaches = cache.NewMapCacheByFn[uint64, []uint64](postComments, config.Conf.PostCommentsCacheTime) + postCommentCaches = cache.NewMapCacheByFn[uint64, []uint64](postComments, c.PostCommentsCacheTime) - maxPostIdCache = cache.NewSliceCache[uint64](getMaxPostId, config.Conf.MaxPostIdCacheTime) + maxPostIdCache = cache.NewSliceCache[uint64](getMaxPostId, c.MaxPostIdCacheTime) - usersCache = cache.NewMapCacheByBatchFn[uint64, wp.Users](getUsers, config.Conf.UserInfoCacheTime) + usersCache = cache.NewMapCacheByBatchFn[uint64, wp.Users](getUsers, c.UserInfoCacheTime) - commentsCache = cache.NewMapCacheByBatchFn[uint64, wp.Comments](getCommentByIds, config.Conf.CommentsCacheTime) + commentsCache = cache.NewMapCacheByBatchFn[uint64, wp.Comments](getCommentByIds, c.CommentsCacheTime) } func ClearCache() { @@ -68,6 +69,16 @@ func ClearCache() { usersCache.ClearExpired() commentsCache.ClearExpired() } +func FlushCache() { + searchPostIdsCache.Flush() + postsCache.Flush() + postsCache.Flush() + postListIdsCache.Flush() + monthPostsCache.Flush() + postContextCache.Flush() + usersCache.Flush() + commentsCache.Flush() +} type PostIds struct { Ids []uint64 diff --git a/actions/feed.go b/actions/feed.go index 1583f5e..e8c9752 100644 --- a/actions/feed.go +++ b/actions/feed.go @@ -41,6 +41,10 @@ func ClearCache() { postFeedCache.ClearExpired() commentCache.ClearExpired() } +func FlushCache() { + postFeedCache.Flush() + commentCache.Flush() +} func isCacheExpired(c *gin.Context, lastTime time.Time) bool { eTag := helper.StringMd5(lastTime.Format(tmp)) diff --git a/config/config.go b/config/config.go index db6bf49..e80df84 100644 --- a/config/config.go +++ b/config/config.go @@ -2,12 +2,13 @@ package config import ( "fmt" + "github/fthvgb1/wp-go/safety" "gopkg.in/yaml.v2" "os" "time" ) -var Conf Config +var Conf safety.Var[Config] type Config struct { Mysql Mysql `yaml:"mysql"` @@ -61,10 +62,12 @@ func InitConfig(conf string) error { if err != nil { return err } - err = yaml.Unmarshal(file, &Conf) + var c Config + err = yaml.Unmarshal(file, &c) if err != nil { return err } + Conf.Store(c) return nil } @@ -77,7 +80,7 @@ type Dsn struct { Charset string `yaml:"charset"` } -func (m *Dsn) GetDsn() string { +func (m Dsn) GetDsn() string { if m.Charset == "" { m.Charset = "utf8" } diff --git a/db/db.go b/db/db.go index 2ec2f6c..43c3451 100644 --- a/db/db.go +++ b/db/db.go @@ -35,23 +35,24 @@ func (r SqlxDb) Get(ctx context.Context, dest any, sql string, params ...any) er } func InitDb() error { - dsn := config.Conf.Mysql.Dsn.GetDsn() + c := config.Conf.Load() + dsn := c.Mysql.Dsn.GetDsn() var err error Db, err = sqlx.Open("mysql", dsn) if err != nil { return err } - if config.Conf.Mysql.Pool.ConnMaxIdleTime != 0 { - Db.SetConnMaxIdleTime(config.Conf.Mysql.Pool.ConnMaxLifetime) + if c.Mysql.Pool.ConnMaxIdleTime != 0 { + Db.SetConnMaxIdleTime(c.Mysql.Pool.ConnMaxLifetime) } - if config.Conf.Mysql.Pool.MaxIdleConn != 0 { - Db.SetMaxIdleConns(config.Conf.Mysql.Pool.MaxIdleConn) + if c.Mysql.Pool.MaxIdleConn != 0 { + Db.SetMaxIdleConns(c.Mysql.Pool.MaxIdleConn) } - if config.Conf.Mysql.Pool.MaxOpenConn != 0 { - Db.SetMaxOpenConns(config.Conf.Mysql.Pool.MaxOpenConn) + if c.Mysql.Pool.MaxOpenConn != 0 { + Db.SetMaxOpenConns(c.Mysql.Pool.MaxOpenConn) } - if config.Conf.Mysql.Pool.ConnMaxLifetime != 0 { - Db.SetConnMaxLifetime(config.Conf.Mysql.Pool.ConnMaxLifetime) + if c.Mysql.Pool.ConnMaxLifetime != 0 { + Db.SetConnMaxLifetime(c.Mysql.Pool.ConnMaxLifetime) } return err } diff --git a/mail/mail.go b/mail/mail.go index f86a3ea..25ac561 100644 --- a/mail/mail.go +++ b/mail/mail.go @@ -23,9 +23,10 @@ func SendMail(mailTo []string, subject string, body string, a ...AttacheFile) er m := gomail.NewMessage( gomail.SetEncoding(gomail.Base64), ) + c := config.Conf.Load() m.SetHeader("From", - m.FormatAddress(config.Conf.Mail.User, - config.Conf.Mail.Alias, + m.FormatAddress(c.Mail.User, + c.Mail.Alias, )) m.SetHeader("To", mailTo...) m.SetHeader("Subject", subject) @@ -43,12 +44,12 @@ func SendMail(mailTo []string, subject string, body string, a ...AttacheFile) er } d := gomail.NewDialer( - config.Conf.Mail.Host, - config.Conf.Mail.Port, - config.Conf.Mail.User, - config.Conf.Mail.Pass, + c.Mail.Host, + c.Mail.Port, + c.Mail.User, + c.Mail.Pass, ) - if config.Conf.Mail.Ssl { + if c.Mail.Ssl { d.TLSConfig = &tls.Config{InsecureSkipVerify: true} } err := d.DialAndSend(m) diff --git a/main.go b/main.go index 4971c30..4568ab4 100644 --- a/main.go +++ b/main.go @@ -2,14 +2,20 @@ package main import ( "flag" + "fmt" "github/fthvgb1/wp-go/actions" "github/fthvgb1/wp-go/actions/common" "github/fthvgb1/wp-go/config" "github/fthvgb1/wp-go/db" + "github/fthvgb1/wp-go/mail" "github/fthvgb1/wp-go/models" "github/fthvgb1/wp-go/plugins" "github/fthvgb1/wp-go/route" + "log" "math/rand" + "os" + "os/signal" + "syscall" "time" ) @@ -43,7 +49,7 @@ func init() { } func cronClearCache() { - t := time.NewTicker(config.Conf.CrontabClearCacheTime) + t := time.NewTicker(config.Conf.Load().CrontabClearCacheTime) for { select { case <-t.C: @@ -54,11 +60,38 @@ func cronClearCache() { } } -func main() { - if config.Conf.Port == "" { - config.Conf.Port = "80" +func signalNotify() { + c := make(chan os.Signal) + signal.Notify(c, syscall.SIGUSR1, syscall.SIGUSR2) + conf := config.Conf.Load() + for { + switch <-c { + case syscall.SIGUSR1: + //todo 更新配置 + case syscall.SIGUSR2: + go func() { + defer func() { + if r := recover(); r != nil { + mail.SendMail([]string{conf.Mail.User}, "清空缓存失败", fmt.Sprintf("err:[%s]", r)) + } + }() + common.FlushCache() + plugins.FlushCache() + actions.FlushCache() + log.Println("清除缓存成功") + }() + } } - err := route.SetupRouter().Run(config.Conf.Port) +} + +func main() { + c := config.Conf.Load() + if c.Port == "" { + c.Port = "80" + config.Conf.Store(c) + } + go signalNotify() + err := route.SetupRouter().Run(c.Port) if err != nil { panic(err) } diff --git a/middleware/sendmail.go b/middleware/sendmail.go index 2549bc5..6d4fabe 100644 --- a/middleware/sendmail.go +++ b/middleware/sendmail.go @@ -41,7 +41,7 @@ func RecoverAndSendMail(w io.Writer) func(ctx *gin.Context) { ) er := mail.SendMail( - []string{config.Conf.Mail.User}, + []string{config.Conf.Load().Mail.User}, fmt.Sprintf("%s%s %s 发生错误", fmt.Sprintf(config.Options.Value("siteurl")), c.FullPath(), time.Now().Format(time.RFC1123Z)), content) if er != nil { diff --git a/middleware/validateservername.go b/middleware/validateservername.go index ad986d2..d28be43 100644 --- a/middleware/validateservername.go +++ b/middleware/validateservername.go @@ -9,7 +9,7 @@ import ( ) func ValidateServerNames() func(ctx *gin.Context) { - serverName := helper.SimpleSliceToMap(config.Conf.TrustServerNames, func(v string) string { + serverName := helper.SimpleSliceToMap(config.Conf.Load().TrustServerNames, func(v string) string { return v }) return func(c *gin.Context) { diff --git a/plugins/digest.go b/plugins/digest.go index 77f99f9..83ef8da 100644 --- a/plugins/digest.go +++ b/plugins/digest.go @@ -19,17 +19,20 @@ var digestCache *cache.MapCache[uint64, string] var quto = regexp.MustCompile(`" *|& *|< *|> ?|  *`) func InitDigestCache() { - digestCache = cache.NewMapCacheByFn[uint64](digestRaw, config.Conf.DigestCacheTime) + digestCache = cache.NewMapCacheByFn[uint64](digestRaw, config.Conf.Load().DigestCacheTime) } func ClearDigestCache() { digestCache.ClearExpired() } +func FlushCache() { + digestCache.Flush() +} func digestRaw(arg ...any) (string, error) { str := arg[0].(string) id := arg[1].(uint64) - limit := config.Conf.DigestWordCount + limit := config.Conf.Load().DigestWordCount if limit < 0 { return str, nil } else if limit == 0 { diff --git a/route/route.go b/route/route.go index cb67360..a3a78ed 100644 --- a/route/route.go +++ b/route/route.go @@ -20,8 +20,9 @@ func SetupRouter() *gin.Engine { // Disable Console Color // gin.DisableConsoleColor() r := gin.New() - if len(config.Conf.TrustIps) > 0 { - err := r.SetTrustedProxies(config.Conf.TrustIps) + c := config.Conf.Load() + if len(c.TrustIps) > 0 { + err := r.SetTrustedProxies(c.TrustIps) if err != nil { panic(err) } @@ -42,11 +43,11 @@ func SetupRouter() *gin.Engine { gin.Logger(), middleware.ValidateServerNames(), middleware.RecoverAndSendMail(gin.DefaultErrorWriter), - middleware.FlowLimit(config.Conf.MaxRequestSleepNum, config.Conf.MaxRequestNum, config.Conf.SleepTime), + middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.SleepTime), middleware.SetStaticFileCache, ) //gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用 - if config.Conf.Gzip { + if c.Gzip { r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{ "/wp-includes/", "/wp-content/", }))) @@ -60,7 +61,7 @@ func SetupRouter() *gin.Engine { })) store := cookie.NewStore([]byte("secret")) r.Use(sessions.Sessions("go-wp", store)) - r.GET("/", middleware.SearchLimit(config.Conf.SingleIpSearchNum), actions.Index) + r.GET("/", middleware.SearchLimit(c.SingleIpSearchNum), actions.Index) r.GET("/page/:page", actions.Index) r.GET("/p/category/:category", actions.Index) r.GET("/p/category/:category/page/:page", actions.Index) @@ -73,7 +74,7 @@ func SetupRouter() *gin.Engine { r.GET("/p/:id/feed", actions.PostFeed) r.GET("/feed", actions.Feed) r.GET("/comments/feed", actions.CommentsFeed) - r.POST("/comment", middleware.FlowLimit(config.Conf.MaxRequestSleepNum, 5, config.Conf.SleepTime), actions.PostComment) + r.POST("/comment", middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.SleepTime), actions.PostComment) if gin.Mode() != gin.ReleaseMode { pprof.Register(r, "dev/pprof") }