mirror of
https://github.com/czx-lab/skeleton.git
synced 2026-04-22 23:57:31 +08:00
feat: v2.0
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
.idea
|
||||
/storage/logs/*
|
||||
@@ -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.
|
||||
@@ -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}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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...")
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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!")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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
|
||||
)
|
||||
@@ -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=
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package constants
|
||||
|
||||
type IService interface {
|
||||
Start() error
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user