From 72d205f3e9871f5871f9304a86233bdc499b33b4 Mon Sep 17 00:00:00 2001 From: qwqcode Date: Sat, 23 Apr 2022 16:28:48 +0800 Subject: [PATCH] feat(cache): Support redis & memcache Signed-off-by: qwqcode --- artalk-go.example.yml | 29 ++++++++----- cmd/core.go | 15 ++++++- config/config.go | 94 +++++++++++++++++++++---------------------- config/init.go | 51 +++++++++++++++++++++++ go.mod | 5 +-- go.sum | 15 +++++-- lib/cache.go | 56 +++++++++++++++++++++++--- model/cache.go | 19 ++++++++- 8 files changed, 210 insertions(+), 74 deletions(-) create mode 100644 config/init.go diff --git a/artalk-go.example.yml b/artalk-go.example.yml index 98a6133..8003b0c 100644 --- a/artalk-go.example.yml +++ b/artalk-go.example.yml @@ -24,6 +24,13 @@ log: enabled: true # 总开关 filename: "./data/artalk-go.log" # 日志文件路径 +# 缓存 +cache: + type: "builtin" # 支持 redis, memcache, builtin (自带缓存) + expires: 30 # 缓存过期时间 (单位:分钟) + warm_up: false # 程序启动时预热缓存 + server: "" # 连接缓存服务器 (例如:"localhost:6379") + # 可信域名 trusted_domains: # - "*" # 无限制 @@ -52,7 +59,7 @@ login_timeout: 259200 # 评论审核 moderator: pending_default: false # 发表新评论默认为 “待审状态” - api_fail_block: false # 垃圾检测 API 请求错误仍然拦截 + api_fail_block: false # 垃圾检测 API 请求错误仍然拦截 # akismet.com 反垃圾 akismet_key: "" # 腾讯云文本内容安全 (tms) @@ -71,16 +78,16 @@ moderator: keywords: enabled: false pending: false # 匹配成功设为待审状态 - files: # 支持多个词库文件 + files: # 支持多个词库文件 - "./data/词库_1.txt" file_sep: "\n" # 词库文件内容分割符 replac_to: "x" # 替换字符 # 验证码 captcha: - enabled: true # 总开关 - always: false # 总是需要验证码 - action_limit: 3 # 激活验证码所需操作次数 + enabled: true # 总开关 + always: false # 总是需要验证码 + action_limit: 3 # 激活验证码所需操作次数 action_reset: 60 # 重置操作计数器超时 (单位:s, 设为 -1 不重置) # Geetest 极验 geetest: # https://www.geetest.com @@ -90,7 +97,7 @@ captcha: # 邮件通知 email: - enabled: false # 总开关 + enabled: false # 总开关 send_type: "smtp" # 发送方式 [smtp, ali_dm, sendmail] send_name: '{{reply_nick}}' # 发信人昵称 send_addr: "example@qq.com" # 发信人地址 @@ -103,19 +110,19 @@ email: username: "example@qq.com" password: "" ali_dm: # https://help.aliyun.com/document_detail/29444.html - access_key_id: "" # 阿里云颁发给用户的访问服务所用的密钥 ID + access_key_id: "" # 阿里云颁发给用户的访问服务所用的密钥 ID access_key_secret: "" # 用于加密的密钥 account_name: "example@example.com" # 管理控制台中配置的发信地址 # 图片上传 img_upload: - enabled: true # 总开关 + enabled: true # 总开关 path: "./data/artalk-img/" # 图片存放路径 - max_size: 5 # 图片大小限制 (单位:MB) - public_path: null # 指定图片链接基础路径 (默认为 "/static/images/") + max_size: 5 # 图片大小限制 (单位:MB) + public_path: null # 指定图片链接基础路径 (默认为 "/static/images/") # 使用 upgit 将图片上传到 GitHub 或图床 (https://github.com/pluveto/upgit) upgit: - enabled: false # 启用 upgit + enabled: false # 启用 upgit exec: "./upgit -c -t /artalk-img" del_local: true # 上传后删除本地的图片 diff --git a/cmd/core.go b/cmd/core.go index fcfb5cb..2687231 100644 --- a/cmd/core.go +++ b/cmd/core.go @@ -25,7 +25,10 @@ func loadCore() { syncConfWithDB() notify_launcher.Init() // 初始化 Notify 发射台 - makeCache() + // 缓存预热 + if config.Instance.Cache.Enabled && config.Instance.Cache.WarmUp { + makeCache() + } // TODO 异步加载开关 // go func() { // makeCache() @@ -48,6 +51,16 @@ func initConfig() { denverLoc, _ := time.LoadLocation(config.Instance.TimeZone) time.Local = denverLoc + // 缓存配置 + if config.Instance.Cache.Type == "" { + // 默认使用内建缓存 + config.Instance.Cache.Type = config.CacheTypeBuiltin + } + if config.Instance.Cache.Type != config.CacheTypeDisabled { + // 非缓存禁用模式,Enabled = true + config.Instance.Cache.Enabled = true + } + // 配置文件 alias 处理 if config.Instance.Captcha.ActionLimit == 0 { config.Instance.Captcha.Always = true diff --git a/config/config.go b/config/config.go index 6b15cd6..f1253a7 100644 --- a/config/config.go +++ b/config/config.go @@ -1,15 +1,6 @@ package config -import ( - "os" - "strings" - - "github.com/sirupsen/logrus" - "github.com/spf13/viper" -) - -// Instance 配置实例 -var Instance *Config +import "time" // Config 配置 // @link https://godoc.org/github.com/mitchellh/mapstructure @@ -20,6 +11,7 @@ type Config struct { Host string `mapstructure:"host" json:"host"` // HTTP Server 监听 IP Port int `mapstructure:"port" json:"port"` // HTTP Server 监听 Port DB DBConf `mapstructure:"db" json:"db"` // 数据文件 + Cache CacheConf `mapstructure:"cache" json:"cache"` // 缓存 Log LogConf `mapstructure:"log" json:"log"` // 日志文件 AllowOrigins []string `mapstructure:"allow_origins" json:"allow_origins"` // @deprecated 已废弃 (请使用 TrustedDomains) TrustedDomains []string `mapstructure:"trusted_domains" json:"trusted_domains"` // 可信任的域名 (新) @@ -39,6 +31,27 @@ type DBConf struct { Dsn string `mapstructure:"dsn" json:"dsn"` } +type CacheConf struct { + Enabled bool // 配置文件不允许修改 + Type CacheType `mapstructure:"type" json:"type"` + Expires int `mapstructure:"expires" json:"expires"` // 过期时间 + WarmUp bool `mapstructure:"warm_up" json:"warm_up"` // 启动时缓存预热 + Server string `mapstructure:"server" json:"server"` // 缓存服务器 + Redis RedisConf `mapstructure:"redis" json:"redis"` +} + +func (c *CacheConf) GetExpiresTime() int64 { + if c.Expires == 0 { + return int64(30 * time.Minute) // 默认 30min + } + + if c.Expires == -1 { + return -1 // Redis.KeepTTL = -1 + } + + return int64(time.Duration(c.Expires) * time.Minute) +} + type LogConf struct { Enabled bool `mapstructure:"enabled" json:"enabled"` Filename string `mapstructure:"filename" json:"filename"` @@ -143,6 +156,15 @@ const ( TypeSqlServer DBType = "sqlserver" ) +type CacheType string + +const ( + CacheTypeBuiltin CacheType = "builtin" // 内建缓存 + CacheTypeRedis CacheType = "redis" + CacheTypeMemcache CacheType = "memcache" + CacheTypeDisabled CacheType = "disabled" // 关闭缓存 +) + type EmailSenderType string const ( @@ -151,6 +173,19 @@ const ( TypeSendmail EmailSenderType = "sendmail" ) +// # Redis 配置 +// redis: +// network: "tcp" +// username: "" +// password: "" +// db: 0 +type RedisConf struct { + Network string `mapstructure:"network" json:"network"` // tcp or unix + Username string `mapstructure:"username" json:"username"` + Password string `mapstructure:"password" json:"password"` + DB int `mapstructure:"db" json:"db"` // Redis 默认数据库 0 +} + type ImgUploadConf struct { Enabled bool `mapstructure:"enabled" json:"enabled"` // 总开关 Path string `mapstructure:"path" json:"path"` // 图片存放路径 @@ -210,42 +245,3 @@ type NotifyLINEConf struct { ChannelAccessToken string `mapstructure:"channel_access_token" json:"channel_access_token"` Receivers []string `mapstructure:"receivers" json:"receivers"` } - -// Init 初始化配置 -func Init(cfgFile string, workDir string) { - viper.SetConfigType("yaml") - - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find config file in path. - viper.AddConfigPath(".") - viper.SetConfigName("artalk-go.yml") - } - - viper.SetEnvPrefix("ATG") - viper.AutomaticEnv() - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - - // 切换工作目录 - if workDir != "" { - viper.AddConfigPath(workDir) // must before - if err := os.Chdir(workDir); err != nil { - logrus.Fatal("工作目录切换错误 ", err) - } - } - - if err := viper.ReadInConfig(); err == nil { - // fmt.Print("\n") - // fmt.Println("- Using ArtalkGo config file:", viper.ConfigFileUsed()) - } else { - logrus.Fatal("找不到配置文件,使用 `-h` 参数查看帮助") - } - - Instance = &Config{} - err := viper.Unmarshal(&Instance) - if err != nil { - logrus.Errorf("unable to decode into struct, %v", err) - } -} diff --git a/config/init.go b/config/init.go new file mode 100644 index 0000000..8cfdd16 --- /dev/null +++ b/config/init.go @@ -0,0 +1,51 @@ +package config + +import ( + "os" + "strings" + + "github.com/sirupsen/logrus" + "github.com/spf13/viper" +) + +// Instance 配置实例 +var Instance *Config + +// Init 初始化配置 +func Init(cfgFile string, workDir string) { + viper.SetConfigType("yaml") + + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find config file in path. + viper.AddConfigPath(".") + viper.SetConfigName("artalk-go.yml") + } + + viper.SetEnvPrefix("ATG") + viper.AutomaticEnv() + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + // 切换工作目录 + if workDir != "" { + viper.AddConfigPath(workDir) // must before + if err := os.Chdir(workDir); err != nil { + logrus.Fatal("工作目录切换错误 ", err) + } + } + + if err := viper.ReadInConfig(); err == nil { + // fmt.Print("\n") + // fmt.Println("- Using ArtalkGo config file:", viper.ConfigFileUsed()) + } else { + logrus.Fatal("找不到配置文件,使用 `-h` 参数查看帮助") + } + + Instance = &Config{} + err := viper.Unmarshal(&Instance) + if err != nil { + logrus.Errorf("unable to decode into struct, %v", err) + } +} diff --git a/go.mod b/go.mod index 34c4602..62e8df3 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,17 @@ module github.com/ArtalkJS/ArtalkGo go 1.16 require ( - github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect github.com/PuerkitoBio/goquery v1.7.1 github.com/aliyun/alibaba-cloud-sdk-go v1.61.1560 github.com/allegro/bigcache/v3 v3.0.0 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/blang/semver v3.5.1+incompatible + github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d github.com/cheggaaa/pb/v3 v3.0.8 github.com/eko/gocache/v2 v2.1.0 - github.com/elliotchance/phpserialize v1.3.1 github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/jedib0t/go-pretty/v6 v6.2.4 github.com/jeremywohl/flatten v1.0.1 @@ -26,7 +26,6 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/nikoksr/notify v0.23.0 github.com/onrik/logrus v0.9.0 - github.com/onsi/gomega v1.16.0 // indirect github.com/qwqcode/go-aliyun-email v0.0.0-20180120030821-cb6e7b1382bf github.com/rhysd/go-github-selfupdate v1.2.3 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 diff --git a/go.sum b/go.sum index 1951de3..8bfd03d 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,6 @@ github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/g github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= @@ -136,6 +134,8 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -189,8 +189,6 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB github.com/eko/gocache/v2 v2.1.0 h1:ljFKAAa5hHsrsSaBvyx0g9a/A9lZSUrf4jBjErQd7gc= github.com/eko/gocache/v2 v2.1.0/go.mod h1:u+EpYjCVsOpeqvDLzinOVLjLxwHJjO+NT4LS2+8XnCU= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/elliotchance/phpserialize v1.3.1 h1:bA32YZF9/WmxJgIFmrweMK03Y74vPAMmRyKTLFs67/Q= -github.com/elliotchance/phpserialize v1.3.1/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -235,6 +233,8 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nA github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-redis/redis/v8 v8.9.0 h1:FTTbB7WqlXfVNdVv0SsxA+oVi0bAwit6bMe3IUucq2o= github.com/go-redis/redis/v8 v8.9.0/go.mod h1:ik7vb7+gm8Izylxu6kf6wG26/t2VljgCfSQ1DM4O1uU= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -335,6 +335,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v0.0.0-20171113160352-8c31c18f31ed/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -598,6 +599,9 @@ github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -608,6 +612,9 @@ github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= diff --git a/lib/cache.go b/lib/cache.go index d4759a7..09b71f4 100644 --- a/lib/cache.go +++ b/lib/cache.go @@ -2,11 +2,16 @@ package lib import ( "context" + "strings" "time" + "github.com/ArtalkJS/ArtalkGo/config" "github.com/allegro/bigcache/v3" + "github.com/bradfitz/gomemcache/memcache" "github.com/eko/gocache/v2/cache" "github.com/eko/gocache/v2/store" + "github.com/go-redis/redis/v8" + "github.com/sirupsen/logrus" ) var CACHE *cache.Cache @@ -14,12 +19,53 @@ var CACHE *cache.Cache var Ctx = context.Background() func OpenCache() (err error) { - bigcacheClient, err := bigcache.NewBigCache(bigcache.DefaultConfig(30 * time.Minute)) // TODO 过期时间是一样的,只有 Redis 才能设置单个 key 的 - if err != nil { - return err + cacheType := config.Instance.Cache.Type + + var cacheStore store.StoreInterface + + switch cacheType { + + case config.CacheTypeBuiltin: + // 内建缓存 + bigcacheClient, err := bigcache.NewBigCache(bigcache.DefaultConfig( + // Tip: 内建缓存过期时间是一样的,只有 Redis/Memcache 才能设置单个 item 的 + time.Duration(config.Instance.Cache.GetExpiresTime()), + )) + if err != nil { + return err + } + cacheStore = store.NewBigcache(bigcacheClient, nil) // No options provided (as second argument) + + case config.CacheTypeRedis: + // Redis + network := "tcp" + if config.Instance.Cache.Redis.Network != "" { + network = config.Instance.Cache.Redis.Network + } + + cacheStore = store.NewRedis(redis.NewClient(&redis.Options{ + Network: network, + Addr: config.Instance.Cache.Server, + Username: config.Instance.Cache.Redis.Username, + Password: config.Instance.Cache.Redis.Password, + DB: config.Instance.Cache.Redis.DB, + }), nil) + + case config.CacheTypeMemcache: + // Memcache + servers := strings.Split(config.Instance.Cache.Server, ",") + cacheStore = store.NewMemcache( + memcache.New(servers...), + &store.Options{ + Expiration: time.Duration(config.Instance.Cache.GetExpiresTime()), + }, + ) + + default: + logrus.Fatal("请检查配置文件 `cache.type` 无效缓存类型:", cacheType) + } - bigcacheStore := store.NewBigcache(bigcacheClient, nil) // No options provided (as second argument) - CACHE = cache.New(bigcacheStore) + CACHE = cache.New(cacheStore) return } diff --git a/model/cache.go b/model/cache.go index a2c11d8..fe824b0 100644 --- a/model/cache.go +++ b/model/cache.go @@ -2,10 +2,13 @@ package model import ( "encoding/json" + "errors" "fmt" "strings" "sync" + "time" + "github.com/ArtalkJS/ArtalkGo/config" "github.com/ArtalkJS/ArtalkGo/lib" "github.com/eko/gocache/v2/store" "github.com/sirupsen/logrus" @@ -24,6 +27,10 @@ func (c *cacher) StoreCache(getSrcStruct func() interface{}) error { func FindCache(name string, destStruct interface{}) (cacher, error) { cacher := cacher{cacheKey: name} + if !config.Instance.Cache.Enabled { + return cacher, errors.New("缓存功能禁用") + } + entry, err := lib.CACHE.Get(lib.Ctx, name) if err != nil { return cacher, err @@ -50,12 +57,18 @@ func StoreCache(name string, srcStruct interface{}, getSrcStruct ...func() inter srcStruct = getSrcStruct[0]() // 这个 func 内再执行 db 查询,加锁防止反复查询 } + if !config.Instance.Cache.Enabled { + return nil + } + str, err := json.Marshal(srcStruct) if err != nil { return err } - err = lib.CACHE.Set(lib.Ctx, name, []byte(str), &store.Options{}) + err = lib.CACHE.Set(lib.Ctx, name, []byte(str), &store.Options{ + Expiration: time.Duration(config.Instance.Cache.GetExpiresTime()), + }) if err != nil { return err } @@ -66,6 +79,10 @@ func StoreCache(name string, srcStruct interface{}, getSrcStruct ...func() inter } func ClearCache(name string) error { + if !config.Instance.Cache.Enabled { + return nil + } + MutexCache.Lock() defer MutexCache.Unlock()