feat: v2.0

This commit is contained in:
czx-lab
2025-02-13 18:09:23 +08:00
commit 016bb84646
36 changed files with 2193 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
.idea
/storage/logs/*
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Sichuan Chuzhixi Technology Co., Ltd. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+42
View File
@@ -0,0 +1,42 @@
# the program fails to load the WakeByAddressSingle, WakeByAddressAll and WaitOnAddress symbols from kernel32.dll.
# View Details: https://github.com/golang/go/issues/61058
BINARY_NAME=main
PLATFORM=Windows
ifeq ($(OS), Windows_NT)
PLATFORM=window
BINARY_NAME=main.exe
else
ifeq ($(shell uname), Darwin)
PLATFORM=mac
else
PLATFORM=linux
endif
endif
all: ${PLATFORM} run
window:
set CGO_ENABLED=0
set GOOS=windows
set GOARCH=amd64
go build -race -o ${BINARY_NAME} -ldflags "-s -w" cmd/main.go
mac:
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -race -o ${BINARY_NAME} -ldflags '-s -w' cmd/main.go
linux:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -race -o ${BINARY_NAME} -ldflags '-s -w' cmd/main.go
run:
./${BINARY_NAME} server:http -m release
debug:
go run ./cmd/main.go
gorm:
go run ./cmd/main.go gorm:gen -c model
clean:
go clean
rm ${BINARY_NAME}
+1
View File
@@ -0,0 +1 @@
#### v2.0
+60
View File
@@ -0,0 +1,60 @@
package app
import (
"czx/app/cron"
"czx/app/event/listen"
"czx/app/router"
"czx/app/svc"
"czx/internal/constants"
"czx/internal/event"
"czx/internal/server/xhttp"
"czx/internal/xcron"
"fmt"
"log"
)
type Bootup struct {
server xhttp.IServer
svcCtx *svc.AppContext
}
func New(path string) constants.IService {
bootup := &Bootup{}
ctx := svc.NewAppContext(path)
bootup.server = xhttp.New(ctx.Config.HttpConf).RegisterHandlers(router.New(ctx))
bootup.svcCtx = ctx
return bootup
}
// Start implements constants.IService.
func (b *Bootup) Start() error {
b.service()
fmt.Printf("Starting server at %s...\n", b.svcCtx.Config.HttpConf.Addr)
if err := b.server.Start(); err != nil {
log.Fatalf("error: app bootup %s", err.Error())
return err
}
return nil
}
func (b *Bootup) service() {
// events
events := []event.IListen{new(listen.Foo)}
if err := b.svcCtx.Event.Register(events...); err != nil {
log.Fatalf("error: app event register %s", err.Error())
return
}
// crons
tasks := []xcron.ICron{new(cron.FooTask)}
xcron.New().AddFunc(tasks...)
// mq consumers
// TODO::
}
var _ constants.IService = (*Bootup)(nil)
+19
View File
@@ -0,0 +1,19 @@
package config
import (
"czx/internal/queue/rocket"
"czx/internal/server/xhttp"
"czx/internal/stores/mongo"
"czx/internal/stores/xmysql"
"czx/internal/stores/xredis"
"czx/internal/xlog"
)
type Config struct {
HttpConf xhttp.HttpConf
MysqlConf xmysql.MySqlConf
MongoConf mongo.MonConf
RedisConf xredis.RedisConf
LogConf xlog.LogConf
RocketMqConf rocket.RocketConf
}
+21
View File
@@ -0,0 +1,21 @@
package cron
import (
"fmt"
"czx/internal/xcron"
)
type FooTask struct {
}
var _ xcron.ICron = (*FooTask)(nil)
func (d *FooTask) Rule() string {
return "* * * * *"
}
func (d *FooTask) Execute() func() {
return func() {
fmt.Println("demo-task exec...")
}
}
+11
View File
@@ -0,0 +1,11 @@
package entity
import "fmt"
type Foo struct {
Name string
}
func (f *Foo) GetData() any {
return fmt.Sprintf("FooEvent.Name = %s --> %s", f.Name, "exec FooEvent.GetData")
}
+22
View File
@@ -0,0 +1,22 @@
package listen
import (
"fmt"
"czx/app/event/entity"
"czx/internal/event"
)
type Foo struct {
}
var _ event.IListen = (*Foo)(nil)
func (*Foo) Listen() []event.IEvent {
return []event.IEvent{
&entity.Foo{},
}
}
func (*Foo) Process(data any) {
fmt.Printf("%v --> %s \n", data, "exec FooListen.Process")
}
+22
View File
@@ -0,0 +1,22 @@
package logic
import (
"net/http"
"czx/app/svc"
"github.com/gin-gonic/gin"
)
type Index struct {
svcCtx *svc.AppContext
}
func NewIndex(ctx *svc.AppContext) *Index {
return &Index{
svcCtx: ctx,
}
}
func (i *Index) Demo(ctx *gin.Context) {
ctx.String(http.StatusOK, "hello word!")
}
+29
View File
@@ -0,0 +1,29 @@
package router
import (
"net/http"
"czx/app/logic"
"czx/app/svc"
"czx/internal/server/router"
"github.com/gin-gonic/gin"
)
type ApiRouter struct {
ctx *svc.AppContext
}
var _ router.IRouter = (*ApiRouter)(nil)
func New(ctx *svc.AppContext) *ApiRouter {
return &ApiRouter{ctx}
}
func (a *ApiRouter) Add(server *gin.Engine) {
server.GET("/", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "hello word!")
})
index := logic.NewIndex(a.ctx)
server.GET("/demo", index.Demo)
}
+46
View File
@@ -0,0 +1,46 @@
package svc
import (
"czx/app/config"
"czx/internal/conf"
"czx/internal/event"
"czx/internal/queue/rocket"
"czx/internal/stores/mongo"
"czx/internal/stores/xmysql"
"czx/internal/stores/xredis"
"czx/internal/xlog"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
"gorm.io/gorm"
)
type AppContext struct {
Config config.Config
DB *gorm.DB
MDB *mongo.Mon
RDB redis.UniversalClient
Log *zap.Logger
Event *event.Event
Rocket *rocket.Rocket
}
func NewAppContext(path string) (ctx *AppContext) {
var c config.Config
conf.New(path).Load(&c)
return &AppContext{
Config: c,
DB: xmysql.NewMysql(c.MysqlConf).DB(),
RDB: xredis.New(c.RedisConf).DB(),
MDB: mongo.New(c.MongoConf),
Log: xlog.New(c.LogConf).Logger(),
Event: event.New(),
Rocket: rocket.New(c.RocketMqConf),
}
}
+14
View File
@@ -0,0 +1,14 @@
package main
import (
"czx/app"
"flag"
)
var configFile = flag.String("f", "config/config.yaml", "the config file")
func main() {
flag.Parse()
_ = app.New(*configFile).Start()
}
+26
View File
@@ -0,0 +1,26 @@
HttpConf:
Mode: debug
Addr: :1889
TemplDir: templates
Timeout: 5000
MySqlConf:
Write: root:root@tcp(127.0.0.1:3006)/test?charset=utf8mb4&loc=Local&parseTime=True
Read:
- root:root@tcp(127.0.0.1:3006)/test?charset=utf8mb4&loc=Local&parseTime=True
MaxIdleConn: 2
MaxOpenConn: 2
ConnMaxLifetime: 12
ConnMaxIdleTime: 3
RedisConf:
Pass: xxxxx
Addrs:
- 127.0.0.1:6379
DB: 10
Pool:
Size: 10
ConnMaxIdle: 10
ConnMinIdle:
MaxLifeTime:
MaxIdleTime:
+90
View File
@@ -0,0 +1,90 @@
module czx
go 1.23.4
require (
github.com/gin-gonic/gin v1.10.0
github.com/redis/go-redis/v9 v9.7.0
)
require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/golang/mock v1.3.1 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.4.0 // indirect
github.com/tidwall/gjson v1.13.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/term v0.23.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
stathat.com/c/consistent v1.0.0 // indirect
)
require (
github.com/apache/rocketmq-client-go/v2 v2.1.2
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/fsnotify/fsnotify v1.7.0
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.20.0
github.com/goccy/go-json v0.10.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/robfig/cron/v3 v3.0.1
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.mongodb.org/mongo-driver v1.17.2
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.27.0
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/mysql v1.5.7
gorm.io/gorm v1.25.12
gorm.io/plugin/dbresolver v1.5.3
)
+335
View File
@@ -0,0 +1,335 @@
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/apache/rocketmq-client-go/v2 v2.1.2 h1:yt73olKe5N6894Dbm+ojRf/JPiP0cxfDNNffKwhpJVg=
github.com/apache/rocketmq-client-go/v2 v2.1.2/go.mod h1:6I6vgxHR3hzrvn+6n/4mrhS+UTulzK/X9LB2Vk1U5gE=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.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.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sirupsen/logrus v1.4.0 h1:yKenngtzGh+cUSSh6GWbxW2abRqhYUSR/t/6+2QqNvE=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M=
github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20211216021012-1d35b9e2eb4e/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
gorm.io/plugin/dbresolver v1.5.3 h1:wFwINGZZmttuu9h7XpvbDHd8Lf9bb8GNzp/NpAMV2wU=
gorm.io/plugin/dbresolver v1.5.3/go.mod h1:TSrVhaUg2DZAWP3PrHlDlITEJmNOkL0tFTjvTEsQ4XE=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
+112
View File
@@ -0,0 +1,112 @@
package conf
import (
"log"
"czx/internal/constants"
"czx/internal/stores/memo"
"sync"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
type Config struct {
mu *sync.Mutex
viper *viper.Viper
cache constants.ICache
prefix string
}
var changeTime time.Time
func init() {
changeTime = time.Now()
}
func New(path string) *Config {
instance, err := viperInstance(path)
if err != nil {
log.Fatalf("error: config file %s, %s", path, err.Error())
return nil
}
conf := &Config{
viper: instance,
mu: new(sync.Mutex),
}
defaultConf(conf)
conf.listen(instance)
return conf
}
func (c *Config) Load(v any) {
if err := c.viper.Unmarshal(&v); err != nil {
log.Fatalf("error: config load %s", err.Error())
}
}
func (c *Config) Cache(key string, value any) (bool, error) {
c.mu.Lock()
defer c.mu.Unlock()
ok, err := c.cache.Has(key)
if err != nil {
return false, err
}
if ok {
return true, nil
}
return c.cache.Set(key, value)
}
func (c *Config) Get(key string) (any, error) {
ok, err := c.cache.Has(key)
if err != nil {
return nil, err
}
if ok {
return c.cache.Get(key)
}
val := c.viper.Get(key)
c.Cache(key, val)
return val, nil
}
func (c *Config) listen(instance *viper.Viper) {
instance.OnConfigChange(func(in fsnotify.Event) {
if time.Since(changeTime).Seconds() >= 1 {
if in.Op != fsnotify.Write {
return
}
c.delCache(c.prefix)
changeTime = time.Now()
}
})
}
func (c *Config) delCache(prefix string) {
method, ok := c.cache.(memo.IMemo)
if !ok {
return
}
method.FuzzyDel(prefix)
}
func defaultConf(c *Config) {
if c.cache == nil {
c.cache = memo.New()
}
if len(c.prefix) == 0 {
c.prefix = "xconf"
}
}
func viperInstance(path string) (instance *viper.Viper, err error) {
instance = viper.New()
instance.SetConfigFile(path)
if err = instance.ReadInConfig(); err != nil {
return
}
return
}
+7
View File
@@ -0,0 +1,7 @@
package constants
type ICache interface {
Get(key string) (any, error)
Set(key string, value any) (bool, error)
Has(key string) (bool, error)
}
+5
View File
@@ -0,0 +1,5 @@
package constants
type IService interface {
Start() error
}
+102
View File
@@ -0,0 +1,102 @@
package event
import (
"errors"
"log"
"reflect"
"sync"
)
type IEvent interface {
GetData() any
}
type IListen interface {
Listen() []IEvent
Process(param any)
}
var smap sync.Map
type Event struct {
wg *sync.WaitGroup
}
func New(listens ...IListen) *Event {
evt := &Event{
wg: new(sync.WaitGroup),
}
if len(listens) == 0 {
return evt
}
if err := evt.Register(listens...); err != nil {
log.Fatalf("event register: %s", err)
}
return evt
}
func (e *Event) Register(listens ...IListen) error {
for _, listen := range listens {
events := listen.Listen()
if len(events) == 0 {
return errors.New("listening events cannot be empty")
}
for _, event := range events {
e.on(event, listen)
}
}
return nil
}
func (e *Event) on(event IEvent, listen IListen) {
name := reflect.TypeOf(event).String()
evts, ok := smap.Load(name)
var handlers []IListen
if ok {
handlers = evts.([]IListen)
}
if len(handlers) == 0 {
smap.Store(name, []IListen{listen})
return
}
handlers = append(handlers, listen)
smap.Store(name, handlers)
}
func (e *Event) Dispatch(event IEvent) error {
name := reflect.TypeOf(event).String()
handlers, ok := smap.Load(name)
if !ok {
return errors.New("event not registered")
}
return e.exec(handlers.([]IListen), event, false)
}
func (e *Event) DispatchAsync(event IEvent) error {
name := reflect.TypeOf(event).String()
handlers, ok := smap.Load(name)
if !ok {
return errors.New("event not registered")
}
return e.exec(handlers.([]IListen), event, true)
}
func (e *Event) exec(handlers []IListen, event IEvent, async bool) error {
param := event.GetData()
if !async {
for _, handler := range handlers {
handler.Process(param)
}
return nil
}
for _, handler := range handlers {
e.wg.Add(1)
execFunc := handler
go func() {
defer e.wg.Done()
execFunc.Process(param)
}()
}
e.wg.Wait()
return nil
}
+78
View File
@@ -0,0 +1,78 @@
package rocket
import (
"errors"
"log"
"github.com/apache/rocketmq-client-go/v2"
"github.com/apache/rocketmq-client-go/v2/consumer"
"github.com/apache/rocketmq-client-go/v2/producer"
)
var (
NilProducerMsgErr = errors.New("producer message is empty")
)
type RocketConf struct {
Servers []string
GroupName string
Retry int
}
type Rocket struct {
conf RocketConf
p rocketmq.Producer
c rocketmq.PushConsumer
}
func New(conf RocketConf) *Rocket {
return &Rocket{
conf: conf,
p: producerInstance(conf),
c: consumerInstance(conf),
}
}
func (r *Rocket) Producer() rocketmq.Producer {
if r.p == nil {
r.p = producerInstance(r.conf)
}
return r.p
}
func (r *Rocket) Consumer() rocketmq.PushConsumer {
if r.c == nil {
r.c = consumerInstance(r.conf)
}
return r.c
}
func consumerInstance(conf RocketConf) rocketmq.PushConsumer {
options := []consumer.Option{
consumer.WithNameServer(conf.Servers),
consumer.WithGroupName(conf.GroupName),
consumer.WithRetry(conf.Retry),
}
c, err := rocketmq.NewPushConsumer(options...)
if err != nil {
log.Fatalf("rocket consumer create error: %v", err.Error())
}
return c
}
func producerInstance(conf RocketConf) rocketmq.Producer {
options := []producer.Option{
producer.WithNameServer(conf.Servers),
producer.WithGroupName(conf.GroupName),
producer.WithRetry(conf.Retry),
}
p, err := rocketmq.NewProducer(options...)
if err != nil {
log.Fatalf("rocket producer create error: %v", err.Error())
}
if err := p.Start(); err != nil {
log.Fatalf("rocket producer start error: %v", err.Error())
}
return p
}
+21
View File
@@ -0,0 +1,21 @@
package router
import "github.com/gin-gonic/gin"
type IRouter interface {
Add(server *gin.Engine)
}
type Router struct {
server *gin.Engine
}
func New(server *gin.Engine) *Router {
return &Router{
server: server,
}
}
func (r *Router) AddRouter(routers IRouter) {
routers.Add(r.server)
}
+169
View File
@@ -0,0 +1,169 @@
package xhttp
import (
"errors"
"fmt"
"reflect"
"czx/internal/utils"
"strings"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
enTranslations "github.com/go-playground/validator/v10/translations/en"
chTranslations "github.com/go-playground/validator/v10/translations/zh"
)
const (
headerName = "Header"
bodyName = "Body"
uriName = "Uri"
)
type IValidator interface {
Message() validator.ValidationErrorsTranslations
}
type Request struct {
trans ut.Translator
}
func NewReq(local string) (*Request, error) {
req := &Request{}
trans, err := trans(local)
if err != nil {
return nil, err
}
req.trans = trans
return req, nil
}
func (r *Request) Validator(ctx *gin.Context, param any) validator.ValidationErrorsTranslations {
var err error
checkHeader := utils.CheckFieldExistence(param, headerName)
if !checkHeader {
goto CheckUriBlock
}
if err := r.ValiHeader(ctx, param); err != nil {
return err
}
CheckUriBlock:
checkUri := utils.CheckFieldExistence(param, uriName)
if !checkUri {
goto CheckBodyBlock
}
if err := r.ValiUri(ctx, param); err != nil {
return err
}
CheckBodyBlock:
field := bodyName
checkBody := utils.CheckFieldExistence(param, field)
if checkBody {
if err := r.ValiBody(ctx, param); err != nil {
return err
}
}
if !checkBody && !checkHeader && !checkUri {
field = ""
if err = ctx.ShouldBind(param); err == nil {
return nil
}
}
if err != nil {
return r.valiErr(field, param, err)
}
return nil
}
func (r *Request) ValiHeader(ctx *gin.Context, param any) validator.ValidationErrorsTranslations {
headerVal := reflectValue(param).FieldByName(headerName)
if headerVal.CanInterface() {
if err := ctx.ShouldBindHeader(headerVal.Addr().Interface()); err != nil {
return r.valiErr(headerName, param, err)
}
}
return nil
}
func (r *Request) ValiBody(ctx *gin.Context, param any) validator.ValidationErrorsTranslations {
bodyVal := reflectValue(param).FieldByName(bodyName)
if bodyVal.CanInterface() {
if err := ctx.ShouldBind(bodyVal.Addr().Interface()); err == nil {
return nil
}
}
return nil
}
func (r *Request) ValiUri(ctx *gin.Context, param any) validator.ValidationErrorsTranslations {
uriVal := reflectValue(param).FieldByName(uriName)
if uriVal.CanInterface() {
if err := ctx.ShouldBindUri(uriVal.Addr().Interface()); err != nil {
return r.valiErr(headerName, param, err)
}
}
return nil
}
func (r *Request) valiErr(field string, param any, err error) validator.ValidationErrorsTranslations {
var errs validator.ValidationErrors
messages := make(validator.ValidationErrorsTranslations)
if ok := errors.As(err, &errs); !ok {
messages["noValidationErrors"] = err.Error()
return messages
}
for _, fieldError := range err.(validator.ValidationErrors) {
stringBuilder := strings.Builder{}
if len(field) > 0 {
stringBuilder.WriteString(fmt.Sprintf("%s.", field))
}
stringBuilder.WriteString(fmt.Sprintf("%s.%s", fieldError.Field(), fieldError.Tag()))
d, ok := param.(IValidator)
if !ok {
messages[fieldError.Field()] = fieldError.Translate(r.trans)
continue
}
if message, exist := d.Message()[stringBuilder.String()]; exist {
messages[fieldError.Field()] = message
continue
}
messages[fieldError.Field()] = fieldError.Error()
}
return messages
}
func reflectValue(param any) reflect.Value {
value := reflect.ValueOf(param)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
return value
}
func trans(local string) (ut.Translator, error) {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
zhT := zh.New()
enT := en.New()
uni := ut.New(enT, zhT, enT)
trans, ok := uni.GetTranslator(local)
if !ok {
return nil, fmt.Errorf("uni.GetTranslator(%s) failed", local)
}
var err error
switch local {
case "zh":
err = chTranslations.RegisterDefaultTranslations(v, trans)
default:
err = enTranslations.RegisterDefaultTranslations(v, trans)
}
return trans, err
}
return nil, nil
}
+125
View File
@@ -0,0 +1,125 @@
package xhttp
import (
"context"
"czx/internal/constants"
"czx/internal/server/router"
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
)
type IServer interface {
constants.IService
Engine() *gin.Engine
RegisterHandlers(router.IRouter) IServer
}
type HttpConf struct {
Mode string
Addr string
TemplDir string
Timeout int64
}
type XHttp struct {
conf HttpConf
engine *gin.Engine
router *router.Router
}
func New(conf HttpConf) IServer {
defaultConf(&conf)
xhp := &XHttp{conf: conf}
xhp.router = router.New(xhp.Engine())
return xhp
}
// RegisterHandlers implements IServer.
func (x *XHttp) RegisterHandlers(routers router.IRouter) IServer {
x.router.AddRouter(routers)
return x
}
// Engine implements IServer.
func (x *XHttp) Engine() *gin.Engine {
if x.engine == nil {
switch x.conf.Mode {
case gin.ReleaseMode:
x.engine = release()
default:
x.engine = debug()
}
}
if len(x.conf.TemplDir) > 0 {
x.engine.LoadHTMLGlob(fmt.Sprintf("%s/*", x.conf.TemplDir))
}
return x.engine
}
// Start implements IService.
func (x *XHttp) Start() error {
srv := &http.Server{
Addr: x.conf.Addr,
Handler: x.engine,
WriteTimeout: time.Duration(x.conf.Timeout),
ReadTimeout: time.Duration(x.conf.Timeout),
}
errCh := make(chan error, 1)
go func() {
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
errCh <- err
}
}()
srvSignal(srv)
select {
case err := <-errCh:
return err
case <-time.After(30 * time.Second):
return errors.New("server start timeout")
}
}
func srvSignal(srv *http.Server) {
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("server shutdown error %s", err.Error())
}
log.Println("server exiting...")
}
func debug() *gin.Engine {
return gin.Default()
}
func release() *gin.Engine {
gin.SetMode(gin.ReleaseMode)
gin.DefaultWriter = io.Discard
return gin.New()
}
func defaultConf(conf *HttpConf) {
if conf.Timeout == 0 {
conf.Timeout = 3000
}
}
var _ IServer = (*XHttp)(nil)
+62
View File
@@ -0,0 +1,62 @@
package memo
import (
"czx/internal/constants"
"strings"
"sync"
)
var smap sync.Map
type IMemo interface {
FuzzyDel(string) error
}
type Memo struct {
}
func New() *Memo {
return &Memo{}
}
// Get implements constants.ICache.
func (m *Memo) Get(key string) (any, error) {
value, exist := smap.Load(key)
if exist {
return value, nil
}
return nil, nil
}
// Has implements constants.ICache.
func (m *Memo) Has(key string) (bool, error) {
_, ok := smap.Load(key)
return ok, nil
}
// Set implements constants.ICache.
func (m *Memo) Set(key string, value any) (res bool, err error) {
ok, err := m.Has(key)
if err != nil {
return
}
if !ok {
smap.Store(key, value)
res = true
}
return
}
func (m *Memo) FuzzyDel(prefix string) error {
smap.Range(func(key, value any) bool {
if key, ok := key.(string); ok {
if strings.HasPrefix(key, prefix) {
smap.Delete(key)
}
}
return true
})
return nil
}
var _ constants.ICache = (*Memo)(nil)
+161
View File
@@ -0,0 +1,161 @@
package mongo
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type ICollection interface {
SelectPage(ctx context.Context, filter any, sort any, skip, limit int64) (int64, []any, error)
SelectList(ctx context.Context, filter any, sort interface{}) ([]any, error)
SelectOne(ctx context.Context, filter any) (interface{}, error)
Count(ctx context.Context, filter any) (int64, error)
UpdateOne(ctx context.Context, filter, update any) (int64, error)
UpdateMany(ctx context.Context, filter, update any) (int64, error)
Delete(ctx context.Context, filter any) (int64, error)
InsertOne(ctx context.Context, model any) (any, error)
InsertMany(ctx context.Context, models []any) ([]any, error)
Aggregate(ctx context.Context, pipeline any, result any) error
CreateIndexes(ctx context.Context, indexes []mongo.IndexModel) error
GetCollection() *mongo.Collection
}
type Collection struct {
coll *mongo.Collection
}
// Aggregate implements ICollection.
func (c *Collection) Aggregate(ctx context.Context, pipeline any, result any) error {
finder, err := c.coll.Aggregate(ctx, pipeline, options.Aggregate())
if err != nil {
return err
}
if err := finder.All(ctx, &result); err != nil {
return err
}
return nil
}
// CreateIndexes implements ICollection.
func (c *Collection) CreateIndexes(ctx context.Context, indexes []mongo.IndexModel) error {
_, err := c.coll.Indexes().CreateMany(ctx, indexes, options.CreateIndexes())
return err
}
// Delete implements ICollection.
func (c *Collection) Delete(ctx context.Context, filter any) (int64, error) {
result, err := c.coll.DeleteMany(ctx, filter, options.Delete())
if err != nil {
return 0, err
}
if result.DeletedCount == 0 {
return 0, fmt.Errorf("DeleteOne result: %s ", "document not found")
}
return result.DeletedCount, nil
}
// GetCollection implements ICollection.
func (c *Collection) GetCollection() *mongo.Collection {
return c.coll
}
// InsertMany implements ICollection.
func (c *Collection) InsertMany(ctx context.Context, models []any) ([]any, error) {
result, err := c.coll.InsertMany(ctx, models, options.InsertMany())
if err != nil {
return nil, err
}
return result.InsertedIDs, err
}
// InsertOne implements ICollection.
func (c *Collection) InsertOne(ctx context.Context, model any) (any, error) {
result, err := c.coll.InsertOne(ctx, model, options.InsertOne())
if err != nil {
return nil, err
}
return result.InsertedID, err
}
// Count implements ICollection.
func (c *Collection) Count(ctx context.Context, filter any) (int64, error) {
return c.coll.CountDocuments(ctx, filter)
}
// SelectList implements ICollection.
func (c *Collection) SelectList(ctx context.Context, filter any, sort interface{}) ([]any, error) {
var err error
opts := options.Find().SetSort(sort)
finder, err := c.coll.Find(ctx, filter, opts)
if err != nil {
return nil, err
}
result := make([]interface{}, 0)
if err := finder.All(ctx, &result); err != nil {
return nil, err
}
return result, err
}
// SelectOne implements ICollection.
func (c *Collection) SelectOne(ctx context.Context, filter any) (interface{}, error) {
result := new(interface{})
err := c.coll.FindOne(ctx, filter, options.FindOne()).Decode(result)
if err != nil {
return nil, err
}
return result, nil
}
// SelectPage implements ICollection.
func (c *Collection) SelectPage(ctx context.Context, filter any, sort any, skip int64, limit int64) (int64, []any, error) {
var err error
resultCount, err := c.coll.CountDocuments(ctx, filter)
if err != nil {
return 0, nil, err
}
opts := options.Find().SetSort(sort).SetSkip(skip).SetLimit(limit)
finder, err := c.coll.Find(ctx, filter, opts)
if err != nil {
return resultCount, nil, err
}
result := make([]interface{}, 0)
if err := finder.All(ctx, &result); err != nil {
return resultCount, nil, err
}
return resultCount, result, nil
}
// UpdateMany implements ICollection.
func (c *Collection) UpdateMany(ctx context.Context, filter any, update any) (int64, error) {
result, err := c.coll.UpdateMany(ctx, filter, update, options.Update())
if err != nil {
return 0, err
}
if result.MatchedCount == 0 {
return 0, fmt.Errorf("update result: %s ", "document not found")
}
return result.MatchedCount, nil
}
// UpdateOne implements ICollection.
func (c *Collection) UpdateOne(ctx context.Context, filter any, update any) (int64, error) {
result, err := c.coll.UpdateOne(ctx, filter, update, options.Update())
if err != nil {
return 0, err
}
if result.MatchedCount == 0 {
return 0, fmt.Errorf("update result: %s ", "document not found")
}
return result.MatchedCount, nil
}
var _ ICollection = (*Collection)(nil)
+74
View File
@@ -0,0 +1,74 @@
package mongo
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const timeout = 3 * time.Second
type MonConf struct {
Uri string
Pool struct {
Max uint64
Min uint64
MaxConn uint64
MaxIdleTime int64
}
}
type Mon struct {
conf MonConf
instance *mongo.Client
}
func New(conf MonConf) *Mon {
defaultConf(&conf)
mon := &Mon{
conf: conf,
}
mon.instance = mon.DB()
return mon
}
func (m *Mon) DB() *mongo.Client {
if m.instance == nil {
m.instance = instance(m.conf)
}
return m.instance
}
func (m *Mon) Collection(db, coll string) ICollection {
dataBase := m.instance.Database(db)
return &Collection{
coll: dataBase.Collection(coll),
}
}
func instance(conf MonConf) *mongo.Client {
idleTime := time.Duration(conf.Pool.MaxIdleTime) * time.Second
option := options.Client().ApplyURI(conf.Uri).SetMaxPoolSize(conf.Pool.Max).SetMinPoolSize(conf.Pool.Min)
option = option.SetMaxConnIdleTime(idleTime).SetMaxConnecting(conf.Pool.MaxConn)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
client, err := mongo.Connect(ctx, option)
if err != nil {
log.Fatalf("mongo connect error: %v", err.Error())
return nil
}
return client
}
func defaultConf(conf *MonConf) {
if conf.Pool.Max == 0 {
conf.Pool.Max = 10
}
}
+72
View File
@@ -0,0 +1,72 @@
package xmysql
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type Options struct {
mysql.Config
}
type Option func(opts *Options)
type MysqlDriver struct {
instance gorm.Dialector
Options Options
}
func NewMysqlDriver(opts ...Option) *MysqlDriver {
driver := &MysqlDriver{}
for _, opt := range opts {
opt(&driver.Options)
}
driver.instance = mysql.New(driver.Options.Config)
return driver
}
func (m *MysqlDriver) Instance() gorm.Dialector {
return m.instance
}
// WithMysqlDsn DSN data source name
func WithMysqlDsn(dsn string) Option {
return func(opts *Options) {
opts.DSN = dsn
}
}
// WithMysqlDefaultStringSize string 类型字段的默认长度
func WithMysqlDefaultStringSize(defaultStringSize uint) Option {
return func(opts *Options) {
opts.DefaultStringSize = defaultStringSize
}
}
// WithMysqlDisableDatetimePrecision 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
func WithMysqlDisableDatetimePrecision(disableDatetimePrecision bool) Option {
return func(opts *Options) {
opts.DisableDatetimePrecision = disableDatetimePrecision
}
}
// WithMysqlDontSupportRenameIndex 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
func WithMysqlDontSupportRenameIndex(dontSupportRenameIndex bool) Option {
return func(opts *Options) {
opts.DontSupportRenameIndex = dontSupportRenameIndex
}
}
// WithMysqlDontSupportRenameColumn 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
func WithMysqlDontSupportRenameColumn(dontSupportRenameColumn bool) Option {
return func(opts *Options) {
opts.DontSupportRenameColumn = dontSupportRenameColumn
}
}
// WithMysqlSkipInitializeWithVersion 根据当前 MySQL 版本自动配置
func WithMysqlSkipInitializeWithVersion(skipInitializeWithVersion bool) Option {
return func(opts *Options) {
opts.SkipInitializeWithVersion = skipInitializeWithVersion
}
}
+11
View File
@@ -0,0 +1,11 @@
package xmysql
import "gorm.io/gorm"
type DbHookFunc func(*gorm.DB)
// MaskNotDataError
// 查询无数据时,报错问题(record not found),但是官方认为报错是应该是,我们认为查询无数据,代码一切ok,不应该报错
func MaskNotDataError(db *gorm.DB) {
db.Statement.RaiseErrorOnNotFound = false
}
+80
View File
@@ -0,0 +1,80 @@
package xmysql
import (
"log"
"time"
"gorm.io/gorm"
"gorm.io/plugin/dbresolver"
)
type MySqlConf struct {
Write string
Read []string
MaxIdleConn int
MaxOpenConn int
ConnMaxLifetime int64
ConnMaxIdleTime int64
}
type XMysql struct {
db *gorm.DB
conf MySqlConf
}
func NewMysql(conf MySqlConf) *XMysql {
instance := &XMysql{conf: conf}
db, err := gorm.Open(driver(instance.conf.Write))
if err != nil {
log.Fatalf("error: mysql init %s", err.Error())
return nil
}
instance.db = db
instance.hook()
if err := instance.resolver(); err != nil {
log.Fatalf("error: mysql init resolver %s", err.Error())
return nil
}
return instance
}
func (m *XMysql) DB() *gorm.DB {
return m.db
}
func (m *XMysql) hook() {
// 查询没有数据,屏蔽 gorm v2 包中会爆出的错误
// https://github.com/go-gorm/gorm/issues/3789 此 issue 所反映的问题就是我们本次解决掉的
_ = m.db.Callback().Query().Before("gorm:query").Register("disable_raise_record_not_found", MaskNotDataError)
}
func (m *XMysql) resolver() error {
if len(m.conf.Read) == 0 {
return nil
}
var dbs []gorm.Dialector
for _, v := range m.conf.Read {
dbs = append(dbs, driver(v))
}
resolverConf := dbresolver.Config{
Replicas: dbs,
Policy: dbresolver.RandomPolicy{},
}
if err := m.db.Use(dbresolver.Register(resolverConf).
SetConnMaxIdleTime(time.Duration(m.conf.ConnMaxIdleTime) * time.Second).
SetConnMaxLifetime(time.Duration(m.conf.ConnMaxLifetime) * time.Second).
SetMaxIdleConns(m.conf.MaxIdleConn).
SetMaxOpenConns(m.conf.MaxOpenConn)); err != nil {
return err
}
return nil
}
func driver(dsn string) gorm.Dialector {
return NewMysqlDriver(WithMysqlDsn(dsn), WithMysqlSkipInitializeWithVersion(true)).Instance()
}
+95
View File
@@ -0,0 +1,95 @@
package xredis
import (
"context"
"fmt"
"czx/internal/constants"
"time"
"github.com/redis/go-redis/v9"
)
type RedisConf struct {
Master string
User string
Pass string
Addrs []string
DB int
Pool struct {
Size int
ConnMaxIdle int
ConnMinIdle int
MaxLifeTime int
MaxIdleTime int
}
}
type XRedis struct {
conf RedisConf
instance redis.UniversalClient
}
func New(conf RedisConf) *XRedis {
xrds := &XRedis{
conf: conf,
}
xrds.instance = xrds.DB()
return xrds
}
func (x *XRedis) DB() redis.UniversalClient {
if x.instance == nil {
x.instance = instance((x.conf))
}
return x.instance
}
// Get implements constants.ICache.
func (x *XRedis) Get(key string) (any, error) {
val, err := x.instance.Get(context.Background(), key).Result()
if err != redis.Nil && err != nil {
return nil, err
}
return val, nil
}
// Has implements constants.ICache.
func (x *XRedis) Has(key string) (bool, error) {
val, err := x.instance.Exists(context.Background(), key).Result()
if err != redis.Nil && err != nil {
return false, err
}
if err == redis.Nil {
return false, nil
}
return val > 0, nil
}
// Set implements constants.ICache.
func (x *XRedis) Set(key string, value any) (bool, error) {
if err := x.instance.Set(context.Background(), key, fmt.Sprintf("%v", value), -1).Err(); err != nil {
return false, err
}
return true, nil
}
func instance(conf RedisConf) redis.UniversalClient {
return redis.NewUniversalClient(&redis.UniversalOptions{
MasterName: conf.Master,
Username: conf.User,
Password: conf.Pass,
DB: conf.DB,
Addrs: conf.Addrs,
PoolFIFO: true,
PoolSize: conf.Pool.Size,
MinIdleConns: conf.Pool.ConnMinIdle,
MaxIdleConns: conf.Pool.ConnMaxIdle,
ConnMaxIdleTime: time.Duration(conf.Pool.MaxIdleTime) * time.Second,
ConnMaxLifetime: time.Duration(conf.Pool.MaxLifeTime) * time.Second,
})
}
var _ constants.ICache = (*XRedis)(nil)
+38
View File
@@ -0,0 +1,38 @@
package utils
import (
"reflect"
)
func CheckFieldExistence(obj interface{}, name string) bool {
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return false
}
return val.FieldByName(name).IsValid()
}
func StructHasTag(obj interface{}, name string) bool {
var typ reflect.Type
switch IsPointer(obj) {
case true:
typ = reflect.TypeOf(obj).Elem()
default:
typ = reflect.TypeOf(obj)
}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
tag := field.Tag.Get(name)
if len(tag) > 0 {
return true
}
}
return false
}
func IsPointer(obj interface{}) bool {
return reflect.TypeOf(obj).Kind() == reflect.Ptr
}
+31
View File
@@ -0,0 +1,31 @@
package xcron
import "github.com/robfig/cron/v3"
type ICron interface {
Rule() string
Execute() func()
}
type Cron struct {
instance *cron.Cron
}
func New() *Cron {
return &Cron{
instance: cron.New(),
}
}
func (c *Cron) AddFunc(cmd ...ICron) {
if len(cmd) == 0 {
return
}
for _, job := range cmd {
c.instance.AddJob(job.Rule(), cron.FuncJob(job.Execute()))
}
}
func (c *Cron) Start() {
c.instance.Start()
}
+131
View File
@@ -0,0 +1,131 @@
package xlog
import (
"fmt"
"os"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
const timeKey = "time"
var levels = map[string]zapcore.Level{
"debug": zap.DebugLevel,
"info": zap.InfoLevel,
"error": zap.ErrorLevel,
"warn": zap.WarnLevel,
"panic": zap.PanicLevel,
"fatal": zap.FatalLevel,
}
type LogConf struct {
ServiceName string
Path string
Mode string
Encoding string
TimeFormat string
Level string
Compress bool
KeepDays int
}
type XLog struct {
conf LogConf
instance *zap.Logger
}
func New(conf LogConf) *XLog {
defaultConf(&conf)
logger := &XLog{
conf: conf,
}
logger.instance = logger.Logger()
return logger
}
func (x *XLog) Logger() *zap.Logger {
if x.instance == nil {
x.instance = instance(x.conf)
}
return x.instance
}
func instance(conf LogConf) *zap.Logger {
opts := []zap.Option{
zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel),
}
if len(conf.ServiceName) > 0 {
opts = append(opts, zap.Fields(zap.String("service", conf.ServiceName)))
}
var write zapcore.WriteSyncer
switch conf.Mode {
case "file":
write = sync(conf)
default:
write = zapcore.Lock(os.Stdout)
}
// logs level default : debug
level, ok := levels[conf.Level]
if !ok {
level = zap.DebugLevel
}
return zap.New(zapcore.NewCore(encoder(conf), write, level), opts...)
}
func sync(conf LogConf) zapcore.WriteSyncer {
return zapcore.AddSync(&lumberjack.Logger{
Filename: fmt.Sprintf("%s/%s", conf.Path, fmt.Sprintf("%s.log", conf.Level)),
Compress: conf.Compress,
MaxAge: conf.KeepDays,
})
}
func encoder(conf LogConf) zapcore.Encoder {
var encoder zapcore.Encoder
econf := zap.NewProductionEncoderConfig()
econf.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format(conf.TimeFormat))
}
if conf.Level == "debug" {
econf.EncodeLevel = zapcore.LowercaseColorLevelEncoder
} else {
econf.EncodeLevel = zapcore.LowercaseLevelEncoder
}
econf.TimeKey = timeKey
switch conf.Encoding {
case "json":
encoder = zapcore.NewJSONEncoder(econf)
default:
encoder = zapcore.NewConsoleEncoder(econf)
}
return encoder
}
func defaultConf(conf *LogConf) {
if len(conf.Path) == 0 {
path, _ := os.Getwd()
conf.Path = fmt.Sprintf("%s/logs", path)
}
if len(conf.Level) == 0 {
conf.Level = "debug"
}
if len(conf.Encoding) == 0 {
conf.Encoding = "console"
}
if len(conf.TimeFormat) == 0 {
conf.TimeFormat = "2006-01-02 15:04:05"
}
if !conf.Compress {
conf.Compress = true
}
}
+34
View File
@@ -0,0 +1,34 @@
package test
import (
"fmt"
"czx/app/config"
"czx/internal/conf"
"testing"
"github.com/spf13/viper"
)
func TestConf(t *testing.T) {
viper.SetConfigFile("../config/config.yaml")
if err := viper.ReadInConfig(); err != nil {
fmt.Println(err)
return
}
var conf config.Config
if err := viper.Unmarshal(&conf); err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", conf)
}
func TestXConf(t *testing.T) {
xconf := conf.New("../config/config.yaml")
tout, err := xconf.Get("Timeout")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(tout)
}
+24
View File
@@ -0,0 +1,24 @@
package test
import (
"czx/internal/server/xhttp"
"testing"
"github.com/spf13/viper"
)
func xhttpConf() (conf xhttp.HttpConf) {
viper.SetConfigFile("../config/config.yaml")
if err := viper.ReadInConfig(); err != nil {
return
}
if err := viper.Unmarshal(&conf); err != nil {
return
}
return
}
func TestXHttp(t *testing.T) {
xhp := xhttp.New(xhttpConf())
xhp.Start()
}