diff --git a/config/reader/json/json.go b/config/reader/json/json.go index 588258f5..9150ae96 100644 --- a/config/reader/json/json.go +++ b/config/reader/json/json.go @@ -4,11 +4,11 @@ import ( "errors" "time" + "dario.cat/mergo" "github.com/go-admin-team/go-admin-core/config/encoder" "github.com/go-admin-team/go-admin-core/config/encoder/json" "github.com/go-admin-team/go-admin-core/config/reader" "github.com/go-admin-team/go-admin-core/config/source" - "github.com/imdario/mergo" ) const readerTyp = "json" diff --git a/config/source/env/env.go b/config/source/env/env.go index bdabcfc5..a5a588c6 100644 --- a/config/source/env/env.go +++ b/config/source/env/env.go @@ -6,8 +6,8 @@ import ( "strings" "time" + "dario.cat/mergo" "github.com/go-admin-team/go-admin-core/config/source" - "github.com/imdario/mergo" ) var ( @@ -117,15 +117,16 @@ func (e *env) String() string { // Underscores are delimiters for nesting, and all keys are lowercased. // // Example: -// "DATABASE_SERVER_HOST=localhost" will convert to // -// { -// "database": { -// "server": { -// "host": "localhost" -// } -// } -// } +// "DATABASE_SERVER_HOST=localhost" will convert to +// +// { +// "database": { +// "server": { +// "host": "localhost" +// } +// } +// } func NewSource(opts ...source.Option) source.Source { options := source.NewOptions(opts...) diff --git a/config/source/flag/flag.go b/config/source/flag/flag.go index cd233e2d..acb36cca 100644 --- a/config/source/flag/flag.go +++ b/config/source/flag/flag.go @@ -1,10 +1,10 @@ package flag import ( + "dario.cat/mergo" "errors" "flag" "github.com/go-admin-team/go-admin-core/config/source" - "github.com/imdario/mergo" "strings" "time" ) @@ -89,13 +89,14 @@ func (fs *flagsrc) String() string { // Hyphens are delimiters for nesting, and all keys are lowercased. // // Example: -// dbhost := flag.String("database-host", "localhost", "the db host name") // -// { -// "database": { -// "host": "localhost" -// } -// } +// dbhost := flag.String("database-host", "localhost", "the db host name") +// +// { +// "database": { +// "host": "localhost" +// } +// } func NewSource(opts ...source.Option) source.Source { return &flagsrc{opts: source.NewOptions(opts...)} } diff --git a/debug/writer/file.go b/debug/writer/file.go index eafb2aa7..2a8bb8ed 100644 --- a/debug/writer/file.go +++ b/debug/writer/file.go @@ -14,6 +14,8 @@ import ( // 用于文件名称格式 const timeFormat = "2006-01-02" +const MB = 1024 * 1024 + // FileWriter 文件写入结构体 type FileWriter struct { file *os.File @@ -78,9 +80,9 @@ func (p *FileWriter) write() { func (p *FileWriter) checkFile() { info, _ := p.file.Stat() if strings.Index(p.file.Name(), time.Now().Format(timeFormat)) < 0 || - (p.opts.cap > 0 && uint(info.Size()) > p.opts.cap) { + (p.opts.cap > 0 && uint(info.Size()) > p.opts.cap*MB) { //生成新文件 - if uint(info.Size()) > p.opts.cap { + if uint(info.Size()) > p.opts.cap*MB { p.num++ } else { p.num = 0 @@ -88,6 +90,34 @@ func (p *FileWriter) checkFile() { filename := p.getFilename() _ = p.file.Close() p.file, _ = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC, 0600) + + dir := filepath.Dir(p.file.Name()) + files, err := os.ReadDir(dir) + if err != nil { + fmt.Println("Error reading log directory:", err) + return + } + + for _, file := range files { + if !file.IsDir() && strings.HasSuffix(file.Name(), p.opts.suffix) { + filePath := filepath.Join(dir, file.Name()) + fileInfo, err := file.Info() + if err != nil { + fmt.Println("Error get Info file:", err) + break + } + fileModTime := fileInfo.ModTime() + daysSinceMod := uint(time.Since(fileModTime).Hours() / 24) + if daysSinceMod > p.opts.daysToKeep { + err := os.Remove(filePath) + if err != nil { + fmt.Println("Error deleting file:", err) + } else { + fmt.Println("Deleted file:", filePath) + } + } + } + } } } diff --git a/debug/writer/options.go b/debug/writer/options.go index f745cfab..580a05ff 100644 --- a/debug/writer/options.go +++ b/debug/writer/options.go @@ -9,29 +9,31 @@ package writer // Options 可配置参数 type Options struct { - path string - suffix string //文件扩展名 - cap uint + path string //文件路径 + suffix string //文件扩展名 + daysToKeep uint //保存天数 + cap uint //文件大小 } func setDefault() Options { return Options{ - path: "/tmp/go-admin", - suffix: "log", + path: "/tmp/go-admin", + suffix: "log", + daysToKeep: 7, } } // Option set options type Option func(*Options) -// WithPath set path +// WithPath 设置文件路径 func WithPath(s string) Option { return func(o *Options) { o.path = s } } -// WithSuffix set suffix +// WithSuffix 设置文件扩展名 func WithSuffix(s string) Option { return func(o *Options) { o.suffix = s @@ -44,3 +46,10 @@ func WithCap(n uint) Option { o.cap = n } } + +// WithDaysToKeep 设置文件保留天数 +func WithDaysToKeep(n uint) Option { + return func(o *Options) { + o.daysToKeep = n + } +} diff --git a/go.mod b/go.mod index 258f930c..e968b8dc 100644 --- a/go.mod +++ b/go.mod @@ -1,84 +1,94 @@ module github.com/go-admin-team/go-admin-core -go 1.18 +go 1.21 require ( - github.com/BurntSushi/toml v0.3.1 - github.com/bitly/go-simplejson v0.5.0 - github.com/bsm/redislock v0.8.2 - github.com/fsnotify/fsnotify v1.4.9 + dario.cat/mergo v1.0.0 + github.com/BurntSushi/toml v1.3.2 + github.com/bitly/go-simplejson v0.5.1 + github.com/bsm/redislock v0.9.4 + github.com/fsnotify/fsnotify v1.7.0 github.com/ghodss/yaml v1.0.0 - github.com/gin-gonic/gin v1.7.7 + github.com/gin-gonic/gin v1.9.1 github.com/go-admin-team/redisqueue/v2 v2.0.0 - github.com/go-redis/redis/v9 v9.0.0-rc.1 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/google/uuid v1.3.0 - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/google/uuid v1.5.0 + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/imdario/mergo v0.3.9 - github.com/json-iterator/go v1.1.11 - github.com/nsqio/go-nsq v1.0.8 + github.com/json-iterator/go v1.1.12 + github.com/nsqio/go-nsq v1.1.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.11.0 + github.com/prometheus/client_golang v1.17.0 + github.com/redis/go-redis/v9 v9.3.1 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - github.com/smartystreets/goconvey v1.6.4 - github.com/spf13/cast v1.3.1 - github.com/xuri/excelize/v2 v2.6.1 - golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 - google.golang.org/grpc v1.29.1 - google.golang.org/protobuf v1.28.0 - gorm.io/driver/mysql v1.4.4 - gorm.io/gorm v1.24.2 - gorm.io/plugin/dbresolver v1.3.0 + github.com/smartystreets/goconvey v1.8.1 + github.com/spf13/cast v1.5.1 + github.com/xuri/excelize/v2 v2.8.0 + golang.org/x/crypto v0.14.0 + google.golang.org/grpc v1.59.0 + google.golang.org/protobuf v1.31.0 + gorm.io/driver/mysql v1.5.2 + gorm.io/gorm v1.25.5 + gorm.io/plugin/dbresolver v1.4.7 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/bytedance/sonic v1.10.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/git-chglog/git-chglog v0.0.0-20190611050339-63a4e637021f // indirect - github.com/go-playground/locales v0.13.0 // indirect - github.com/go-playground/universal-translator v0.17.0 // indirect - github.com/go-playground/validator/v10 v10.4.1 // indirect - github.com/go-sql-driver/mysql v1.6.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.1 // indirect - github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect + github.com/imdario/mergo v0.3.7 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/leodido/go-urn v1.2.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-colorable v0.1.7 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/goveralls v0.0.2 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.26.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect - github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect + github.com/smarty/assertions v1.15.0 // indirect github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect - github.com/ugorji/go/codec v1.1.7 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect github.com/urfave/cli v1.20.0 // indirect - github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect - github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect - golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.12 // indirect - google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect + github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/image v0.11.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.7.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/logger/default.go b/logger/default.go index 1cb71dfe..51c7bffb 100644 --- a/logger/default.go +++ b/logger/default.go @@ -97,7 +97,7 @@ func (l *defaultLogger) logf(level Level, format string, v ...interface{}) { fields := copyFields(l.opts.Fields) l.RUnlock() - fields["level"] = level.String() + //fields["level"] = level.String() if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok && level.String() == "error" { fields["file"] = fmt.Sprintf("%s:%d", logCallerfilePath(file), line) @@ -134,16 +134,16 @@ func (l *defaultLogger) logf(level Level, format string, v ...interface{}) { if l.opts.Name != "" { name = "[" + l.opts.Name + "]" } - t := rec.Timestamp.Format("2006-01-02 15:04:05.000Z0700") - //fmt.Printf("%s\n", t) - //fmt.Printf("%s\n", name) - //fmt.Printf("%s\n", metadata) - //fmt.Printf("%v\n", rec.Message) + timeFormat := "2006-01-02 15:04:05" + if l.opts.TimeFormat != "" { + timeFormat = l.opts.TimeFormat + } + t := rec.Timestamp.Format(timeFormat) logStr := "" if name == "" { - logStr = fmt.Sprintf("%s %s %v\n", t, metadata, rec.Message) + logStr = fmt.Sprintf("%s %s %s %v\n", t, level.String(), metadata, rec.Message) } else { - logStr = fmt.Sprintf("%s %s %s %v\n", name, t, metadata, rec.Message) + logStr = fmt.Sprintf("%s %s %s %s %v\n", name, t, level.String(), metadata, rec.Message) } _, err := l.opts.Out.Write([]byte(logStr)) if err != nil { diff --git a/logger/options.go b/logger/options.go index edfc41ce..dcfbfa0a 100644 --- a/logger/options.go +++ b/logger/options.go @@ -20,6 +20,8 @@ type Options struct { Context context.Context // Name logger name Name string + // Timestamp.Format + TimeFormat string } // WithFields set default fields for the logger @@ -29,6 +31,12 @@ func WithFields(fields map[string]interface{}) Option { } } +func RemoveFieldByKey(key string) Option { + return func(args *Options) { + delete(args.Fields, key) + } +} + // WithLevel set default level for the logger func WithLevel(level Level) Option { return func(args *Options) { @@ -57,6 +65,13 @@ func WithName(name string) Option { } } +// WithTimeFormat set time format for logger eg. 2006-01-02 15:04:05.000Z0700 +func WithTimeFormat(TimeFormat string) Option { + return func(args *Options) { + args.TimeFormat = TimeFormat + } +} + func SetOption(k, v interface{}) Option { return func(o *Options) { if o.Context == nil { diff --git a/plugins/logger/logrus/go.mod b/plugins/logger/logrus/go.mod index 5503fb31..a4b0d629 100644 --- a/plugins/logger/logrus/go.mod +++ b/plugins/logger/logrus/go.mod @@ -1,15 +1,12 @@ module github.com/go-admin-team/go-admin-core/plugins/logger/logrus -go 1.18 +go 1.21 require ( - github.com/go-admin-team/go-admin-core v1.3.11 - github.com/sirupsen/logrus v1.8.0 + github.com/go-admin-team/go-admin-core v1.5.2-0.20231103104827-82b086d9e2c1 + github.com/sirupsen/logrus v1.9.3 ) -require ( - github.com/magefile/mage v1.10.0 // indirect - golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 // indirect -) +require golang.org/x/sys v0.13.0 // indirect //replace github.com/go-admin-team/go-admin-core => ../../../ diff --git a/plugins/logger/zap/go.mod b/plugins/logger/zap/go.mod index 43ce2f8a..7d3905a5 100644 --- a/plugins/logger/zap/go.mod +++ b/plugins/logger/zap/go.mod @@ -1,10 +1,12 @@ module github.com/go-admin-team/go-admin-core/plugins/logger/zap -go 1.18 +go 1.21 require ( - github.com/go-admin-team/go-admin-core v1.3.11 - go.uber.org/zap v1.10.0 + github.com/go-admin-team/go-admin-core v1.5.2-0.20231103104827-82b086d9e2c1 + go.uber.org/zap v1.26.0 ) -//replace github.com/go-admin-team/go-admin-core => ../../../ +require go.uber.org/multierr v1.10.0 // indirect + +//replace github.com/go-admin-team/go-admin-core v1.3.11 => ../../../ diff --git a/plugins/logger/zap/zap_test.go b/plugins/logger/zap/zap_test.go index 3e7fc442..8634578c 100644 --- a/plugins/logger/zap/zap_test.go +++ b/plugins/logger/zap/zap_test.go @@ -67,7 +67,7 @@ func TestFields(t *testing.T) { } func TestFile(t *testing.T) { - output, err := writer.NewFileWriter("testdata", "log") + output, err := writer.NewFileWriter(writer.WithPath("testdata"), writer.WithSuffix("log")) if err != nil { t.Errorf("logger setup error: %s", err.Error()) } @@ -82,3 +82,18 @@ func TestFile(t *testing.T) { fmt.Println(logger.DefaultLogger) logger.DefaultLogger.Log(logger.InfoLevel, "hello") } + +//func TestFileKeep(t *testing.T) { +// output, err := writer.NewFileWriter(writer.WithPath("testdata"), writer.WithSuffix("log")) +// if err != nil { +// t.Errorf("logger setup error: %s", err.Error()) +// } +// //var err error +// logger.DefaultLogger, err = NewLogger(logger.WithLevel(logger.TraceLevel), WithOutput(output)) +// if err != nil { +// t.Errorf("logger setup error: %s", err.Error()) +// } +// +// fmt.Println(logger.DefaultLogger) +// logger. +//} diff --git a/sdk/config/application.go b/sdk/config/application.go index af1402e2..bccd85b5 100644 --- a/sdk/config/application.go +++ b/sdk/config/application.go @@ -6,7 +6,6 @@ type Application struct { Host string Port int64 Name string - JwtSecret string Mode string DemoMsg string EnableDP bool diff --git a/sdk/config/locker.go b/sdk/config/locker.go index 5b1a335b..71a12d4c 100644 --- a/sdk/config/locker.go +++ b/sdk/config/locker.go @@ -3,7 +3,7 @@ package config import ( "github.com/go-admin-team/go-admin-core/storage" "github.com/go-admin-team/go-admin-core/storage/locker" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" ) var LockerConfig = new(Locker) diff --git a/sdk/config/logger.go b/sdk/config/logger.go index dbfc3b45..bfd061e4 100644 --- a/sdk/config/logger.go +++ b/sdk/config/logger.go @@ -3,12 +3,13 @@ package config import "github.com/go-admin-team/go-admin-core/sdk/pkg/logger" type Logger struct { - Type string - Path string - Level string - Stdout string - EnabledDB bool - Cap uint + Type string + Path string + Level string + Stdout string + EnabledDB bool + Cap uint + DaysToKeep uint } // Setup 设置logger @@ -19,6 +20,7 @@ func (e Logger) Setup() { logger.WithLevel(e.Level), logger.WithStdout(e.Stdout), logger.WithCap(e.Cap), + logger.WithDaysToKeep(e.DaysToKeep), ) } diff --git a/sdk/config/option_redis.go b/sdk/config/option_redis.go index af6c5390..0490f9a4 100644 --- a/sdk/config/option_redis.go +++ b/sdk/config/option_redis.go @@ -5,9 +5,8 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "github.com/redis/go-redis/v9" "io/ioutil" - - "github.com/go-redis/redis/v9" ) var _redis *redis.Client diff --git a/sdk/config/queue.go b/sdk/config/queue.go index b4be3a4f..c137f66b 100644 --- a/sdk/config/queue.go +++ b/sdk/config/queue.go @@ -4,7 +4,7 @@ import ( "github.com/go-admin-team/go-admin-core/storage" "github.com/go-admin-team/go-admin-core/storage/queue" "github.com/go-admin-team/redisqueue/v2" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" "time" ) diff --git a/sdk/go.mod b/sdk/go.mod index 57e96de4..2c54552b 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -1,107 +1,133 @@ module github.com/go-admin-team/go-admin-core/sdk -go 1.18 +go 1.21 require ( - github.com/bsm/redislock v0.8.2 - github.com/bytedance/go-tagexpr/v2 v2.7.12 - github.com/casbin/casbin/v2 v2.54.0 - github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd - github.com/gin-gonic/gin v1.7.7 - github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f - github.com/go-admin-team/go-admin-core/plugins/logger/zap v0.0.0-20210610020726-2db73adb505d + github.com/bsm/redislock v0.9.4 + github.com/bytedance/go-tagexpr/v2 v2.9.11 + github.com/casbin/casbin/v2 v2.77.2 + github.com/chanxuehong/wechat v0.0.0-20230222024006-36f0325263cd + github.com/gin-gonic/gin v1.9.1 + github.com/go-admin-team/go-admin-core v1.5.2-0.20231227145810-797ba969c20d + github.com/go-admin-team/go-admin-core/plugins/logger/zap v1.3.5-rc.0.0.20231103105142-2d9e40ec6f71 github.com/go-admin-team/gorm-adapter/v3 v3.2.1-0.20210902112335-4148cb356a24 - github.com/go-admin-team/redis-watcher/v2 v2.0.0-20221121052608-058cebff72c2 - github.com/go-admin-team/redisqueue/v2 v2.0.0-20221119141731-97c556b0d5b7 - github.com/go-playground/locales v0.13.0 - github.com/go-playground/universal-translator v0.17.0 - github.com/go-playground/validator/v10 v10.4.1 - github.com/go-redis/redis/v9 v9.0.0-rc.1 - github.com/golang-jwt/jwt/v4 v4.4.2 - github.com/google/uuid v1.3.0 - github.com/gorilla/websocket v1.4.2 - github.com/mojocn/base64Captcha v1.3.1 - github.com/nsqio/go-nsq v1.0.8 + github.com/go-admin-team/redis-watcher/v2 v2.0.0-20231102130416-bfe327cac940 + github.com/go-admin-team/redisqueue/v2 v2.0.1-0.20231102124201-508101cc789a + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/go-playground/validator/v10 v10.15.5 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/google/uuid v1.4.0 + github.com/gorilla/websocket v1.5.0 + github.com/mojocn/base64Captcha v1.3.6 + github.com/nsqio/go-nsq v1.1.0 + github.com/redis/go-redis/v9 v9.3.0 github.com/robfig/cron/v3 v3.0.1 github.com/shamsher31/goimgext v1.0.0 - github.com/slok/go-http-metrics v0.9.0 - github.com/smartystreets/goconvey v1.6.4 - golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b - gorm.io/gorm v1.24.2 + github.com/slok/go-http-metrics v0.11.0 + github.com/smartystreets/goconvey v1.8.1 + golang.org/x/crypto v0.14.0 + gorm.io/gorm v1.25.5 ) require ( - github.com/BurntSushi/toml v0.3.1 // indirect + dario.cat/mergo v1.0.0 // indirect + github.com/AlecAivazis/survey/v2 v2.3.6 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/andeya/ameda v1.5.3 // indirect + github.com/andeya/goutil v1.0.1 // indirect + github.com/andygrunwald/go-jira v1.16.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bitly/go-simplejson v0.5.0 // indirect - github.com/casbin/redis-watcher/v2 v2.3.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect + github.com/bitly/go-simplejson v0.5.1 // indirect + github.com/bytedance/sonic v1.10.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chanxuehong/rand v0.0.0-20211009035549-2f07823e8e99 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/fatih/color v1.7.0 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/git-chglog/git-chglog v0.0.0-20190611050339-63a4e637021f // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/git-chglog/git-chglog v0.15.4 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.1 // indirect - github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect - github.com/henrylee2cn/ameda v1.4.10 // indirect - github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect - github.com/imdario/mergo v0.3.9 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect + github.com/huandu/xstrings v1.3.3 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.13.0 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/pgx/v4 v4.17.2 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/json-iterator/go v1.1.11 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/leodido/go-urn v1.2.0 // indirect - github.com/mattn/go-colorable v0.1.7 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/kyokomi/emoji/v2 v2.2.11 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.15 // indirect - github.com/mattn/goveralls v0.0.2 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mattn/goveralls v0.0.12 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/microsoft/go-mssqldb v0.17.0 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.11.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.26.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect - github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect - github.com/spf13/cast v1.3.1 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/smarty/assertions v1.15.0 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/trivago/tgo v1.0.7 // indirect github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect - github.com/ugorji/go/codec v1.1.7 // indirect - github.com/urfave/cli v1.20.0 // indirect - go.uber.org/atomic v1.6.0 // indirect - go.uber.org/multierr v1.5.0 // indirect - go.uber.org/zap v1.13.0 // indirect - golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect - golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.12 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect - gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/urfave/cli/v2 v2.24.3 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/image v0.13.0 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.8.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gorm.io/driver/mysql v1.4.4 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.2 // indirect gorm.io/driver/postgres v1.4.5 // indirect gorm.io/driver/sqlite v1.4.3 // indirect gorm.io/driver/sqlserver v1.4.1 // indirect diff --git a/sdk/pkg/captcha/captcha.go b/sdk/pkg/captcha/captcha.go index af359e81..491fcc5b 100644 --- a/sdk/pkg/captcha/captcha.go +++ b/sdk/pkg/captcha/captcha.go @@ -12,7 +12,7 @@ func SetStore(s base64Captcha.Store) { base64Captcha.DefaultMemStore = s } -//configJsonBody json request body. +// configJsonBody json request body. type configJsonBody struct { Id string CaptchaType string @@ -24,22 +24,22 @@ type configJsonBody struct { DriverDigit *base64Captcha.DriverDigit } -func DriverStringFunc() (id, b64s string, err error) { +func DriverStringFunc() (id, b64s, answer string, err error) { e := configJsonBody{} e.Id = uuid.New().String() - e.DriverString = base64Captcha.NewDriverString(46, 140, 2, 2, 4, "234567890abcdefghjkmnpqrstuvwxyz", &color.RGBA{240, 240, 246, 246}, []string{"wqy-microhei.ttc"}) + e.DriverString = base64Captcha.NewDriverString(46, 140, 2, 2, 4, "234567890abcdefghjkmnpqrstuvwxyz", &color.RGBA{240, 240, 246, 246}, nil, []string{"wqy-microhei.ttc"}) driver := e.DriverString.ConvertFonts() - cap := base64Captcha.NewCaptcha(driver, base64Captcha.DefaultMemStore) - return cap.Generate() + captcha := base64Captcha.NewCaptcha(driver, base64Captcha.DefaultMemStore) + return captcha.Generate() } -func DriverDigitFunc() (id, b64s string, err error) { +func DriverDigitFunc() (id, b64s, answer string, err error) { e := configJsonBody{} e.Id = uuid.New().String() e.DriverDigit = base64Captcha.NewDriverDigit(80, 240, 4, 0.7, 80) driver := e.DriverDigit - cap := base64Captcha.NewCaptcha(driver, base64Captcha.DefaultMemStore) - return cap.Generate() + captcha := base64Captcha.NewCaptcha(driver, base64Captcha.DefaultMemStore) + return captcha.Generate() } // Verify 校验验证码 diff --git a/sdk/pkg/captcha/store.go b/sdk/pkg/captcha/store.go index 707b1d4e..15142fe5 100644 --- a/sdk/pkg/captcha/store.go +++ b/sdk/pkg/captcha/store.go @@ -21,8 +21,8 @@ func NewCacheStore(cache storage.AdapterCache, expiration int) base64Captcha.Sto } // Set sets the digits for the captcha id. -func (e *cacheStore) Set(id string, value string) { - _ = e.cache.Set(id, value, e.expiration) +func (e *cacheStore) Set(id string, value string) error { + return e.cache.Set(id, value, e.expiration) } // Get returns stored digits for the captcha id. Clear indicates @@ -38,7 +38,7 @@ func (e *cacheStore) Get(id string, clear bool) string { return "" } -//Verify captcha's answer directly +// Verify captcha's answer directly func (e *cacheStore) Verify(id, answer string, clear bool) bool { return e.Get(id, clear) == answer } diff --git a/sdk/pkg/casbin/log.go b/sdk/pkg/casbin/log.go index 6498c24d..b34e5b1f 100644 --- a/sdk/pkg/casbin/log.go +++ b/sdk/pkg/casbin/log.go @@ -1,9 +1,9 @@ package mycasbin import ( - "sync/atomic" - "github.com/go-admin-team/go-admin-core/logger" + "log/slog" + "sync/atomic" ) // Logger is the implementation for a Logger using golang log. @@ -11,6 +11,10 @@ type Logger struct { enable int32 } +func (l *Logger) LogError(err error, msg ...string) { + slog.Error(err.Error(), msg, err) +} + // EnableLog controls whether print the message. func (l *Logger) EnableLog(enable bool) { i := 0 diff --git a/sdk/pkg/casbin/mycasbin.go b/sdk/pkg/casbin/mycasbin.go index e4f5bf93..7bf6309a 100644 --- a/sdk/pkg/casbin/mycasbin.go +++ b/sdk/pkg/casbin/mycasbin.go @@ -10,7 +10,7 @@ import ( "github.com/go-admin-team/go-admin-core/sdk" "github.com/go-admin-team/go-admin-core/sdk/config" redisWatcher "github.com/go-admin-team/redis-watcher/v2" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" "gorm.io/gorm" gormAdapter "github.com/go-admin-team/gorm-adapter/v3" @@ -38,7 +38,7 @@ var ( func Setup(db *gorm.DB, _ string) *casbin.SyncedEnforcer { once.Do(func() { - Apter, err := gormAdapter.NewAdapterByDBUseTableName(db, "sys", "casbin_rule") + Apter, err := gormAdapter.NewAdapterByDBUseTableName(db, "", "casbin_rule") if err != nil && err.Error() != "invalid DDL" { panic(err) } diff --git a/sdk/pkg/jwtauth/jwtauth.go b/sdk/pkg/jwtauth/jwtauth.go index 51c8ecd8..19c7f841 100644 --- a/sdk/pkg/jwtauth/jwtauth.go +++ b/sdk/pkg/jwtauth/jwtauth.go @@ -3,6 +3,7 @@ package jwtauth import ( "crypto/rsa" "errors" + "fmt" "io/ioutil" "net/http" "strings" @@ -44,6 +45,11 @@ type GinJWTMiddleware struct { // Check error (e) to determine the appropriate error message. Authenticator func(c *gin.Context) (interface{}, error) + // Callback function that should perform the authentication of the user based on login info. + // Must return user data as user identifier, it will be stored in Claim Array. Required. + // Check error (e) to determine the appropriate error message. + TwoFaAuthenticator func(c *gin.Context) (interface{}, error) + // Callback function that should perform the authorization of the authenticated user. Called // only after an authentication success. Must return true on success, false on failure. // Optional, default to success. @@ -157,6 +163,8 @@ var ( // ErrFailedAuthentication indicates authentication failed, could be faulty username or password ErrFailedAuthentication = errors.New("incorrect Username or Password") + ErrFailed2FAAuthentication = errors.New("2FA authentication failed") + // ErrFailedTokenCreation indicates JWT Token failed to create, reason unknown ErrFailedTokenCreation = errors.New("failed to create JWT Token") @@ -201,6 +209,9 @@ var ( // ErrInvalidPubKey indicates the the given public key is invalid ErrInvalidPubKey = errors.New("public key invalid") + // Login Step + LoginStepKey = "loginStep" + // IdentityKey default identity key IdentityKey = "identity" @@ -396,6 +407,7 @@ func (mw *GinJWTMiddleware) middlewareImpl(c *gin.Context) { mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c)) return } + fmt.Printf("claims: %#v\n", claims) exp, err := claims.Exp() if err != nil { mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(err, c)) @@ -442,6 +454,7 @@ func (mw *GinJWTMiddleware) GetClaimsFromJWT(c *gin.Context) (MapClaims, error) // Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}. // Reply will be of the form {"token": "TOKEN"}. func (mw *GinJWTMiddleware) LoginHandler(c *gin.Context) { + fmt.Printf("这是我自定义仓库的登陆handler \r\n") if mw.Authenticator == nil { mw.unauthorized(c, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrMissingAuthenticatorFunc, c)) return @@ -483,6 +496,73 @@ func (mw *GinJWTMiddleware) LoginHandler(c *gin.Context) { ) } + if claims[LoginStepKey] == 1 { + // 第一步登陆获取临时jwt + mw.LoginResponse(c, http.StatusForbidden, tokenString, expire) + } else { + // 第二步通过2fa验证,获取正式jwt + mw.AntdLoginResponse(c, http.StatusOK, tokenString, expire) + } +} + +// Login2FAHandler can be used by clients to get a jwt token after 2fa verify success. +// Payload needs to be json in the form of {"code": "2facode", "tempToken": "temptoken"}. +// Reply will be of the form {"token": "TOKEN"}. +func (mw *GinJWTMiddleware) Login2FAHandler(c *gin.Context) { + fmt.Printf("这是我自定义仓库的2fa登陆handler \r\n") + claims, err := mw.GetClaimsFromJWT(c) + fmt.Printf("claims: %#v\n", claims) + if err != nil { + mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c)) + return + } + exp, err := claims.Exp() + if err != nil { + mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(err, c)) + return + } + if exp < mw.TimeFunc().Unix() { + mw.unauthorized(c, 6401, mw.HTTPStatusMessageFunc(ErrExpiredToken, c)) + return + } + data, err := mw.TwoFaAuthenticator(c) + if err != nil { + mw.unauthorized(c, 400, mw.HTTPStatusMessageFunc(err, c)) + return + } + // 2fa认证通过,生成访问token + token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm)) + newClaims := token.Claims.(jwt.MapClaims) + if mw.PayloadFunc != nil { + for key, value := range mw.PayloadFunc(data) { + newClaims[key] = value + } + } + fmt.Printf("new claims: %#v\n", newClaims) + expire := mw.TimeFunc().Add(mw.Timeout) + newClaims["exp"] = expire.Unix() + newClaims["orig_iat"] = mw.TimeFunc().Unix() + tokenString, err := mw.signedString(token) + + if err != nil { + mw.unauthorized(c, http.StatusOK, mw.HTTPStatusMessageFunc(ErrFailedTokenCreation, c)) + return + } + + // set cookie + if mw.SendCookie { + maxage := int(expire.Unix() - time.Now().Unix()) + c.SetCookie( + mw.CookieName, + tokenString, + maxage, + "/", + mw.CookieDomain, + mw.SecureCookie, + mw.CookieHTTPOnly, + ) + } + mw.AntdLoginResponse(c, http.StatusOK, tokenString, expire) } diff --git a/sdk/pkg/logger/options.go b/sdk/pkg/logger/options.go index 60395698..193df49a 100644 --- a/sdk/pkg/logger/options.go +++ b/sdk/pkg/logger/options.go @@ -55,3 +55,9 @@ func WithCap(n uint) Option { o.cap = n } } + +func WithDaysToKeep(n uint) Option { + return func(o *options) { + o.cap = n + } +} diff --git a/sdk/runtime/application.go b/sdk/runtime/application.go index c8190308..306a2e36 100644 --- a/sdk/runtime/application.go +++ b/sdk/runtime/application.go @@ -14,21 +14,23 @@ import ( ) type Application struct { - dbs map[string]*gorm.DB - casbins map[string]*casbin.SyncedEnforcer - engine http.Handler - crontab map[string]*cron.Cron - mux sync.RWMutex - middlewares map[string]interface{} - cache storage.AdapterCache - queue storage.AdapterQueue - locker storage.AdapterLocker - memoryQueue storage.AdapterQueue - handler map[string][]func(r *gin.RouterGroup, hand ...*gin.HandlerFunc) - routers []Router - configs map[string]interface{} // 系统参数 - appRouters []func() // app路由 - + dbs map[string]*gorm.DB + casbins map[string]*casbin.SyncedEnforcer + engine http.Handler + crontab map[string]*cron.Cron + mux sync.RWMutex + middlewares map[string]interface{} + cache storage.AdapterCache + queue storage.AdapterQueue + locker storage.AdapterLocker + memoryQueue storage.AdapterQueue + handler map[string][]func(r *gin.RouterGroup, hand ...*gin.HandlerFunc) + routers []Router + configs map[string]map[string]interface{} // 系统参数 + appRouters []func() // app路由 + casbinExclude map[string]interface{} // casbin排除 + before []func() // 启动前执行 + app map[string]interface{} // app } type Router struct { @@ -39,6 +41,62 @@ type Routers struct { List []Router } +func (e *Application) SetBefore(f func()) { + e.before = append(e.before, f) +} + +func (e *Application) GetBefore() []func() { + return e.before +} + +// SetCasbinExclude 设置对应key的Exclude +func (e *Application) SetCasbinExclude(key string, list interface{}) { + e.mux.Lock() + defer e.mux.Unlock() + e.casbinExclude[key] = list +} + +// GetCasbinExclude 获取所有map里的Exclude数据 +func (e *Application) GetCasbinExclude() map[string]interface{} { + e.mux.Lock() + defer e.mux.Unlock() + return e.casbinExclude +} + +// GetCasbinExcludeByKey 根据key获取Exclude +func (e *Application) GetCasbinExcludeByKey(key string) interface{} { + e.mux.Lock() + defer e.mux.Unlock() + if exclude, ok := e.casbinExclude["*"]; ok { + return exclude + } + return e.casbinExclude[key] +} + +// SetApp 设置对应key的app +func (e *Application) SetApp(key string, app interface{}) { + e.mux.Lock() + defer e.mux.Unlock() + e.app[key] = app +} + +// GetApp 获取所有map里的app数据 +func (e *Application) GetApp() map[string]interface{} { + e.mux.Lock() + defer e.mux.Unlock() + return e.app +} + +// GetAppByKey 根据key获取app +func (e *Application) GetAppByKey(key string) interface{} { + e.mux.Lock() + defer e.mux.Unlock() + if app, ok := e.app["*"]; ok { + return app + } + return e.app[key] +} + // SetDb 设置对应key的db func (e *Application) SetDb(key string, db *gorm.DB) { e.mux.Lock() @@ -123,14 +181,15 @@ func (e *Application) GetLogger() logger.Logger { // NewConfig 默认值 func NewConfig() *Application { return &Application{ - dbs: make(map[string]*gorm.DB), - casbins: make(map[string]*casbin.SyncedEnforcer), - crontab: make(map[string]*cron.Cron), - middlewares: make(map[string]interface{}), - memoryQueue: queue.NewMemory(10000), - handler: make(map[string][]func(r *gin.RouterGroup, hand ...*gin.HandlerFunc)), - routers: make([]Router, 0), - configs: make(map[string]interface{}), + dbs: make(map[string]*gorm.DB), + casbins: make(map[string]*casbin.SyncedEnforcer), + crontab: make(map[string]*cron.Cron), + middlewares: make(map[string]interface{}), + memoryQueue: queue.NewMemory(10000), + handler: make(map[string][]func(r *gin.RouterGroup, hand ...*gin.HandlerFunc)), + routers: make([]Router, 0), + configs: make(map[string]map[string]interface{}), + casbinExclude: make(map[string]interface{}), } } @@ -252,18 +311,35 @@ func (e *Application) GetMemoryQueue(prefix string) storage.AdapterQueue { return NewQueue(prefix, e.memoryQueue) } +// SetConfigByTenant 设置对应租户的config +func (e *Application) SetConfigByTenant(tenant string, value map[string]interface{}) { + e.mux.Lock() + defer e.mux.Unlock() + e.configs[tenant] = value +} + // SetConfig 设置对应key的config -func (e *Application) SetConfig(key string, value interface{}) { +func (e *Application) SetConfig(tenant, key string, value interface{}) { e.mux.Lock() defer e.mux.Unlock() - e.configs[key] = value + if _, ok := e.configs[tenant]; !ok { + e.configs[tenant] = make(map[string]interface{}) + } + e.configs[tenant][key] = value } // GetConfig 获取对应key的config -func (e *Application) GetConfig(key string) interface{} { +func (e *Application) GetConfig(tenant, key string) interface{} { + e.mux.Lock() + defer e.mux.Unlock() + return e.configs[tenant][key] +} + +// GetConfigByTenant 获取对应租户的config +func (e *Application) GetConfigByTenant(tenant string) interface{} { e.mux.Lock() defer e.mux.Unlock() - return e.configs[key] + return e.configs[tenant] } // SetAppRouters 设置app的路由 diff --git a/sdk/runtime/queue_test.go b/sdk/runtime/queue_test.go index d68dd5bd..903fbc32 100644 --- a/sdk/runtime/queue_test.go +++ b/sdk/runtime/queue_test.go @@ -3,7 +3,7 @@ package runtime import ( "fmt" "github.com/go-admin-team/redisqueue/v2" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" "reflect" "testing" "time" diff --git a/sdk/runtime/type.go b/sdk/runtime/type.go index c44a9df0..74302ad9 100644 --- a/sdk/runtime/type.go +++ b/sdk/runtime/type.go @@ -17,6 +17,17 @@ type Runtime interface { GetDb() map[string]*gorm.DB GetDbByKey(key string) *gorm.DB + SetApp(key string, app interface{}) + GetApp() map[string]interface{} + GetAppByKey(key string) interface{} + + SetBefore(f func()) + GetBefore() []func() + + SetCasbinExclude(key string, list interface{}) + GetCasbinExclude() map[string]interface{} + GetCasbinExcludeByKey(key string) interface{} + SetCasbin(key string, enforcer *casbin.SyncedEnforcer) GetCasbin() map[string]*casbin.SyncedEnforcer GetCasbinKey(key string) *casbin.SyncedEnforcer @@ -61,8 +72,10 @@ type Runtime interface { GetStreamMessage(id, stream string, value map[string]interface{}) (storage.Messager, error) - GetConfig(key string) interface{} - SetConfig(key string, value interface{}) + GetConfigByTenant(tenant string) interface{} + GetConfig(tenant, key string) interface{} + SetConfigByTenant(tenant string, value map[string]interface{}) + SetConfig(tenant, key string, value interface{}) // SetAppRouters set AppRouter SetAppRouters(appRouters func()) diff --git a/storage/cache/redis.go b/storage/cache/redis.go index 104a9d91..31412714 100644 --- a/storage/cache/redis.go +++ b/storage/cache/redis.go @@ -2,7 +2,7 @@ package cache import ( "context" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" "time" ) diff --git a/storage/locker/redis.go b/storage/locker/redis.go index 3e6742a8..2705b814 100644 --- a/storage/locker/redis.go +++ b/storage/locker/redis.go @@ -2,7 +2,7 @@ package locker import ( "context" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" "time" "github.com/bsm/redislock" diff --git a/storage/queue/redis.go b/storage/queue/redis.go index 36fccdf6..6b0ed843 100644 --- a/storage/queue/redis.go +++ b/storage/queue/redis.go @@ -3,7 +3,7 @@ package queue import ( "github.com/go-admin-team/go-admin-core/storage" "github.com/go-admin-team/redisqueue/v2" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" ) // NewRedis redis模式 diff --git a/storage/queue/redis_test.go b/storage/queue/redis_test.go index 42a98e28..144e521c 100644 --- a/storage/queue/redis_test.go +++ b/storage/queue/redis_test.go @@ -3,7 +3,7 @@ package queue import ( "fmt" "github.com/go-admin-team/redisqueue/v2" - "github.com/go-redis/redis/v9" + "github.com/redis/go-redis/v9" "sync" "testing" "time" diff --git a/tools/gorm/logger/logger.go b/tools/gorm/logger/logger.go index 7964dc55..d578c453 100644 --- a/tools/gorm/logger/logger.go +++ b/tools/gorm/logger/logger.go @@ -138,18 +138,18 @@ func New(config logger.Config) logger.Interface { infoStr = "%s\n[info] " warnStr = "%s\n[warn] " errStr = "%s\n[error] " - traceStr = "%s [%.3fms] [rows:%v] %s" - traceWarnStr = "%s %s [%.3fms] [rows:%v] %s" - traceErrStr = "%s %s [%.3fms] [rows:%v] %s" + traceStr = "%s\n[%.3fms] [rows:%v] %s\n" + traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s\n" + traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s\n" ) if config.Colorful { - infoStr = Green + "%s " + Reset + Green + "[info] " + Reset - warnStr = BlueBold + "%s " + Reset + Magenta + "[warn] " + Reset - errStr = Magenta + "%s " + Reset + Red + "[error] " + Reset - traceStr = Green + "%s " + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s" - traceWarnStr = Green + "%s " + Yellow + "%s " + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset - traceErrStr = RedBold + "%s " + MagentaBold + "%s " + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s" + infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset + warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset + errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset + traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s\n" + traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset + traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s" } return &gormLogger{ diff --git a/tools/search/query.go b/tools/search/query.go index ff56f1ac..503768f2 100644 --- a/tools/search/query.go +++ b/tools/search/query.go @@ -34,10 +34,10 @@ func ResolveSearchQuery(driver string, q interface{}, condition Condition) { var ok bool var t *resolveSearchTag - var sep = "`" - if driver == Postgres { - sep = "\"" - } + //var sep = "`" + //if driver == Postgres { + // sep = "\"" + //} for i := 0; i < qType.NumField(); i++ { tag, ok = "", false @@ -74,6 +74,8 @@ func pgSql(driver string, t *resolveSearchTag, condition Condition, qValue refle ResolveSearchQuery(driver, qValue.Field(i).Interface(), join) case "exact", "iexact": condition.SetWhere(fmt.Sprintf("%s.%s = ?", t.Table, t.Column), []interface{}{qValue.Field(i).Interface()}) + case "glt": + condition.SetWhere(fmt.Sprintf("%s.%s <> ?", t.Table, t.Column), []interface{}{qValue.Field(i).Interface()}) case "icontains": condition.SetWhere(fmt.Sprintf("%s.%s ilike ?", t.Table, t.Column), []interface{}{"%" + qValue.Field(i).String() + "%"}) case "contains": diff --git a/tools/utils/excel.go b/tools/utils/excel.go index 49e9db26..2e037aa7 100644 --- a/tools/utils/excel.go +++ b/tools/utils/excel.go @@ -11,9 +11,9 @@ var Cols = []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", " // WriteXlsx 填充excel func WriteXlsx(sheet string, records interface{}) *excelize.File { - xlsx := excelize.NewFile() // new file - index := xlsx.NewSheet(sheet) // new sheet - xlsx.SetActiveSheet(index) // set active (default) sheet + xlsx := excelize.NewFile() // new file + index, _ := xlsx.NewSheet(sheet) // new sheet + xlsx.SetActiveSheet(index) // set active (default) sheet t := reflect.TypeOf(records) if t.Kind() != reflect.Slice {