diff --git a/config/app.yml.example b/config/app.yml.example index e9d8f0f..62aa566 100644 --- a/config/app.yml.example +++ b/config/app.yml.example @@ -1,4 +1,4 @@ -version: 1.0.2 +version: 1.0.3 app: name: "maintainman" listen: ":8080" @@ -26,7 +26,7 @@ database: driver: "mysql" mysql: host: "localhost" - port: "3306" + port: 3306 name: "maintainman" params: "parseTime=true&loc=Local&charset=utf8mb4" user: "root" @@ -35,6 +35,11 @@ database: path: "maintainman.db" cache: + driver: "go-cache" + redis: + host: "localhost" + port: 6379 + password: "" expire: "24h" purge: "10m" diff --git a/config/index.go b/config/index.go index 560a044..a22dade 100644 --- a/config/index.go +++ b/config/index.go @@ -4,7 +4,7 @@ import ( "github.com/spf13/viper" ) -const AppConfigVersion = "1.0.2" +const AppConfigVersion = "1.0.3" var ( AppConfig *viper.Viper @@ -37,12 +37,16 @@ func init() { AppConfig.SetDefault("database.driver", "sqlite") AppConfig.SetDefault("database.sqlite.path", "maintainman.db") AppConfig.SetDefault("database.mysql.host", "localhost") - AppConfig.SetDefault("database.mysql.port", "3306") + AppConfig.SetDefault("database.mysql.port", 3306) AppConfig.SetDefault("database.mysql.name", "maintainman") AppConfig.SetDefault("database.mysql.params", "parseTime=true&loc=Local&charset=utf8mb4") AppConfig.SetDefault("database.mysql.user", "root") AppConfig.SetDefault("database.mysql.password", "123456") + AppConfig.SetDefault("cache.driver", "go-cache") + AppConfig.SetDefault("cache.redis.host", "localhost") + AppConfig.SetDefault("cache.redis.port", 6379) + AppConfig.SetDefault("cache.redis.password", "") AppConfig.SetDefault("cache.expire", "24h") AppConfig.SetDefault("cache.purge", "10m") diff --git a/config/updater.go b/config/updater.go index bcf7e15..395e027 100644 --- a/config/updater.go +++ b/config/updater.go @@ -15,12 +15,12 @@ func ReadAndUpdateConfig(config *viper.Viper, name string, version string) { fmt.Printf("%s configuration file not found: %v\n", name, err) config.SetDefault("version", version) if err := config.SafeWriteConfig(); err != nil { - panic(fmt.Errorf("Failed to write %s configuration file: %v", name, err)) + panic(fmt.Errorf("failed to write %s configuration file: %v", name, err)) } fmt.Printf("default %s configuration file created.\n", name) created = true } else { - panic(fmt.Errorf("Fatal error reading %s configuration: %v", name, err)) + panic(fmt.Errorf("fatal error reading %s configuration: %v", name, err)) } } if created { @@ -37,7 +37,7 @@ func ReadAndUpdateConfig(config *viper.Viper, name string, version string) { fmt.Printf("updating your %s configuration file. conflict entries will not be updated.\n", name) config.Set("version", version) if err := config.WriteConfig(); err != nil { - panic(fmt.Errorf("Failed to write %s configuration file: %v", name, err)) + panic(fmt.Errorf("failed to write %s configuration file: %v", name, err)) } fmt.Printf("%s configuration file updated to version %s.\n", name, version) } diff --git a/database/cache.go b/database/cache.go index 03ec23d..4021eb3 100644 --- a/database/cache.go +++ b/database/cache.go @@ -1,22 +1,46 @@ package database import ( + "context" "fmt" "maintainman/config" + "maintainman/logger" "time" + "github.com/go-redis/redis/v8" "github.com/patrickmn/go-cache" ) +type CacheClient interface { + Get(key string) (any, bool) + Set(key string, value any, expire time.Duration) +} + +type GoCacheClient struct { + cache *cache.Cache +} + +type RedisClient struct { + rdb *redis.Client +} + var ( - Cache *cache.Cache + Cache CacheClient ) func init() { - Cache = initCache() + cacheType := config.AppConfig.GetString("cache.driver") + switch cacheType { + case "go-cache": + Cache = initGoCache() + case "redis": + Cache = initRedis() + default: + panic(fmt.Errorf("support go-cache and redis only")) + } } -func initCache() *cache.Cache { +func initGoCache() CacheClient { cacheExpire, err := time.ParseDuration(config.AppConfig.GetString("cache.expire")) if err != nil { panic(fmt.Errorf("Can not parse cache.expire in app config: %v", err)) @@ -26,6 +50,46 @@ func initCache() *cache.Cache { panic(fmt.Errorf("Can not parse cache.purge in app config: %v", err)) } - cache := cache.New(cacheExpire, cachePurge) + cache := &GoCacheClient{ + cache: cache.New(cacheExpire, cachePurge), + } + return cache +} + +func initRedis() CacheClient { + rdbHost := config.AppConfig.GetString("cache.redis.host") + rdbPort := config.AppConfig.GetInt("cache.redis.port") + rdbPasswd := config.AppConfig.GetString("cache.redis.password") + rdbAddr := fmt.Sprintf("%s:%d", rdbHost, rdbPort) + + cache := &RedisClient{ + rdb: redis.NewClient(&redis.Options{ + Addr: rdbAddr, + Password: rdbPasswd, + DB: 0, + }), + } return cache } + +func (client *GoCacheClient) Get(key string) (any, bool) { + return client.cache.Get(key) +} + +func (client *GoCacheClient) Set(key string, value any, expire time.Duration) { + client.cache.Set(key, value, expire) +} + +func (client *RedisClient) Get(key string) (any, bool) { + ctx := context.Background() + value, err := client.rdb.Get(ctx, key).Result() + if err != nil && err != redis.Nil { + logger.Logger.Debugf("%+v", err) + } + return value, err == nil +} + +func (client *RedisClient) Set(key string, value any, expire time.Duration) { + ctx := context.Background() + client.rdb.Set(ctx, key, value, expire) +} diff --git a/database/index.go b/database/index.go index 9dc2b61..13f020a 100644 --- a/database/index.go +++ b/database/index.go @@ -38,12 +38,12 @@ func initSqlite() *gorm.DB { func initMysql() *gorm.DB { dbHost := config.AppConfig.GetString("database.mysql.host") - dbPort := config.AppConfig.GetString("database.mysql.port") + dbPort := config.AppConfig.GetInt("database.mysql.port") dbName := config.AppConfig.GetString("database.mysql.name") dbParams := config.AppConfig.GetString("database.mysql.params") dbUser := config.AppConfig.GetString("database.mysql.user") dbPasswd := config.AppConfig.GetString("database.mysql.password") - dbURL := fmt.Sprintf("%s:%s@(%s:%s)/%s?%s", dbUser, dbPasswd, dbHost, dbPort, dbName, dbParams) + dbURL := fmt.Sprintf("%s:%s@(%s:%d)/%s?%s", dbUser, dbPasswd, dbHost, dbPort, dbName, dbParams) db, err := gorm.Open(mysql.Open(dbURL)) if err != nil { diff --git a/go.mod b/go.mod index dea1454..5fae4a6 100644 --- a/go.mod +++ b/go.mod @@ -18,12 +18,15 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/aymerick/douceur v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/flosch/pongo2/v4 v4.0.2 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-playground/locales v0.14.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/goccy/go-json v0.9.4 // indirect github.com/golang-jwt/jwt/v4 v4.3.0 // indirect diff --git a/go.sum b/go.sum index 953a287..bf26813 100644 --- a/go.sum +++ b/go.sum @@ -15,11 +15,16 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +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/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= @@ -38,6 +43,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= +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.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI=