提交 c1638cdf authored 作者: mooncake's avatar mooncake

update

上级 d57375cc
package enums
import (
"fmt"
"reflect"
"github.com/gin-gonic/gin"
"gitlab.wanzhuangkj.com/tush/opkg/gin/response"
)
type EnumDictionary map[string]any
var dict = &EnumDictionary{}
func GetDict() *EnumDictionary {
return dict
}
func (d EnumDictionary) Add(key string, value any) {
if _, ok := d[key]; ok {
panic(fmt.Sprintf("枚举字典[%s]重复", key))
}
d[key] = value
}
func HandleDict(c *gin.Context) {
response.Success(c, dict)
}
func HandleDictWithDict(c *gin.Context, d *EnumDictionary) {
response.Success(c, d)
}
func HandleDictOptions(c *gin.Context) {
ret, _ := convertMap(dict)
response.Success(c, ret)
}
func HandleDictOptionsWithDict(c *gin.Context, d *EnumDictionary) {
ret, _ := convertMap(d)
response.Success(c, ret)
}
type BaseReply struct {
Code int `json:"code" form:"code" example:"1"`
Msg string `json:"message" form:"message" example:"OK"`
Data interface{} `json:"data"`
TimeStamp int64 `json:"timestamp" form:"data" example:"1718850053"`
TraceID string `json:"traceID" form:"traceID" example:"7f0000016673920576f0659c620086b0"`
}
type LabelValue struct {
Label string `json:"label"`
Value any `json:"value"`
}
func convertMap(input *EnumDictionary) (map[string][]LabelValue, error) {
result := make(map[string][]LabelValue)
for outerKey, innerValue := range *input {
innerValueRef := reflect.ValueOf(innerValue)
if innerValueRef.Kind() != reflect.Map {
return nil, fmt.Errorf("value for key '%s' is not a map", outerKey)
}
var items []LabelValue
for _, key := range innerValueRef.MapKeys() {
value := innerValueRef.MapIndex(key)
if value.Kind() != reflect.String {
continue
}
var keyValue any
switch key.Kind() {
case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Float64, reflect.Bool:
keyValue = key.Interface()
default:
keyValue = fmt.Sprintf("%v", key.Interface())
}
items = append(items, LabelValue{
Label: value.String(),
Value: keyValue,
})
}
result[outerKey] = items
}
return result, nil
}
package prof
import (
"net/http/pprof"
"github.com/felixge/fgprof"
"github.com/gin-gonic/gin"
)
var defaultPrefix = "/debug/pprof"
// Option set defaultPrefix func
type Option func(o *options)
type options struct {
prefix string
enableIOWaitTime bool
}
func (o *options) apply(opts ...Option) {
for _, opt := range opts {
opt(o)
}
}
// WithPrefix set route defaultPrefix
func WithPrefix(prefix string) Option {
return func(o *options) {
if prefix == "" {
return
}
o.prefix = prefix
}
}
// WithIOWaitTime enable IO wait time
func WithIOWaitTime() Option {
return func(o *options) {
o.enableIOWaitTime = true
}
}
// Register pprof for gin router
func Register(r *gin.Engine, opts ...Option) {
o := &options{prefix: defaultPrefix}
o.apply(opts...)
group := r.Group(o.prefix)
group.GET("/", gin.WrapF(pprof.Index))
group.GET("/cmdline", gin.WrapF(pprof.Cmdline))
group.GET("/profile", gin.WrapF(pprof.Profile))
group.POST("/symbol", gin.WrapF(pprof.Symbol))
group.GET("/symbol", gin.WrapF(pprof.Symbol))
group.GET("/trace", gin.WrapF(pprof.Trace))
group.GET("/allocs", gin.WrapH(pprof.Handler("allocs")))
group.GET("/block", gin.WrapH(pprof.Handler("block")))
group.GET("/goroutine", gin.WrapH(pprof.Handler("goroutine")))
group.GET("/heap", gin.WrapH(pprof.Handler("heap")))
group.GET("/mutex", gin.WrapH(pprof.Handler("mutex")))
group.GET("/threadcreate", gin.WrapH(pprof.Handler("threadcreate")))
if o.enableIOWaitTime {
// Similar to /profile, add IO wait time, https://github.com/felixge/fgprof
group.GET("/profile-io", gin.WrapH(fgprof.Handler()))
}
}
package router
import "github.com/gin-gonic/gin"
func Register(r *gin.Engine, groupPath string, routerFns []func(*gin.RouterGroup), middlewares ...gin.HandlerFunc) {
rg := r.Group(groupPath)
rg.Use(middlewares...)
for _, fn := range routerFns {
fn(rg)
}
}
...@@ -5,6 +5,7 @@ go 1.24.3 ...@@ -5,6 +5,7 @@ go 1.24.3
require ( require (
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/bwmarrin/snowflake v0.3.0 github.com/bwmarrin/snowflake v0.3.0
github.com/felixge/fgprof v0.9.3
github.com/gin-contrib/cors v1.7.6 github.com/gin-contrib/cors v1.7.6
github.com/gin-gonic/gin v1.11.0 github.com/gin-gonic/gin v1.11.0
github.com/go-redsync/redsync/v4 v4.14.0 github.com/go-redsync/redsync/v4 v4.14.0
...@@ -20,11 +21,11 @@ require ( ...@@ -20,11 +21,11 @@ require (
github.com/spf13/cast v1.10.0 github.com/spf13/cast v1.10.0
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
github.com/uptrace/opentelemetry-go-extra/otelgorm v0.3.2 github.com/uptrace/opentelemetry-go-extra/otelgorm v0.3.2
gitlab.wanzhuangkj.com/tush/xpkg v1.2.30
go.opentelemetry.io/contrib v1.38.0 go.opentelemetry.io/contrib v1.38.0
go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel v1.37.0
go.opentelemetry.io/otel/trace v1.37.0 go.opentelemetry.io/otel/trace v1.37.0
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
golang.org/x/crypto v0.40.0
golang.org/x/sync v0.17.0 golang.org/x/sync v0.17.0
google.golang.org/grpc v1.76.0 google.golang.org/grpc v1.76.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
...@@ -58,6 +59,7 @@ require ( ...@@ -58,6 +59,7 @@ require (
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect github.com/goccy/go-yaml v1.18.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
...@@ -94,7 +96,6 @@ require ( ...@@ -94,7 +96,6 @@ require (
go.uber.org/mock v0.5.0 // indirect go.uber.org/mock v0.5.0 // indirect
go.uber.org/multierr v1.10.0 // indirect go.uber.org/multierr v1.10.0 // indirect
golang.org/x/arch v0.20.0 // indirect golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/image v0.23.0 // indirect golang.org/x/image v0.23.0 // indirect
golang.org/x/mod v0.25.0 // indirect golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.42.0 // indirect golang.org/x/net v0.42.0 // indirect
......
...@@ -16,6 +16,9 @@ github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZw ...@@ -16,6 +16,9 @@ github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZw
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
...@@ -23,6 +26,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c ...@@ -23,6 +26,8 @@ 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/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 h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
...@@ -77,6 +82,9 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN ...@@ -77,6 +82,9 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
...@@ -84,6 +92,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l ...@@ -84,6 +92,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
...@@ -184,8 +193,6 @@ github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTX ...@@ -184,8 +193,6 @@ github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTX
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
gitlab.wanzhuangkj.com/tush/xpkg v1.2.30 h1:nHS6M23/cUxFMdAX5hEoSTDYtBQIps/I36WI9x5r4uM=
gitlab.wanzhuangkj.com/tush/xpkg v1.2.30/go.mod h1:Pg1aL6bPUwYIxzmcxvFR6fUmI2UGPo2rjqpPBQMbHBY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib v1.38.0 h1:msaHYZ13HfLIbqXsGwZZQBg5zgxwumlZ1mCkXn3E7LM= go.opentelemetry.io/contrib v1.38.0 h1:msaHYZ13HfLIbqXsGwZZQBg5zgxwumlZ1mCkXn3E7LM=
...@@ -246,6 +253,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w ...@@ -246,6 +253,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
......
package cd
import (
"database/sql/driver"
"encoding/json"
"encoding/xml"
"fmt"
"unicode/utf8"
)
type IDCard string
func NewIDCard(v string) IDCard {
return IDCard(v)
}
func (id IDCard) String() string {
return string(id)
}
// Mask 身份证号遮蔽处理(保留格式中的X)
func (id IDCard) Mask() string {
s := string(id)
length := utf8.RuneCountInString(s)
switch {
case length == 18:
return s[:6] + "********" + s[14:]
case length == 15:
return s[:6] + "******" + s[12:]
default:
return s
}
}
// MarshalJSON 序列化时自动遮蔽敏感信息
func (id IDCard) MarshalJSON() ([]byte, error) {
if opts.idCardCSVShow {
return json.Marshal(id)
}
return json.Marshal(id.Mask())
}
// UnmarshalJSON 反序列化保持原始数据
func (id *IDCard) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
*id = IDCard(s)
return nil
}
// MarshalXML 序列化时自动遮蔽敏感信息
func (id IDCard) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if opts.idCardXMLShow {
return e.EncodeElement(id, start)
}
return e.EncodeElement(id.Mask(), start)
}
// UnmarshalXML 反序列化保持原始数据
func (id *IDCard) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var s string
if err := d.DecodeElement(&s, &start); err != nil {
return err
}
*id = IDCard(s)
return nil
}
// MarshalCSV 序列化时自动遮蔽敏感信息
func (id IDCard) MarshalCSV() (string, error) {
if opts.idCardCSVShow {
return string(id), nil
}
return id.Mask(), nil
}
// UnmarshalCSV 反序列化保持原始数据
func (id *IDCard) UnmarshalCSV(csv string) error {
*id = IDCard(csv)
return nil
}
// Scan 数据库读取接口
func (id *IDCard) Scan(value interface{}) error {
if value == nil {
*id = ""
return nil
}
switch v := value.(type) {
case []byte:
*id = IDCard(v)
case string:
*id = IDCard(v)
default:
return fmt.Errorf("无法扫描非string/[]byte类型的值到IDCard")
}
return nil
}
// Value 数据库写入接口
func (id IDCard) Value() (driver.Value, error) {
return string(id), nil
}
package cd
var opts = defaultOptions()
type options struct {
mobileJSONShow bool
mobileXMLShow bool
mobileCSVShow bool
passwordJSONShow bool
passwordXMLShow bool
passwordCSVShow bool
idCardJSONShow bool
idCardXMLShow bool
idCardCSVShow bool
}
type Option func(*options)
func Init(options ...Option) {
o := defaultOptions()
o.apply(options...)
opts = o
}
func defaultOptions() *options {
return &options{
mobileJSONShow: false,
mobileXMLShow: false,
mobileCSVShow: false,
passwordJSONShow: false,
passwordXMLShow: false,
passwordCSVShow: false,
idCardJSONShow: false,
idCardXMLShow: false,
idCardCSVShow: false,
}
}
func (o *options) apply(options ...Option) {
for _, opt := range options {
opt(o)
}
}
func WithMobileJSONShow(show bool) Option {
return func(o *options) {
o.mobileJSONShow = show
}
}
func WithMobileXMLShow(show bool) Option {
return func(o *options) {
o.mobileXMLShow = show
}
}
func WithMobileCSVShow(show bool) Option {
return func(o *options) {
o.mobileCSVShow = show
}
}
func WithPasswordJSONShow(show bool) Option {
return func(o *options) {
o.mobileJSONShow = show
}
}
func WithPasswordXMLShow(show bool) Option {
return func(o *options) {
o.mobileXMLShow = show
}
}
func WithPasswordCSVShow(show bool) Option {
return func(o *options) {
o.mobileCSVShow = show
}
}
func WithIDCardJSONShow(show bool) Option {
return func(o *options) {
o.mobileJSONShow = show
}
}
func WithIDCardXMLShow(show bool) Option {
return func(o *options) {
o.mobileXMLShow = show
}
}
func WithIDCardCSVShow(show bool) Option {
return func(o *options) {
o.mobileCSVShow = show
}
}
package cd_test
import (
"encoding/json"
"fmt"
"testing"
"gitlab.wanzhuangkj.com/tush/opkg/pkg/cd"
)
type Dog struct {
Mobile *cd.Mobile `json:"mobile"`
}
func TestWithMobileCSVShow(t *testing.T) {
mobile := cd.NewMobile("15068150081")
dog := Dog{
Mobile: &mobile,
}
cd.Init(cd.WithMobileJSONShow(true))
v, _ := json.Marshal(dog)
fmt.Println(string(v))
cd.Init(cd.WithMobileJSONShow(false))
v, _ = json.Marshal(dog)
fmt.Println(string(v))
}
package cd
import (
"database/sql/driver"
"encoding/xml"
"fmt"
"strings"
"unicode"
)
type Mobile string
func NewMobile(v string) Mobile {
return Mobile(v)
}
func (id Mobile) String() string {
return string(id)
}
func (d *Mobile) MarshalCSV() (string, error) {
if d == nil {
return "", nil
}
if opts.mobileCSVShow {
return string(*d), nil
}
return MaskPhone(string(*d)), nil
}
func (d *Mobile) UnmarshalCSV(csv string) error {
*d = Mobile(csv)
return nil
}
// MarshalJSON 实现JSON序列化
func (d Mobile) MarshalJSON() ([]byte, error) {
if d == "" {
return []byte(`""`), nil
}
if opts.mobileJSONShow {
return []byte(`"` + string(d) + `"`), nil
}
return []byte(`"` + MaskPhone(string(d)) + `"`), nil
}
func (d *Mobile) UnmarshalJSON(data []byte) error {
if string(data) == `null` {
*d = ""
return nil
}
s := strings.Trim(string(data), `"`)
*d = Mobile(s)
return nil
}
// MarshalXML 实现XML序列化
func (d *Mobile) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if d == nil {
return nil
}
if opts.mobileXMLShow {
return e.EncodeElement(string(*d), start)
}
return e.EncodeElement(MaskPhone(string(*d)), start)
}
// UnmarshalXML 实现XML反序列化
func (d *Mobile) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
var s string
if err := dec.DecodeElement(&s, &start); err != nil {
return err
}
*d = Mobile(s)
return nil
}
// MaskPhone 智能识别手机号格式并脱敏
func MaskPhone(phone string) string {
// 提取纯数字
digits := strings.Map(func(r rune) rune {
if unicode.IsDigit(r) {
return r
}
return -1
}, phone)
switch {
case len(digits) == 8: // 本地8位号码
return digits[:2] + strings.Repeat("*", 4) + digits[6:]
case len(digits) == 11: // 标准11位手机
return digits[:3] + strings.Repeat("*", 4) + digits[7:]
case len(digits) == 12: // 带区号的12位
return digits[:4] + strings.Repeat("*", 4) + digits[8:]
default:
return phone // 其他格式原样返回
}
}
// Scan 数据库读取接口
func (id *Mobile) Scan(value interface{}) error {
if value == nil {
*id = ""
return nil
}
switch v := value.(type) {
case []byte:
*id = Mobile(v)
case string:
*id = Mobile(v)
default:
return fmt.Errorf("无法扫描非string/[]byte类型的值到Mobile")
}
return nil
}
// Value 数据库写入接口
func (id Mobile) Value() (driver.Value, error) {
return string(id), nil
}
package cd
import (
"database/sql/driver"
"encoding/xml"
"fmt"
"strings"
"golang.org/x/crypto/bcrypt"
)
type Password string
func NewPassword(v string) Password {
return Password(v)
}
func (id Password) String() string {
return string(id)
}
func (d Password) MarshalCSV() (string, error) {
if d == "" {
if opts.passwordCSVShow {
return "", nil
}
return "******", nil
}
if opts.passwordCSVShow {
return string(d), nil
}
return "******", nil
}
func (d *Password) UnmarshalCSV(csv string) error {
*d = Password(csv)
return nil
}
// MarshalJSON 实现JSON序列化
func (d Password) MarshalJSON() ([]byte, error) {
if d == "" {
return []byte(`""`), nil
}
if opts.passwordJSONShow {
return []byte(string(d)), nil
}
return []byte(`"******"`), nil
}
// UnmarshalJSON 实现JSON反序列化
func (d *Password) UnmarshalJSON(data []byte) error {
if string(data) == `null` {
*d = ""
return nil
}
s := strings.Trim(string(data), `"`)
*d = Password(s)
return nil
}
// MarshalXML 实现XML序列化
func (d Password) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if d == "" {
return nil
}
if opts.passwordXMLShow {
return e.EncodeElement(string(d), start)
}
return e.EncodeElement("******", start)
}
// UnmarshalXML 实现XML反序列化
func (d *Password) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
var s string
if err := dec.DecodeElement(&s, &start); err != nil {
return err
}
*d = Password(s)
return nil
}
// Scan 数据库读取接口
func (id *Password) Scan(value interface{}) error {
if value == nil {
*id = ""
return nil
}
switch v := value.(type) {
case []byte:
*id = Password(v)
case string:
*id = Password(v)
default:
return fmt.Errorf("无法扫描非string/[]byte类型的值到Password")
}
return nil
}
// Value 数据库写入接口
func (id Password) Value() (driver.Value, error) {
return string(id), nil
}
var PasswordUtil = Password("")
// 生成密码的哈希值
func (id *Password) Hash(password string) (string, error) {
// bcrypt.GenerateFromPassword 会自动生成随机盐,并包含在最终的哈希值中
// bcrypt.DefaultCost 是计算成本因子,值越大越安全,但计算时间也越长
hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hashedBytes), nil
}
// 验证密码是否正确
func (id *Password) IsSame(password, hashedPassword string) bool {
// bcrypt.CompareHashAndPassword 会从hashedPassword中解析出盐和成本因子,
// 然后对输入的password进行相同的计算,最后比较结果
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
return err == nil
}
// func main() {
// password := "mySecretPassword123"
// // 用户注册时,哈希密码并存储
// hashed, err := HashPassword(password)
// if err != nil {
// panic(err)
// }
// fmt.Println("Hashed Password to store:", hashed)
// // 用户登录时,验证密码
// isCorrect := CheckPasswordHash(password, hashed)
// fmt.Println("Password is correct:", isCorrect) // 输出: true
// isWrong := CheckPasswordHash("wrongPassword", hashed)
// fmt.Println("Wrong password is correct:", isWrong) // 输出: false
// }
package cd_test
import (
"fmt"
"testing"
"gitlab.wanzhuangkj.com/tush/opkg/pkg/cd"
)
func TestPassword_Hash(t *testing.T) {
password := "mySecretPassword123"
// 用户注册时,哈希密码并存储
hashed, err := cd.PasswordUtil.Hash(password)
if err != nil {
panic(err)
}
fmt.Println("Hashed Password to store:", hashed)
// 用户登录时,验证密码
isCorrect := cd.PasswordUtil.IsSame(password, hashed)
fmt.Println("Password is correct:", isCorrect) // 输出: true
isWrong := cd.PasswordUtil.IsSame("wrongPassword", hashed)
fmt.Println("Wrong password is correct:", isWrong) // 输出: false
}
...@@ -8,6 +8,10 @@ import ( ...@@ -8,6 +8,10 @@ import (
"gitlab.wanzhuangkj.com/tush/opkg/pkg/xerrors/xerror" "gitlab.wanzhuangkj.com/tush/opkg/pkg/xerrors/xerror"
) )
type Key interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 | ~string
}
var ( var (
node *snowflake.Node node *snowflake.Node
) )
......
...@@ -9,7 +9,7 @@ Circuit Breaker for web middleware and rpc interceptor. ...@@ -9,7 +9,7 @@ Circuit Breaker for web middleware and rpc interceptor.
**gin circuit breaker middleware** **gin circuit breaker middleware**
```go ```go
import "gitlab.wanzhuangkj.com/tush/xpkg/pkg/shield/circuitbreaker" import "gitlab.wanzhuangkj.com/tush/opkg/pkg/shield/circuitbreaker"
// CircuitBreaker a circuit breaker middleware // CircuitBreaker a circuit breaker middleware
func CircuitBreaker(opts ...CircuitBreakerOption) gin.HandlerFunc { func CircuitBreaker(opts ...CircuitBreakerOption) gin.HandlerFunc {
...@@ -45,7 +45,7 @@ func CircuitBreaker(opts ...CircuitBreakerOption) gin.HandlerFunc { ...@@ -45,7 +45,7 @@ func CircuitBreaker(opts ...CircuitBreakerOption) gin.HandlerFunc {
**rpc server circuit breaker interceptor** **rpc server circuit breaker interceptor**
```go ```go
import "gitlab.wanzhuangkj.com/tush/xpkg/pkg/shield/circuitbreaker" import "gitlab.wanzhuangkj.com/tush/opkg/pkg/shield/circuitbreaker"
// UnaryServerCircuitBreaker server-side unary circuit breaker interceptor // UnaryServerCircuitBreaker server-side unary circuit breaker interceptor
func UnaryServerCircuitBreaker(opts ...CircuitBreakerOption) grpc.UnaryServerInterceptor { func UnaryServerCircuitBreaker(opts ...CircuitBreakerOption) grpc.UnaryServerInterceptor {
......
...@@ -3,7 +3,7 @@ package circuitbreaker_test ...@@ -3,7 +3,7 @@ package circuitbreaker_test
import ( import (
"testing" "testing"
"gitlab.wanzhuangkj.com/tush/xpkg/pkg/shield/circuitbreaker" "gitlab.wanzhuangkj.com/tush/opkg/pkg/shield/circuitbreaker"
) )
// This is an example of using a circuit breaker Do() when return nil. // This is an example of using a circuit breaker Do() when return nil.
......
...@@ -7,8 +7,8 @@ import ( ...@@ -7,8 +7,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"gitlab.wanzhuangkj.com/tush/xpkg/pkg/shield/cpu" "gitlab.wanzhuangkj.com/tush/opkg/pkg/shield/cpu"
"gitlab.wanzhuangkj.com/tush/xpkg/pkg/shield/window" "gitlab.wanzhuangkj.com/tush/opkg/pkg/shield/window"
) )
var ( var (
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gitlab.wanzhuangkj.com/tush/xpkg/pkg/shield/window" "gitlab.wanzhuangkj.com/tush/opkg/pkg/shield/window"
) )
var ( var (
......
package xset package xset
type Key interface { import "gitlab.wanzhuangkj.com/tush/opkg/pkg/sf"
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 | ~string
}
type Set[T Key] struct { type Set[T sf.Key] struct {
m map[any]bool m map[any]bool
} }
func NewSet[T Key]() *Set[T] { func NewSet[T sf.Key]() *Set[T] {
return &Set[T]{m: make(map[any]bool)} return &Set[T]{m: make(map[any]bool)}
} }
......
package sliceutils
import (
"fmt"
"strings"
"gitlab.wanzhuangkj.com/tush/opkg/pkg/errcode"
"gitlab.wanzhuangkj.com/tush/opkg/pkg/sf"
"gitlab.wanzhuangkj.com/tush/opkg/pkg/xset"
"github.com/jinzhu/copier"
"github.com/spf13/cast"
"gitlab.wanzhuangkj.com/tush/opkg/pkg/xerrors/xerror"
)
// connector 连接符
func Join[T any](rs []T, connector string) string {
if len(rs) == 0 {
return ""
}
strs := make([]string, 0, len(rs))
for _, r := range rs {
v := cast.ToString(r) // use cast
strs = append(strs, v)
}
return strings.Join(strs, connector)
}
func Contains[T comparable](rs []T, r T) bool {
for _, v := range rs {
if v == r {
return true
}
}
return false
}
func NotContains[T comparable](rs []T, r T) bool {
return !Contains(rs, r)
}
func StrToUint64(rs []string) []uint64 {
if len(rs) == 0 {
return nil
}
var IDs []uint64
for _, r := range rs {
IDs = append(IDs, cast.ToUint64(r))
}
return IDs
}
type IID[ID sf.Key] interface {
GetID() ID
}
type IIDTable[ID sf.Key] interface {
GetID() ID
TableName() string
}
type ITable interface {
TableName() string
}
func GetIDs[ID sf.Key, T IID[ID]](rs []*T) []ID {
if len(rs) == 0 {
return nil
}
set := xset.NewSet[ID]()
for _, r := range rs {
set.Add((*r).GetID())
}
return set.Slice()
}
func SliceToIDMap[ID sf.Key, T IID[ID]](rs []*T) map[ID]*T {
m := make(map[ID]*T)
for _, r := range rs {
m[(*r).GetID()] = r
}
return m
}
func MapToSlice[T comparable, FromT, ToT any](m map[T]*FromT) []*ToT {
if len(m) == 0 {
return nil
}
ret := make([]*ToT, len(m))
for _, r := range m {
ret = append(ret, TypeToType[FromT, ToT](r))
}
return ret
}
func MapToMap[T comparable, FromT, ToT any](m map[T]*FromT) map[T]*ToT {
if len(m) == 0 {
return nil
}
ret := make(map[T]*ToT, len(m))
for k, r := range m {
ret[k] = TypeToType[FromT, ToT](r)
}
return ret
}
func TypeToType[FromT, ToT any](r *FromT) *ToT {
if r == nil {
return nil
}
var ret ToT
copier.Copy(&ret, r)
return &ret
}
func SliceToSlice[FromT, ToT any](rs []*FromT) []*ToT {
if len(rs) == 0 {
return nil
}
ret := make([]*ToT, 0, len(rs))
for _, r := range rs {
if r == nil {
continue
}
ret = append(ret, TypeToType[FromT, ToT](r))
}
return ret
}
func MapSliceToMapSlice[T comparable, FromT, ToT any](m map[T][]*FromT) map[T][]*ToT {
if len(m) == 0 {
return nil
}
ret := make(map[T][]*ToT, len(m))
for k, rs := range m {
ret[k] = SliceToSlice[FromT, ToT](rs)
}
return ret
}
func MapSliceToSlice[T comparable, FromT, ToT any](m map[T][]*FromT) []*ToT {
if len(m) == 0 {
return nil
}
ret := make([]*ToT, 0)
for _, rs := range m {
ret = append(ret, SliceToSlice[FromT, ToT](rs)...)
}
return ret
}
// SetDifference 计算两个切片的差集 A - B
func SetDifference[T comparable](A, B []T) []T {
result := []T{}
setB := make(map[T]struct{})
for _, elem := range B {
setB[elem] = struct{}{}
}
for _, elem := range A {
if _, found := setB[elem]; !found {
result = append(result, elem)
}
}
return result
}
func StrMapToSlice[T any](m map[string]*T) []*T {
var rs []*T
for _, r := range m {
rs = append(rs, r)
}
return rs
}
func GetStrMapIDs[ID sf.Key, T IID[ID]](m map[string]*T) []ID {
st := xset.NewSet[ID]()
for _, v := range m {
st.Add((*v).GetID())
}
return st.Slice()
}
func IDMapToSlice[ID sf.Key, T any](m map[ID]*T) []*T {
var rs []*T
for _, r := range m {
rs = append(rs, r)
}
return rs
}
func GetIDMapIDs[ID sf.Key, T IID[ID]](m map[ID]*T) []ID {
st := xset.NewSet[ID]()
for _, v := range m {
st.Add((*v).GetID())
}
return st.Slice()
}
func StrMapSliceToSlice[T any](m map[string][]*T) []*T {
var rs []*T
for _, r := range m {
rs = append(rs, r...)
}
return rs
}
func GetStrMapSliceIDs[ID sf.Key, T IID[ID]](m map[string][]*T) []ID {
st := xset.NewSet[ID]()
for _, rs := range m {
for _, r := range rs {
st.Add((*r).GetID())
}
}
return st.Slice()
}
func IDMapSliceToSlice[ID sf.Key, T any](m map[ID][]*T) []*T {
var rs []*T
for _, r := range m {
rs = append(rs, r...)
}
return rs
}
func GetIDMapSliceIDs[ID sf.Key, T IID[ID]](m map[ID][]*T) []ID {
st := xset.NewSet[ID]()
for _, rs := range m {
for _, r := range rs {
st.Add((*r).GetID())
}
}
return st.Slice()
}
type ICode interface {
Code() int
}
func CompareSlice[ID sf.Key, T IIDTable[ID], BizSlice ~[]*T](ids []ID, bizSlice BizSlice, errCode error) error {
if len(ids) == 0 {
return nil
}
if len(bizSlice) < len(ids) {
if len(bizSlice) == 0 {
if v, ok := errCode.(*errcode.Error); ok {
return xerror.NewC(v.Code(), v.Msg())
}
return xerror.New(errCode.Error())
}
deltaIDs := SetDifference(ids, GetIDs[ID](bizSlice))
if len(deltaIDs) > 0 {
if v, ok := errCode.(*errcode.Error); ok {
return xerror.NewC(v.Code(), fmt.Sprintf("%s[ids:%s]", v.Msg(), Join(deltaIDs, ",")))
}
return xerror.New(errCode.Error())
}
}
return nil
}
func ArrayUnique[T comparable](array []T) []T {
mp := make(map[T]struct{})
idx := 0
for _, value := range array {
if _, ok := mp[value]; ok {
continue
}
array[idx] = value
idx = idx + 1
mp[value] = struct{}{}
}
return array[:idx]
}
//
//type IId[id sf.Key] interface {
// GetID() id
//}
//
//func GetIds[id sf.Key, T IId[id]](rs []*T) []id {
// if len(rs) == 0 {
// return nil
// }
// set := xset.NewSet[id]()
// for _, r := range rs {
// set.Add((*r).GetID())
// }
// return set.Slice()
//}
//
//func SliceToIdMap[id sf.Key, T IId[id]](rs []*T) map[id]*T {
// m := make(map[id]*T)
// for _, r := range rs {
// m[(*r).GetID()] = r
// }
// return m
//}
func ChunkSlice[T any](slice []T, chunkSize int) [][]T {
var chunks [][]T
for i := 0; i < len(slice); i += chunkSize {
end := i + chunkSize
if end > len(slice) {
end = len(slice)
}
chunks = append(chunks, slice[i:end])
}
return chunks
}
type IString interface {
String() string
}
func JoinStrs[T IString](rs []T, connector string) string {
if len(rs) == 0 {
return ""
}
strs := make([]string, 0, len(rs))
for _, r := range rs {
strs = append(strs, r.String())
}
return strings.Join(strs, connector)
}
func AllNotEmpty(rs ...string) bool {
if len(rs) == 0 {
return false
}
ret := true
for _, r := range rs {
if strings.TrimSpace(r) == "" {
ret = false
}
}
return ret
}
func AllEmpty(rs ...string) bool {
if len(rs) == 0 {
return false
}
ret := true
for _, r := range rs {
if strings.TrimSpace(r) != "" {
ret = false
}
}
return ret
}
func AnyEmpty(rs ...string) bool {
if len(rs) == 0 {
return false
}
for _, r := range rs {
if strings.TrimSpace(r) == "" {
return true
}
}
return false
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论