diff --git a/internal/conf/conf.go b/internal/conf/conf.go index ebc471fd..1bad1921 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -4,6 +4,8 @@ import ( "log" "sync" "time" + + "github.com/rocboss/paopao-ce/pkg/cfg" ) var ( @@ -12,7 +14,6 @@ var ( loggerZincSetting *LoggerZincSettingS loggerMeiliSetting *LoggerMeiliSettingS redisSetting *RedisSettingS - features *FeaturesSettingS DatabaseSetting *DatabaseSetingS MysqlSetting *MySQLSettingS @@ -45,9 +46,11 @@ func setupSetting(suite []string, noDefault bool) error { return err } - features = setting.FeaturesFrom("Features") + // initialize features configure + ss, kv := setting.featuresInfoFrom("Features") + cfg.Initialize(ss, kv) if len(suite) > 0 { - if err = features.Use(suite, noDefault); err != nil { + if err = cfg.Use(suite, noDefault); err != nil { return err } } @@ -106,59 +109,26 @@ func Initialize(suite []string, noDefault bool) { setupDBEngine() } -// Cfg get value by key if exist -func Cfg(key string) (string, bool) { - return features.Cfg(key) -} - -// CfgIf check expression is true. if expression just have a string like -// `Sms` is mean `Sms` whether defined in suite feature settings. expression like -// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value -// is `SmsJuhe` -func CfgIf(expression string) bool { - return features.CfgIf(expression) -} - -// CfgBe check expression is true then do the handle. if expression just have a string like -// `Sms` is mean `Sms` whether defined in suite feature settings. expression like -// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value -// is `SmsJuhe` -func CfgBe(expression string, handle func()) { - if features.CfgIf(expression) { - handle() - } -} - -// CfgNot check expression is not true then do the handle. if expression just have a string like -// `Sms` is mean `Sms` whether defined in suite feature settings. expression like -// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value -// is `SmsJuhe` -func CfgNot(expression string, handle func()) { - if !features.CfgIf(expression) { - handle() - } -} - func GetOssDomain() string { uri := "https://" - if CfgIf("AliOSS") { + if cfg.If("AliOSS") { return uri + AliOSSSetting.Domain + "/" - } else if CfgIf("COS") { + } else if cfg.If("COS") { return uri + COSSetting.Domain + "/" - } else if CfgIf("HuaweiOBS") { + } else if cfg.If("HuaweiOBS") { return uri + HuaweiOBSSetting.Domain + "/" - } else if CfgIf("MinIO") { + } else if cfg.If("MinIO") { if !MinIOSetting.Secure { uri = "http://" } return uri + MinIOSetting.Domain + "/" + MinIOSetting.Bucket + "/" - } else if CfgIf("S3") { + } else if cfg.If("S3") { if !S3Setting.Secure { uri = "http://" } // TODO: will not work well need test in real world return uri + S3Setting.Domain + "/" + S3Setting.Bucket + "/" - } else if CfgIf("LocalOSS") { + } else if cfg.If("LocalOSS") { if !LocalOSSSetting.Secure { uri = "http://" } diff --git a/internal/conf/db.go b/internal/conf/db.go index ddca7030..ef4f7c92 100644 --- a/internal/conf/db.go +++ b/internal/conf/db.go @@ -5,6 +5,7 @@ import ( "time" "github.com/go-redis/redis/v8" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/driver/postgres" @@ -59,15 +60,15 @@ func newDBEngine() (*gorm.DB, error) { db *gorm.DB err error ) - if CfgIf("MySQL") { + if cfg.If("MySQL") { logrus.Debugln("use MySQL as db") if db, err = gorm.Open(mysql.Open(MysqlSetting.Dsn()), config); err == nil { db.Use(plugin) } - } else if CfgIf("Postgres") { + } else if cfg.If("Postgres") { logrus.Debugln("use PostgreSQL as db") db, err = gorm.Open(postgres.Open(PostgresSetting.Dsn()), config) - } else if CfgIf("Sqlite3") { + } else if cfg.If("Sqlite3") { logrus.Debugf("use Sqlite3 as db path:%s sqlite3InCgoEnabled:%t", Sqlite3Setting.Path, sqlite3InCgoEnabled) db, err = gormOpenSqlite3(config) } else { diff --git a/internal/conf/logger.go b/internal/conf/logger.go index ef466079..c65612dc 100644 --- a/internal/conf/logger.go +++ b/internal/conf/logger.go @@ -3,6 +3,7 @@ package conf import ( "io" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" "gopkg.in/natefinch/lumberjack.v2" ) @@ -20,16 +21,20 @@ func setupLogger() { logrus.SetFormatter(&logrus.JSONFormatter{}) logrus.SetLevel(loggerSetting.logLevel()) - if CfgIf("LoggerFile") { - out := newFileLogger() - logrus.SetOutput(out) - } else if CfgIf("LoggerZinc") { - hook := newZincLogHook() - logrus.SetOutput(io.Discard) - logrus.AddHook(hook) - } else if CfgIf("LoggerMeili") { - hook := newMeiliLogHook() - logrus.SetOutput(io.Discard) - logrus.AddHook(hook) - } + cfg.In(cfg.Actions{ + "LoggerFile": func() { + out := newFileLogger() + logrus.SetOutput(out) + }, + "LoggerZinc": func() { + hook := newZincLogHook() + logrus.SetOutput(io.Discard) + logrus.AddHook(hook) + }, + "LoggerMeili": func() { + hook := newMeiliLogHook() + logrus.SetOutput(io.Discard) + logrus.AddHook(hook) + }, + }) } diff --git a/internal/conf/settting.go b/internal/conf/settting.go index 2e2ae9ec..116fdf95 100644 --- a/internal/conf/settting.go +++ b/internal/conf/settting.go @@ -90,12 +90,6 @@ type SmsJuheSettings struct { TplVal string } -type FeaturesSettingS struct { - kv map[string]string - suites map[string][]string - features map[string]string -} - type TweetSearchS struct { MaxUpdateQPS int MinWorker int @@ -237,7 +231,7 @@ func (s *Setting) Unmarshal(objects map[string]any) error { return nil } -func (s *Setting) FeaturesFrom(k string) *FeaturesSettingS { +func (s *Setting) featuresInfoFrom(k string) (map[string][]string, map[string]string) { sub := s.vp.Sub(k) keys := sub.AllKeys() @@ -252,73 +246,7 @@ func (s *Setting) FeaturesFrom(k string) *FeaturesSettingS { suites[key] = sub.GetStringSlice(key) } } - return newFeatures(suites, kv) -} - -func newFeatures(suites map[string][]string, kv map[string]string) *FeaturesSettingS { - features := &FeaturesSettingS{ - suites: suites, - kv: kv, - features: make(map[string]string), - } - features.UseDefault() - return features -} - -func (f *FeaturesSettingS) UseDefault() { - f.Use([]string{"default"}, true) -} - -func (f *FeaturesSettingS) Use(suite []string, noDefault bool) error { - if noDefault && len(f.features) != 0 { - f.features = make(map[string]string) - } - features := f.flatFeatures(suite) - for _, feature := range features { - if len(feature) == 0 { - continue - } - f.features[feature] = f.kv[feature] - } - return nil -} - -func (f *FeaturesSettingS) flatFeatures(suite []string) []string { - features := make([]string, 0, len(suite)+10) - for s := suite[:]; len(s) > 0; s = s[:len(s)-1] { - item := strings.TrimSpace(strings.ToLower(s[0])) - if len(item) > 0 { - if items, exist := f.suites[item]; exist { - s = append(s, items...) - } - features = append(features, item) - } - s[0] = s[len(s)-1] - } - return features -} - -// Cfg get value by key if exist -func (f *FeaturesSettingS) Cfg(key string) (string, bool) { - key = strings.ToLower(key) - value, exist := f.features[key] - return value, exist -} - -// CfgIf check expression is true. if expression just have a string like -// `Sms` is mean `Sms` whether define in suite feature settings. expression like -// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value -// is `SmsJuhe` -func (f *FeaturesSettingS) CfgIf(expression string) bool { - kv := strings.Split(expression, "=") - key := strings.Trim(strings.ToLower(kv[0]), " ") - v, ok := f.features[key] - if len(kv) == 2 && ok && strings.Trim(kv[1], " ") == v { - return true - } else if len(kv) == 1 && ok { - return true - } - return false + return suites, kv } func (s *MySQLSettingS) Dsn() string { diff --git a/internal/dao/dao.go b/internal/dao/dao.go index 9a1ad705..6f4a776a 100644 --- a/internal/dao/dao.go +++ b/internal/dao/dao.go @@ -3,13 +3,13 @@ package dao import ( "sync" - "github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/dao/jinzhu" "github.com/rocboss/paopao-ce/internal/dao/sakila" "github.com/rocboss/paopao-ce/internal/dao/search" "github.com/rocboss/paopao-ce/internal/dao/slonik" "github.com/rocboss/paopao-ce/internal/dao/storage" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" ) @@ -24,11 +24,11 @@ var ( func DataService() core.DataService { onceDs.Do(func() { var v core.VersionInfo - if conf.CfgIf("Gorm") { + if cfg.If("Gorm") { ds, v = jinzhu.NewDataService() - } else if conf.CfgIf("Sqlx") && conf.CfgIf("MySQL") { + } else if cfg.If("Sqlx") && cfg.If("MySQL") { ds, v = sakila.NewDataService() - } else if conf.CfgIf("Sqlx") && (conf.CfgIf("Postgres") || conf.CfgIf("PostgreSQL")) { + } else if cfg.If("Sqlx") && (cfg.If("Postgres") || cfg.If("PostgreSQL")) { ds, v = slonik.NewDataService() } else { // default use gorm as orm for sql database @@ -42,19 +42,19 @@ func DataService() core.DataService { func ObjectStorageService() core.ObjectStorageService { onceOss.Do(func() { var v core.VersionInfo - if conf.CfgIf("AliOSS") { + if cfg.If("AliOSS") { oss, v = storage.MustAliossService() - } else if conf.CfgIf("COS") { + } else if cfg.If("COS") { oss, v = storage.NewCosService() - } else if conf.CfgIf("HuaweiOBS") { + } else if cfg.If("HuaweiOBS") { oss, v = storage.MustHuaweiobsService() - } else if conf.CfgIf("MinIO") { + } else if cfg.If("MinIO") { oss, v = storage.MustMinioService() - } else if conf.CfgIf("S3") { + } else if cfg.If("S3") { oss, v = storage.MustS3Service() logrus.Infof("use S3 as object storage by version %s", v.Version()) return - } else if conf.CfgIf("LocalOSS") { + } else if cfg.If("LocalOSS") { oss, v = storage.MustLocalossService() } else { // default use AliOSS as object storage service @@ -71,9 +71,9 @@ func TweetSearchService() core.TweetSearchService { onceTs.Do(func() { var v core.VersionInfo ams := newAuthorizationManageService() - if conf.CfgIf("Zinc") { + if cfg.If("Zinc") { ts, v = search.NewZincTweetSearchService(ams) - } else if conf.CfgIf("Meili") { + } else if cfg.If("Meili") { ts, v = search.NewMeiliTweetSearchService(ams) } else { // default use Zinc as tweet search service @@ -87,11 +87,11 @@ func TweetSearchService() core.TweetSearchService { } func newAuthorizationManageService() (s core.AuthorizationManageService) { - if conf.CfgIf("Gorm") { + if cfg.If("Gorm") { s = jinzhu.NewAuthorizationManageService() - } else if conf.CfgIf("Sqlx") && conf.CfgIf("MySQL") { + } else if cfg.If("Sqlx") && cfg.If("MySQL") { s = sakila.NewAuthorizationManageService() - } else if conf.CfgIf("Sqlx") && (conf.CfgIf("Postgres") || conf.CfgIf("PostgreSQL")) { + } else if cfg.If("Sqlx") && (cfg.If("Postgres") || cfg.If("PostgreSQL")) { s = slonik.NewAuthorizationManageService() } else { s = jinzhu.NewAuthorizationManageService() diff --git a/internal/dao/jinzhu/jinzhu.go b/internal/dao/jinzhu/jinzhu.go index a0a7f1f1..9f5e1c66 100644 --- a/internal/dao/jinzhu/jinzhu.go +++ b/internal/dao/jinzhu/jinzhu.go @@ -10,6 +10,7 @@ import ( "github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/dao/cache" "github.com/rocboss/paopao-ce/internal/dao/security" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" ) @@ -43,10 +44,10 @@ func NewDataService() (core.DataService, core.VersionInfo) { db := conf.MustGormDB() i := newIndexPostsService(db) - if conf.CfgIf("SimpleCacheIndex") { + if cfg.If("SimpleCacheIndex") { i = newSimpleIndexPostsService(db) c, v = cache.NewSimpleCacheIndexService(i) - } else if conf.CfgIf("BigCacheIndex") { + } else if cfg.If("BigCacheIndex") { a := newAuthorizationManageService(db) c, v = cache.NewBigCacheIndexService(i, a) } else { diff --git a/internal/dao/storage/storage.go b/internal/dao/storage/storage.go index 83ad6b0d..8e124047 100644 --- a/internal/dao/storage/storage.go +++ b/internal/dao/storage/storage.go @@ -14,6 +14,7 @@ import ( "github.com/minio/minio-go/v7/pkg/credentials" "github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/core" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" "github.com/tencentyun/cos-go-sdk-v5" ) @@ -31,14 +32,14 @@ func MustAliossService() (core.ObjectStorageService, core.VersionInfo) { domain := conf.GetOssDomain() var cs core.OssCreateService - if conf.CfgIf("OSS:TempDir") { + if cfg.If("OSS:TempDir") { cs = &aliossCreateTempDirServant{ bucket: bucket, domain: domain, tempDir: conf.ObjectStorage.TempDirSlash(), } logrus.Debugln("use OSS:TempDir feature") - } else if conf.CfgIf("OSS:Retention") { + } else if cfg.If("OSS:Retention") { cs = &aliossCreateRetentionServant{ bucket: bucket, domain: domain, @@ -75,7 +76,7 @@ func NewCosService() (core.ObjectStorageService, core.VersionInfo) { domain := conf.GetOssDomain() var cs core.OssCreateService - if conf.CfgIf("OSS:TempDir") { + if cfg.If("OSS:TempDir") { cs = &cosCreateTempDirServant{ client: client, domain: domain, @@ -108,7 +109,7 @@ func MustHuaweiobsService() (core.ObjectStorageService, core.VersionInfo) { domain := conf.GetOssDomain() var cs core.OssCreateService - if conf.CfgIf("OSS:TempDir") { + if cfg.If("OSS:TempDir") { cs = &hwobsCreateTempDirServant{ client: client, bucket: s.Bucket, @@ -116,7 +117,7 @@ func MustHuaweiobsService() (core.ObjectStorageService, core.VersionInfo) { tempDir: conf.ObjectStorage.TempDirSlash(), } logrus.Debugln("use OSS:TempDir feature") - } else if conf.CfgIf("OSS:Retention") { + } else if cfg.If("OSS:Retention") { retainUntilDays := time.Until(time.Date(2049, time.December, 1, 12, 0, 0, 0, time.UTC)) / (24 * time.Hour) cs = &hwobsCreateRetentionServant{ client: client, @@ -153,7 +154,7 @@ func MustLocalossService() (core.ObjectStorageService, core.VersionInfo) { domain := conf.GetOssDomain() savePath = savePath + "/" + conf.LocalOSSSetting.Bucket + "/" var cs core.OssCreateService - if conf.CfgIf("OSS:TempDir") { + if cfg.If("OSS:TempDir") { cs = &localossCreateTempDirServant{ savePath: savePath, domain: domain, @@ -188,7 +189,7 @@ func MustMinioService() (core.ObjectStorageService, core.VersionInfo) { domain := conf.GetOssDomain() var cs core.OssCreateService - if conf.CfgIf("OSS:TempDir") { + if cfg.If("OSS:TempDir") { cs = &minioCreateTempDirServant{ client: client, bucket: conf.MinIOSetting.Bucket, @@ -196,7 +197,7 @@ func MustMinioService() (core.ObjectStorageService, core.VersionInfo) { tempDir: conf.ObjectStorage.TempDirSlash(), } logrus.Debugln("use OSS:TempDir feature") - } else if conf.CfgIf("OSS:Retention") { + } else if cfg.If("OSS:Retention") { cs = &minioCreateRetentionServant{ client: client, bucket: conf.MinIOSetting.Bucket, @@ -235,7 +236,7 @@ func MustS3Service() (core.ObjectStorageService, core.VersionInfo) { domain := conf.GetOssDomain() var cs core.OssCreateService - if conf.CfgIf("OSS:TempDir") { + if cfg.If("OSS:TempDir") { cs = &minioCreateTempDirServant{ client: client, bucket: conf.S3Setting.Bucket, @@ -243,7 +244,7 @@ func MustS3Service() (core.ObjectStorageService, core.VersionInfo) { tempDir: conf.ObjectStorage.TempDirSlash(), } logrus.Debugln("use OSS:TempDir feature") - } else if conf.CfgIf("OSS:Retention") { + } else if cfg.If("OSS:Retention") { cs = &minioCreateRetentionServant{ client: client, bucket: conf.S3Setting.Bucket, diff --git a/internal/middleware/priv.go b/internal/middleware/priv.go index 32ccbf41..fe31b008 100644 --- a/internal/middleware/priv.go +++ b/internal/middleware/priv.go @@ -2,14 +2,14 @@ package middleware import ( "github.com/gin-gonic/gin" - "github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/model" "github.com/rocboss/paopao-ce/pkg/app" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/rocboss/paopao-ce/pkg/errcode" ) func Priv() gin.HandlerFunc { - if conf.CfgIf("PhoneBind") { + if cfg.If("PhoneBind") { return func(c *gin.Context) { if u, exist := c.Get("USER"); exist { if user, ok := u.(*model.User); ok { diff --git a/internal/migration/migration.go b/internal/migration/migration.go index dec12c19..44c16fb4 100644 --- a/internal/migration/migration.go +++ b/internal/migration/migration.go @@ -4,12 +4,12 @@ package migration import ( - "github.com/rocboss/paopao-ce/internal/conf" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" ) func Run() { - if conf.CfgIf("Migration") { + if cfg.If("Migration") { logrus.Infoln("want migrate feature but not support in this compile version") } } diff --git a/internal/migration/migration_embed.go b/internal/migration/migration_embed.go index c9368987..84952538 100644 --- a/internal/migration/migration_embed.go +++ b/internal/migration/migration_embed.go @@ -14,12 +14,13 @@ import ( "github.com/golang-migrate/migrate/v4/source" "github.com/golang-migrate/migrate/v4/source/iofs" "github.com/rocboss/paopao-ce/internal/conf" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/rocboss/paopao-ce/scripts/migration" "github.com/sirupsen/logrus" ) func Run() { - if !conf.CfgIf("Migration") { + if !cfg.If("Migration") { logrus.Infoln("skip migrate because not add Migration feature in config.yaml") return } @@ -32,13 +33,13 @@ func Run() { err, err2 error ) - if conf.CfgIf("MySQL") { + if cfg.If("MySQL") { dbName = conf.MysqlSetting.DBName db, err = sql.Open("mysql", conf.MysqlSetting.Dsn()+"&multiStatements=true") - } else if conf.CfgIf("PostgreSQL") || conf.CfgIf("Postgres") { + } else if cfg.If("PostgreSQL") || cfg.If("Postgres") { dbName = (*conf.PostgresSetting)["DBName"] db, err = sql.Open("postgres", conf.PostgresSetting.Dsn()) - } else if conf.CfgIf("Sqlite3") { + } else if cfg.If("Sqlite3") { db, err = conf.OpenSqlite3() } else { dbName = conf.MysqlSetting.DBName @@ -50,13 +51,13 @@ func Run() { } migrationsTable := conf.DatabaseSetting.TablePrefix + "schema_migrations" - if conf.CfgIf("MySQL") { + if cfg.If("MySQL") { srcDriver, err = iofs.New(migration.Files, "mysql") dbDriver, err2 = mysql.WithInstance(db, &mysql.Config{MigrationsTable: migrationsTable}) - } else if conf.CfgIf("PostgreSQL") || conf.CfgIf("Postgres") { + } else if cfg.If("PostgreSQL") || cfg.If("Postgres") { srcDriver, err = iofs.New(migration.Files, "postgres") dbDriver, err2 = postgres.WithInstance(db, &postgres.Config{MigrationsTable: migrationsTable}) - } else if conf.CfgIf("Sqlite3") { + } else if cfg.If("Sqlite3") { srcDriver, err = iofs.New(migration.Files, "sqlite3") dbDriver, err2 = sqlite3.WithInstance(db, &sqlite3.Config{MigrationsTable: migrationsTable}) } else { diff --git a/internal/routers/api/api.go b/internal/routers/api/api.go index afc24578..c722ac88 100644 --- a/internal/routers/api/api.go +++ b/internal/routers/api/api.go @@ -4,6 +4,7 @@ import ( "github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/dao" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" "github.com/smartwalle/alipay/v3" ) @@ -16,7 +17,7 @@ var ( func Initialize() { objectStorage = dao.ObjectStorageService() - if conf.CfgIf("Alipay") { + if cfg.If("Alipay") { initAlipay() } } diff --git a/internal/routers/docs_embed.go b/internal/routers/docs_embed.go index 1ae71513..e9c0d17d 100644 --- a/internal/routers/docs_embed.go +++ b/internal/routers/docs_embed.go @@ -6,12 +6,12 @@ package routers import ( "github.com/gin-gonic/gin" "github.com/rocboss/paopao-ce/docs/openapi" - "github.com/rocboss/paopao-ce/internal/conf" + "github.com/rocboss/paopao-ce/pkg/cfg" ) // registerDocs register docs asset route func registerDocs(e *gin.Engine) { - if conf.CfgIf("Docs:OpenAPI") { + cfg.Be("Docs:OpenAPI", func() { e.StaticFS("/docs/openapi", openapi.NewFileSystem()) - } + }) } diff --git a/internal/routers/router.go b/internal/routers/router.go index 6a746472..1a2b57f6 100644 --- a/internal/routers/router.go +++ b/internal/routers/router.go @@ -9,6 +9,7 @@ import ( "github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/middleware" "github.com/rocboss/paopao-ce/internal/routers/api" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" ) @@ -28,7 +29,10 @@ func NewRouter() *gin.Engine { { registerDocs(e) registerStatick(e) - routeLocalOSS(e) + + cfg.Be("LocalOSS", func() { + routeLocalOSS(e) + }) } // v1 group api @@ -84,7 +88,9 @@ func NewRouter() *gin.Engine { routeCore(authApi, privApi, adminApi) // 支付宝路由注册 - routeAlipay(r, authApi) + cfg.Be("Alipay", func() { + routeAlipay(r, authApi) + }) // Relationship相关路由注册 routeRelationship(authApi) @@ -205,10 +211,6 @@ func routeCore(authApi gin.IRoutes, privApi gin.IRoutes, adminApi gin.IRoutes) { // routeLocalOSS register LocalOSS route if needed func routeLocalOSS(e *gin.Engine) { - if !conf.CfgIf("LocalOSS") { - return - } - savePath, err := filepath.Abs(conf.LocalOSSSetting.SavePath) if err != nil { logrus.Fatalf("get localOSS save path err: %v", err) @@ -220,10 +222,6 @@ func routeLocalOSS(e *gin.Engine) { // routeAlipay register Alipay feature releated route if needed func routeAlipay(public gin.IRoutes, authApi gin.IRoutes) { - if !conf.CfgIf("Alipay") { - return - } - // 支付宝回调 public.POST("/alipay/notify", api.AlipayNotify) @@ -239,15 +237,18 @@ func routeAlipay(public gin.IRoutes, authApi gin.IRoutes) { // routeRelationship register Relationship releated routes func routeRelationship(authApi gin.IRoutes) { - if conf.CfgIf("Friendship") { - routeFriendship(authApi) - } else if conf.CfgIf("Followship") { - routeFollowship(authApi) - } else { + cfg.In(cfg.Actions{ + "Friendship": func() { + routeFriendship(authApi) + }, + "Followship": func() { + routeFollowship(authApi) + }, + }, func() { // 暂时默认使用好友模式 // TODO: 后期提供一种无关系模式(既不是好友模式也不是关注者模式)作为默认的关系模式 routeFriendship(authApi) - } + }) } // routeFriendship register Friendship feature releated routes diff --git a/internal/servants/chain/priv.go b/internal/servants/chain/priv.go index 60409b6b..a60ebe41 100644 --- a/internal/servants/chain/priv.go +++ b/internal/servants/chain/priv.go @@ -2,14 +2,14 @@ package chain import ( "github.com/gin-gonic/gin" - "github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/model" "github.com/rocboss/paopao-ce/pkg/app" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/rocboss/paopao-ce/pkg/errcode" ) func Priv() gin.HandlerFunc { - if conf.CfgIf("PhoneBind") { + if cfg.If("PhoneBind") { return func(c *gin.Context) { if u, exist := c.Get("USER"); exist { if user, ok := u.(*model.User); ok { diff --git a/internal/servants/docs_embed.go b/internal/servants/docs_embed.go index aeb0b4cd..1d7efb0f 100644 --- a/internal/servants/docs_embed.go +++ b/internal/servants/docs_embed.go @@ -6,12 +6,12 @@ package servants import ( "github.com/gin-gonic/gin" "github.com/rocboss/paopao-ce/docs/openapi" - "github.com/rocboss/paopao-ce/internal/conf" + "github.com/rocboss/paopao-ce/pkg/cfg" ) // registerDocs register docs asset route func registerDocs(e *gin.Engine) { - if conf.CfgIf("Docs:OpenAPI") { + cfg.Be("Docs:OpenAPI", func() { e.StaticFS("/docs/openapi", openapi.NewFileSystem()) - } + }) } diff --git a/internal/servants/localoss/localoss.go b/internal/servants/localoss/localoss.go index ba37ddf8..1435e300 100644 --- a/internal/servants/localoss/localoss.go +++ b/internal/servants/localoss/localoss.go @@ -14,10 +14,6 @@ type localossSrv struct { // RouteLocalOSS register LocalOSS route if needed func RouteLocalOSS(e *gin.Engine) { - if !conf.CfgIf("LocalOSS") { - return - } - savePath, err := filepath.Abs(conf.LocalOSSSetting.SavePath) if err != nil { logrus.Fatalf("get localOSS save path err: %v", err) diff --git a/internal/servants/servants.go b/internal/servants/servants.go index fb03aff1..c61dcc82 100644 --- a/internal/servants/servants.go +++ b/internal/servants/servants.go @@ -4,6 +4,7 @@ import ( "github.com/gin-gonic/gin" "github.com/rocboss/paopao-ce/internal/servants/localoss" "github.com/rocboss/paopao-ce/internal/servants/web" + "github.com/rocboss/paopao-ce/pkg/cfg" ) // RegisterWebServants register all the servants to gin.Engine @@ -15,5 +16,9 @@ func RegisterWebServants(e *gin.Engine) { } web.RouteWeb(e) - localoss.RouteLocalOSS(e) + { + cfg.Be("LocalOSS", func() { + localoss.RouteLocalOSS(e) + }) + } } diff --git a/internal/service/service.go b/internal/service/service.go index b35bc541..7236fba2 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -8,6 +8,7 @@ import ( "github.com/rocboss/paopao-ce/internal/dao" "github.com/rocboss/paopao-ce/internal/model" "github.com/rocboss/paopao-ce/internal/servants" + "github.com/rocboss/paopao-ce/pkg/cfg" "github.com/sirupsen/logrus" ) @@ -43,7 +44,7 @@ func Initialize() { ds = dao.DataService() ts = dao.TweetSearchService() oss = dao.ObjectStorageService() - DisablePhoneVerify = !conf.CfgIf("Sms") + DisablePhoneVerify = !cfg.If("Sms") } // persistMediaContents 获取媒体内容并持久化 diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go new file mode 100644 index 00000000..019deba9 --- /dev/null +++ b/pkg/cfg/cfg.go @@ -0,0 +1,41 @@ +package cfg + +var ( + _features = newEmptyFeatures() + + // Use alias of Features.Use func + Use = _features.Use + + // UseDeafult alias of Features.UseDefault func + UseDefault = _features.UseDefault + + // As alias of Features.Cfg func + As = _features.Cfg + + // If alias of Features.CfgIf func + If = _features.CfgIf + + // In alias of Features.CfgIn func + In = _features.CfgIn + + // Be alias of Feaures.CfgBe func + Be = _features.CfgBe + + // Not alias of Features.CfgNot func + Not = _features.CfgNot +) + +// Initialize initialize features in cfg pkg +func Initialize(suites map[string][]string, kv map[string]string) { + _features = NewFeatures(suites, kv) + { + // must re-assign variable below + Use = _features.Use + UseDefault = _features.UseDefault + As = _features.Cfg + If = _features.CfgIf + In = _features.CfgIn + Be = _features.CfgBe + Not = _features.CfgNot + } +} diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go new file mode 100644 index 00000000..0fccbce2 --- /dev/null +++ b/pkg/cfg/cfg_test.go @@ -0,0 +1,78 @@ +package cfg + +import ( + "testing" +) + +func TestCfg(t *testing.T) { + suites := map[string][]string{ + "default": {"Sms", "Alipay", "Zinc", "MySQL", "Redis", "AliOSS", "LogZinc"}, + "develop": {"Zinc", "MySQL", "AliOSS", "LogFile"}, + "slim": {"Zinc", "MySQL", "Redis", "AliOSS", "LogFile"}, + } + kv := map[string]string{ + "sms": "SmsJuhe", + } + + Initialize(suites, kv) + UseDefault() + + if !If("Sms") { + t.Error(`want If("Sms") == true but not`) + } + + if v, exist := As("Sms"); exist && v != "SmsJuhe" { + t.Errorf(`want As("Sms") == "SmsJuhe", true but got: "%s", "%t"`, v, exist) + } + + matched := false + Be("Alipay", func() { + matched = true + }) + if !matched { + t.Error(`want Be("Alipay", ...) matched but not`) + } + + matched = false + Not("LogFile", func() { + matched = true + }) + if !matched { + t.Error(`want Not("LogFile", ...) matched but not`) + } + + var m1, m2, m3, m4 bool + In(Actions{ + "Sms": func() { + m1 = true + }, + "Alipay": func() { + m2 = true + }, + "Meili": func() { + m4 = true + }, + }, func() { + m3 = true + }) + if !m1 || !m2 || m3 || m4 { + t.Errorf(`In("Sms", "Alipay", "Meili", ...) not correct -> m1: %t m2:%t m3:%t m4:%t`, m1, m2, m3, m4) + } + + m1 = false + m2 = false + m3 = false + In(Actions{ + "LogFile": func() { + m1 = true + }, + "Meili": func() { + m2 = true + }, + }, func() { + m3 = true + }) + if m1 || m2 || !m3 { + t.Errorf(`In("Zinc", "MySQL", ...) not correct -> m1: %t m2:%t m3:%t`, m1, m2, m3) + } +} diff --git a/pkg/cfg/feature.go b/pkg/cfg/feature.go new file mode 100644 index 00000000..4fec8737 --- /dev/null +++ b/pkg/cfg/feature.go @@ -0,0 +1,131 @@ +package cfg + +import ( + "strings" + + "github.com/rocboss/paopao-ce/pkg/types" +) + +// Features fetures info struct +type Features struct { + kv map[string]string + suites map[string][]string + features map[string]string +} + +// Actions feature-func map alias type +type Actions map[string]types.Fn + +// NewFeatures create new Features instance +func NewFeatures(suites map[string][]string, kv map[string]string) *Features { + f := &Features{ + suites: suites, + kv: kv, + features: make(map[string]string), + } + f.UseDefault() + return f +} + +func newEmptyFeatures() *Features { + return &Features{ + features: make(map[string]string), + } +} + +// UseDefault use default suite for features +func (f *Features) UseDefault() { + f.Use([]string{"default"}, true) +} + +// Use use custom suite for features +func (f *Features) Use(suite []string, noDefault bool) error { + if noDefault && len(f.features) != 0 { + f.features = make(map[string]string) + } + features := f.flatFeatures(suite) + for _, feature := range features { + if len(feature) == 0 { + continue + } + f.features[feature] = f.kv[feature] + } + return nil +} + +func (f *Features) flatFeatures(suite []string) []string { + features := make([]string, 0, len(suite)+10) + for s := suite[:]; len(s) > 0; s = s[:len(s)-1] { + item := strings.TrimSpace(strings.ToLower(s[0])) + if len(item) > 0 { + if items, exist := f.suites[item]; exist { + s = append(s, items...) + } + features = append(features, item) + } + s[0] = s[len(s)-1] + } + return features +} + +// Cfg get value by key if exist +func (f *Features) Cfg(key string) (string, bool) { + key = strings.ToLower(key) + value, exist := f.features[key] + return value, exist +} + +// CfgIf check expression is true. if expression just have a string like +// `Sms` is mean `Sms` whether define in suite feature settings. expression like +// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value +// is `SmsJuhe` +func (f *Features) CfgIf(expression string) bool { + kv := strings.Split(expression, "=") + key := strings.Trim(strings.ToLower(kv[0]), " ") + v, ok := f.features[key] + if len(kv) == 2 && ok && strings.Trim(kv[1], " ") == v { + return true + } else if len(kv) == 1 && ok { + return true + } + return false +} + +// CfgIn range actions to check item's expression is true then do the handle, defFn will handle +// if all items are not matched, +func (f *Features) CfgIn(actions Actions, defAct ...types.Fn) { + itemMatched := false + for expression, handle := range actions { + if f.CfgIf(expression) && handle != nil { + handle() + itemMatched = true + } + } + if !itemMatched && len(defAct) > 0 { + for _, handle := range defAct { + if handle != nil { + handle() + } + } + } +} + +// CfgBe check expression is true then do the handle. if expression just have a string like +// `Sms` is mean `Sms` whether defined in suite feature settings. expression like +// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value +// is `SmsJuhe` +func (f *Features) CfgBe(expression string, handle types.Fn) { + if f.CfgIf(expression) && handle != nil { + handle() + } +} + +// CfgNot check expression is not true then do the handle. if expression just have a string like +// `Sms` is mean `Sms` whether defined in suite feature settings. expression like +// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value +// is `SmsJuhe` +func (f *Features) CfgNot(expression string, handle func()) { + if !f.CfgIf(expression) { + handle() + } +} diff --git a/internal/conf/seting_test.go b/pkg/cfg/feature_test.go similarity index 80% rename from internal/conf/seting_test.go rename to pkg/cfg/feature_test.go index 895a69ad..98e01ec7 100644 --- a/internal/conf/seting_test.go +++ b/pkg/cfg/feature_test.go @@ -1,4 +1,4 @@ -package conf +package cfg import ( "testing" @@ -13,7 +13,7 @@ func TestUseDefault(t *testing.T) { kv := map[string]string{ "sms": "SmsJuhe", } - features := newFeatures(suites, kv) + f := NewFeatures(suites, kv) for _, data := range []struct { key string expect string @@ -25,7 +25,7 @@ func TestUseDefault(t *testing.T) { {"Redis", "", true}, {"Database", "", false}, } { - if v, ok := features.Cfg(data.key); ok != data.exist || v != data.expect { + if v, ok := f.Cfg(data.key); ok != data.exist || v != data.expect { t.Errorf("key: %s expect: %s exist: %t got v: %s ok: %t", data.key, data.expect, data.exist, v, ok) } } @@ -35,7 +35,7 @@ func TestUseDefault(t *testing.T) { "SmsJuhe": false, "default": true, } { - if ok := features.CfgIf(exp); res != ok { + if ok := f.CfgIf(exp); res != ok { t.Errorf("CfgIf(%s) want %t got %t", exp, res, ok) } } @@ -50,9 +50,9 @@ func TestUse(t *testing.T) { kv := map[string]string{ "sms": "SmsJuhe", } - features := newFeatures(suites, kv) + f := NewFeatures(suites, kv) - features.Use([]string{"develop"}, true) + f.Use([]string{"develop"}, true) for _, data := range []struct { key string expect string @@ -64,7 +64,7 @@ func TestUse(t *testing.T) { {"Redis", "", false}, {"Database", "", false}, } { - if v, ok := features.Cfg(data.key); ok != data.exist || v != data.expect { + if v, ok := f.Cfg(data.key); ok != data.exist || v != data.expect { t.Errorf("key: %s expect: %s exist: %t got v: %s ok: %t", data.key, data.expect, data.exist, v, ok) } } @@ -75,13 +75,13 @@ func TestUse(t *testing.T) { "default": false, "develop": true, } { - if ok := features.CfgIf(exp); res != ok { + if ok := f.CfgIf(exp); res != ok { t.Errorf("CfgIf(%s) want %t got %t", exp, res, ok) } } - features.UseDefault() - features.Use([]string{"slim", "", "demo"}, false) + f.UseDefault() + f.Use([]string{"slim", "", "demo"}, false) for _, data := range []struct { key string expect string @@ -94,7 +94,7 @@ func TestUse(t *testing.T) { {"Database", "", false}, {"demo", "", true}, } { - if v, ok := features.Cfg(data.key); ok != data.exist || v != data.expect { + if v, ok := f.Cfg(data.key); ok != data.exist || v != data.expect { t.Errorf("key: %s expect: %s exist: %t got v: %s ok: %t", data.key, data.expect, data.exist, v, ok) } } @@ -107,7 +107,7 @@ func TestUse(t *testing.T) { "slim": true, "demo": true, } { - if ok := features.CfgIf(exp); res != ok { + if ok := f.CfgIf(exp); res != ok { t.Errorf("CfgIf(%s) want %t got %t", exp, res, ok) } } diff --git a/pkg/types/types.go b/pkg/types/types.go index 2b2bd639..2696f8b9 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -1,3 +1,7 @@ package types +// Empty empty alias type type Empty = struct{} + +// Fn empty argument func alias type +type Fn = func()