Compare commits

...

25 Commits

Author SHA1 Message Date
9f547eed27 feat 模块删除bind函数 2026-02-06 22:54:01 +08:00
9b3a23e9be feat 废弃jwt 、 学识分 2026-02-06 22:31:33 +08:00
e2fa47fd27 feat sn 改成 int64 2026-01-30 11:56:14 +08:00
9781cd126f feat kafka 改版 2 2026-01-30 11:02:55 +08:00
3b14697a45 feat 配置 2026-01-26 10:21:50 +08:00
4249a8b43d feat kafka 2026-01-24 22:47:43 +08:00
e80f3593c9 feat kafka 2026-01-24 21:48:33 +08:00
9e184ef506 feat kafka 2026-01-23 21:26:11 +08:00
f1f8e162e0 feat 模块增加after start 2026-01-20 12:11:29 +08:00
81bae2992d feat grpc模块 2026-01-19 10:53:16 +08:00
86a07d63f1 feat 服务发现模块 2026-01-18 00:08:58 +08:00
9d7397b279 feat 自定义拦截器 2026-01-16 23:51:48 +08:00
450f89107a feat jenkins 2026-01-16 22:58:49 +08:00
e9d82d9831 feat Prometheus 2026-01-16 22:36:32 +08:00
b81b7f4e13 feat 错误包装 2026-01-16 22:13:22 +08:00
d7c9442aae feat 端口修改 2026-01-16 22:09:44 +08:00
17d4616eb6 feat app 模块 2026-01-16 22:07:10 +08:00
f9592747db feat 答题记录 2026-01-14 21:05:42 +08:00
ecbe4cc43c feat common 2026-01-14 18:19:42 +08:00
1caf9f32ea feat 历史记录 2026-01-14 18:15:43 +08:00
3750ff1c34 feat 微信登录 2026-01-14 10:53:27 +08:00
7aec1c2d4f feat 奇怪的知识1.0.1 2026-01-13 11:28:00 +08:00
b8e5aba27c feat 拆出qgdzs 2026-01-12 16:53:48 +08:00
a0b434fe7c feat sc改名ss 2026-01-12 12:20:12 +08:00
652290352c feat ss改名rs 2026-01-12 11:58:40 +08:00
31 changed files with 619 additions and 1375 deletions

View File

@@ -2,29 +2,32 @@ package app
import (
"fmt"
"git.hlsq.asia/mmorpg/service-common/discover"
"git.hlsq.asia/mmorpg/service-common/discover/common"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/module"
"git.hlsq.asia/mmorpg/service-user/config"
"git.hlsq.asia/mmorpg/service-user/internal/grpc_server"
"github.com/judwhite/go-svc"
"sync"
)
type Program struct {
moduleList []Module // 模块列表
}
type Module interface {
init() error
start() error
stop() error
moduleList []module.Module // 模块列表
}
func (p *Program) Init(_ svc.Environment) error {
p.moduleList = append(p.moduleList, &ModuleBase{})
p.moduleList = append(p.moduleList, &ModuleDB{})
p.moduleList = append(p.moduleList, &ModuleGrpcServer{})
if err := config.LoadConfig(); err != nil {
return err
}
p.moduleList = append(p.moduleList, &module.Base{Log: config.Get().Log})
p.moduleList = append(p.moduleList, &module.DB{Cfg: config.Get().DB, AppName: config.Get().App.Name})
p.moduleList = append(p.moduleList, &module.Grpc{Server: grpc_server.NewServer(config.Get().Serve.Grpc)})
p.moduleList = append(p.moduleList, &module.Prometheus{MetricCfg: config.Get().Metric})
p.moduleList = append(p.moduleList, &module.Tracer{MetricCfg: config.Get().Metric, ServiceName: common.KeyDiscoverServiceNameUser})
p.moduleList = append(p.moduleList, &module.Discover{})
for _, module := range p.moduleList {
if err := module.init(); err != nil {
for _, m := range p.moduleList {
if err := m.Init(); err != nil {
return err
}
}
@@ -33,22 +36,28 @@ func (p *Program) Init(_ svc.Environment) error {
}
func (p *Program) Start() error {
for _, module := range p.moduleList {
if err := module.start(); err != nil {
ready := &sync.WaitGroup{}
ready.Add(len(p.moduleList))
for _, m := range p.moduleList {
if err := m.Start(ready); err != nil {
return err
}
}
ready.Wait()
for _, m := range p.moduleList {
if err := m.AfterStart(); err != nil {
return err
}
}
discover.Listen()
log.Infof(fmt.Sprintf("%v Start successful...", config.Get().App.Name))
return nil
}
func (p *Program) Stop() error {
discover.Close()
for i := len(p.moduleList) - 1; i >= 0; i-- {
module := p.moduleList[i]
if err := module.stop(); err != nil {
m := p.moduleList[i]
if err := m.Stop(); err != nil {
log.Errorf("module stop error: %v", err)
}
}

View File

@@ -1,33 +0,0 @@
package app
import (
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/utils"
"git.hlsq.asia/mmorpg/service-user/config"
"math/rand"
)
// ModuleBase 基础模块,或者一些零散的模块
type ModuleBase struct {
}
func (p *ModuleBase) init() error {
// 配置
if err := config.LoadConfig(); err != nil {
return err
}
cfg := config.Get()
// 日志
log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level)
// 雪花
utils.InitSnowflake(int64(rand.Intn(1000)))
return nil
}
func (p *ModuleBase) start() error {
return nil
}
func (p *ModuleBase) stop() error {
return nil
}

View File

@@ -1,23 +0,0 @@
package app
import (
"git.hlsq.asia/mmorpg/service-common/db"
"git.hlsq.asia/mmorpg/service-user/config"
)
// ModuleDB 数据库模块
type ModuleDB struct {
dbModule *db.ModuleDB
}
func (p *ModuleDB) init() error {
return p.dbModule.Init(config.Get().DB)
}
func (p *ModuleDB) start() error {
return nil
}
func (p *ModuleDB) stop() error {
return p.dbModule.Stop()
}

View File

@@ -1,27 +0,0 @@
package app
import (
"git.hlsq.asia/mmorpg/service-common/net/grpc/service"
"git.hlsq.asia/mmorpg/service-user/config"
"git.hlsq.asia/mmorpg/service-user/internal/grpc_server/server"
)
// ModuleGrpcServer Grpc服务模块
type ModuleGrpcServer struct {
server service.IService
}
func (m *ModuleGrpcServer) init() error {
return nil
}
func (m *ModuleGrpcServer) start() error {
m.server = server.NewServer(config.Get().Serve.Grpc.TTL)
m.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port)
return nil
}
func (m *ModuleGrpcServer) stop() error {
m.server.Close()
return nil
}

View File

@@ -8,24 +8,36 @@ log:
maxBackups: 100
maxAge: 7
metric:
prometheus:
address: "0.0.0.0"
port: 18801
jaeger:
endpoint: "127.0.0.1:4317"
db:
etcd:
endpoints: [ "10.0.40.9:2379" ]
endpoints: [ "127.0.0.1:2379" ]
mysql:
user_db:
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/user_db?charset=utf8mb4&parseTime=True&loc=Local"
dsn: "root:gR9pV4tY7zR6qL3e@tcp(127.0.0.1:3306)/user_db?charset=utf8mb4&parseTime=True&loc=Local"
maxOpenConn: 50
maxIdleConn: 20
connMaxLifetimeSec: 600
connMaxIdleTimeSec: 180
logLevel: "warn"
logLevel: "info"
redis:
addr: "47.108.184.184:6379"
addr: "127.0.0.1:6379"
password: "lQ7aM8oB6lK0iD5k"
db: 0
serve:
grpc:
address: "10.0.40.199"
port: 8602
address: "127.0.0.1"
port: 18800
ttl: 20
wxMini:
appid: "wx1b6ea981a8bafd4e"
secret: "e62e0fdf51db0e91dee3a7aba6a9c3ed"
envVersion: "release"

View File

@@ -7,8 +7,14 @@ const path = "./config"
type Config struct {
App *config.AppConfig `yaml:"app"`
Log *config.LogConfig `yaml:"log"`
Metric *config.MetricConfig `yaml:"metric"`
DB *config.DBConfig `yaml:"db"`
Serve *config.ServeConfig `yaml:"serve"`
WxMini *struct {
AppID string `yaml:"appid"`
Secret string `yaml:"secret"`
EnvVersion string `yaml:"envVersion"`
} `yaml:"wxMini"`
}
var cfg *Config

View File

@@ -8,6 +8,13 @@ log:
maxBackups: 100
maxAge: 7
metric:
prometheus:
address: "0.0.0.0"
port: 18801
jaeger:
endpoint: "172.18.28.0:4317"
db:
etcd:
endpoints: [ "172.18.28.0:2379" ]
@@ -27,5 +34,10 @@ db:
serve:
grpc:
address: "172.18.28.0"
port: 8602
port: 18800
ttl: 20
wxMini:
appid: "wx1b6ea981a8bafd4e"
secret: "e62e0fdf51db0e91dee3a7aba6a9c3ed"
envVersion: "release"

5
deploy/Jenkinsfile vendored
View File

@@ -51,7 +51,7 @@ pipeline {
stage('Build Go Binary') {
agent {
docker {
image 'golang:1.23.1-alpine'
image 'golang:1.24.0-alpine'
reuseNode true
args '-u root:root -v $GO_MOD_CACHE_DIR:/go/pkg/mod -v $GO_BUILD_CACHE_DIR:/root/.cache/go-build'
}
@@ -80,6 +80,7 @@ pipeline {
sh """
echo "$DOCKER_PASS" | docker login --username "$DOCKER_USER" --password-stdin ${env.REGISTRY_URL}
docker buildx build --platform linux/amd64 -t ${env.IMAGE_TAG} -f deploy/Dockerfile . --push
docker rmi ${env.IMAGE_TAG}
docker logout ${env.REGISTRY_URL}
"""
}
@@ -109,7 +110,7 @@ pipeline {
docker run -d \\
--name ${env.APP_NAME} \\
--restart unless-stopped \\
-p 8602:8602 \\
-p 18800-18801:18800-18801 \\
--env XH_G_ENV=prod \\
-v /root/service/logs/user_log/:/app/logs \\
${env.IMAGE_TAG}

84
go.mod
View File

@@ -1,12 +1,11 @@
module git.hlsq.asia/mmorpg/service-user
go 1.23.1
go 1.24.0
require (
git.hlsq.asia/mmorpg/service-common v0.0.0-20260110153008-0be254c6a298
git.hlsq.asia/mmorpg/service-common v0.0.0-20260206145147-5a0f4b71d430
github.com/judwhite/go-svc v1.2.1
google.golang.org/grpc v1.71.1
google.golang.org/protobuf v1.36.9
google.golang.org/grpc v1.77.0
gorm.io/gen v0.3.27
gorm.io/gorm v1.31.1
gorm.io/plugin/dbresolver v1.6.2
@@ -14,45 +13,69 @@ require (
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/IBM/sarama v1.46.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.14.2 // indirect
github.com/bytedance/sonic/loader v0.4.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/eapache/go-resiliency v1.7.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/gin-gonic/gin v1.11.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.27.0 // indirect
github.com/go-playground/validator/v10 v10.28.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.1 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
github.com/panjf2000/gnet/v2 v2.9.7 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.54.0 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.57.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/redis/go-redis/v9 v9.10.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
@@ -63,24 +86,33 @@ require (
github.com/stretchr/testify v1.11.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
go.etcd.io/etcd/api/v3 v3.6.1 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.1 // indirect
go.etcd.io/etcd/client/v3 v3.6.1 // indirect
go.uber.org/mock v0.5.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/mod v0.26.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/tools v0.35.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
golang.org/x/arch v0.23.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/tools v0.38.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/datatypes v1.2.4 // indirect

223
go.sum
View File

@@ -1,19 +1,27 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.hlsq.asia/mmorpg/service-common v0.0.0-20260110153008-0be254c6a298 h1:zKQC0gqQfP9sUVYs7OsoHSrzdk379u6aenko6rMx1go=
git.hlsq.asia/mmorpg/service-common v0.0.0-20260110153008-0be254c6a298/go.mod h1:xv6m1I2jUA6mudKVznygpnzMoshBQarthHD1QnkW4qc=
git.hlsq.asia/mmorpg/service-common v0.0.0-20260206145147-5a0f4b71d430 h1:8aNIgKpU6HBg7h4ENjuGWshap+VxeKUmLE0IvFoWbug=
git.hlsq.asia/mmorpg/service-common v0.0.0-20260206145147-5a0f4b71d430/go.mod h1:mMhZcumphj6gaVTppVYsMTkd+5HupmQgAc53Pd4MH9I=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/IBM/sarama v1.46.3 h1:njRsX6jNlnR+ClJ8XmkO+CM4unbrNr/2vB5KK6UA+IE=
github.com/IBM/sarama v1.46.3/go.mod h1:GTUYiF9DMOZVe3FwyGT+dtSPceGFIgA+sPc5u6CBwko=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
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/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
@@ -27,18 +35,27 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/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/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws=
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
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.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -47,16 +64,16 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
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.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
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/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.0 h1:EmkZ9RIsX+Uq4DYFowegAuJo8+xdX3T/2dwNPXbxEYE=
github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -68,13 +85,20 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
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.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
@@ -83,6 +107,18 @@ github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
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.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@@ -94,12 +130,16 @@ github.com/judwhite/go-svc v1.2.1 h1:a7fsJzYUa33sfDJRF2N/WXhA+LonCEEY8BJb1tuS5tA
github.com/judwhite/go-svc v1.2.1/go.mod h1:mo/P2JNX8C07ywpP9YtO2gnBgnUiFTHqtsZekJrUuTk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -109,26 +149,41 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
github.com/panjf2000/gnet/v2 v2.9.7 h1:6zW7Jl3oAfXwSuh1PxHLndoL2MQRWx0AJR6aaQjxUgA=
github.com/panjf2000/gnet/v2 v2.9.7/go.mod h1:WQTxDWYuQ/hz3eccH0FN32IVuvZ19HewEWx0l62fx7E=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10=
github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
@@ -144,105 +199,143 @@ github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjb
github.com/stretchr/objx v0.1.0/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
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.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
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.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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.etcd.io/etcd/api/v3 v3.6.1 h1:yJ9WlDih9HT457QPuHt/TH/XtsdN2tubyxyQHSHPsEo=
go.etcd.io/etcd/api/v3 v3.6.1/go.mod h1:lnfuqoGsXMlZdTJlact3IB56o3bWp1DIlXPIGKRArto=
go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BSoGk=
go.etcd.io/etcd/client/pkg/v3 v3.6.1/go.mod h1:aTkCp+6ixcVTZmrJGa7/Mc5nMNs59PEgBbq+HCmWyMc=
go.etcd.io/etcd/client/v3 v3.6.1 h1:KelkcizJGsskUXlsxjVrSmINvMMga0VWwFF0tSPGEP0=
go.etcd.io/etcd/client/v3 v3.6.1/go.mod h1:fCbPUdjWNLfx1A6ATo9syUmFVxqHH9bCnPLBZmnLmMY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
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/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.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=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
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.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
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-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
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-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-20210124154548-22da62e12c0c/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-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.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
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/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.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
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/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
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/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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
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=

View File

@@ -1,55 +0,0 @@
package ai
import (
"git.hlsq.asia/mmorpg/service-common/log"
)
type Client struct {
enableSearch bool // 是否开启搜索
searchStrategy string // 搜索策略(开了搜索才生效)
temperature float32 // 采样温度
}
func NewAIClient(enableSearch bool, searchStrategy string, temperature float32) *Client {
return &Client{
enableSearch: enableSearch,
searchStrategy: searchStrategy,
temperature: temperature,
}
}
func (c *Client) RequestAI(prompt []string, cb func(content string, i int) error) error {
inToken, outToken := int32(0), int32(0)
messages := make([]Message, 0)
for i, step := range prompt {
messages = append(messages, Message{
Role: "user",
Content: step,
})
r, err := request("deepseek-v3.2", Parameters{
EnableSearch: c.enableSearch,
SearchOptions: SearchOptions{
SearchStrategy: c.searchStrategy,
},
ResultFormat: "message",
Temperature: c.temperature,
}, messages)
if err != nil {
return err
}
inToken += r.Usage.InputTokens
outToken += r.Usage.OutputTokens
if len(r.Output.Choices) == 0 {
log.Infof("AI response err, r: %#+v", r)
return err
} else {
messages = append(messages, r.Output.Choices[0].Message)
}
log.Infof("AI 回答 %v: %v", i, r.Output.Choices[0].Message.Content)
if err = cb(r.Output.Choices[0].Message.Content, i); err != nil {
return err
}
}
log.Infof("AI finished, use token: in-%v out-%v", inToken, outToken)
return nil
}

View File

@@ -1,82 +0,0 @@
package ai
import (
"bytes"
"encoding/json"
"io"
"net/http"
)
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type Input struct {
Messages []Message `json:"messages"`
}
type Parameters struct {
EnableSearch bool `json:"enable_search,omitempty"`
SearchOptions SearchOptions `json:"search_options,omitempty"`
ResultFormat string `json:"result_format,omitempty"`
Temperature float32 `json:"temperature,omitempty"`
}
type SearchOptions struct {
SearchStrategy string `json:"search_strategy"`
}
type RequestBody struct {
Model string `json:"model"`
Input Input `json:"input"`
Parameters Parameters `json:"parameters"`
}
type ResponseBody struct {
Output struct {
Choices []struct {
Message Message `json:"message"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
} `json:"output"`
Usage struct {
InputTokens int32 `json:"input_tokens"`
OutputTokens int32 `json:"output_tokens"`
TotalTokens int32 `json:"total_tokens"`
} `json:"usage"`
}
func request(model string, parameters Parameters, messages []Message) (*ResponseBody, error) {
requestBody := RequestBody{
Model: model,
Input: Input{
Messages: messages,
},
Parameters: parameters,
}
jsonData, _ := json.Marshal(requestBody)
req, err := http.NewRequest("POST", "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+"sk-4daf94ad2fa94288b198d2a1d8924cef")
req.Header.Set("Content-Type", "application/json")
resp, err := (&http.Client{}).Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var res ResponseBody
if err = json.Unmarshal(body, &res); err != nil {
return nil, err
}
return &res, nil
}

View File

@@ -1,42 +0,0 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
"git.hlsq.asia/mmorpg/service-common/utils"
"gorm.io/gorm"
)
const TableNameQuestion = "questions"
// Question mapped from table <questions>
type Question struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Sn string `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
Question string `gorm:"column:question;not null;comment:题干" json:"question"` // 题干
Options string `gorm:"column:options;not null;comment:选项" json:"options"` // 选项
Answer string `gorm:"column:answer;not null;comment:答案" json:"answer"` // 答案
Explanation string `gorm:"column:explanation;not null;comment:解析" json:"explanation"` // 解析
Difficulty int32 `gorm:"column:difficulty;not null;comment:难度分 0 - 100" json:"difficulty"` // 难度分 0 - 100
Category string `gorm:"column:category;not null;comment:分类" json:"category"` // 分类
CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"`
}
// TableName Question's table name
func (*Question) TableName() string {
return TableNameQuestion
}
// Auto sn
func (m *Question) BeforeCreate(_ *gorm.DB) error {
if m.Sn == "" {
m.Sn = utils.SnowflakeInstance().Generate().String()
}
return nil
}

View File

@@ -16,9 +16,11 @@ const TableNameUser = "users"
// User mapped from table <users>
type User struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Sn string `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
Sn int64 `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
Name string `gorm:"column:name;not null" json:"name"`
Phone string `gorm:"column:phone;not null" json:"phone"`
Phone string `gorm:"column:phone" json:"phone"`
WxUnionID string `gorm:"column:wx_union_id;comment:微信用户唯一标识" json:"wx_union_id"` // 微信用户唯一标识
WxMiniOpenID string `gorm:"column:wx_mini_open_id;comment:微信小程序的openID" json:"wx_mini_open_id"` // 微信小程序的openID
CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"`
@@ -31,8 +33,8 @@ func (*User) TableName() string {
// Auto sn
func (m *User) BeforeCreate(_ *gorm.DB) error {
if m.Sn == "" {
m.Sn = utils.SnowflakeInstance().Generate().String()
if m.Sn == 0 {
m.Sn = utils.SnowflakeInstance().Generate().Int64()
}
return nil
}

View File

@@ -18,7 +18,6 @@ import (
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{
db: db,
Question: newQuestion(db, opts...),
User: newUser(db, opts...),
}
}
@@ -26,7 +25,6 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
type Query struct {
db *gorm.DB
Question question
User user
}
@@ -35,7 +33,6 @@ func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query {
return &Query{
db: db,
Question: q.Question.clone(db),
User: q.User.clone(db),
}
}
@@ -51,19 +48,16 @@ func (q *Query) WriteDB() *Query {
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{
db: db,
Question: q.Question.replaceDB(db),
User: q.User.replaceDB(db),
}
}
type queryCtx struct {
Question *questionDo
User *userDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{
Question: q.Question.WithContext(ctx),
User: q.User.WithContext(ctx),
}
}

View File

@@ -1,367 +0,0 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"git.hlsq.asia/mmorpg/service-user/internal/dao/model"
)
func newQuestion(db *gorm.DB, opts ...gen.DOOption) question {
_question := question{}
_question.questionDo.UseDB(db, opts...)
_question.questionDo.UseModel(&model.Question{})
tableName := _question.questionDo.TableName()
_question.ALL = field.NewAsterisk(tableName)
_question.ID = field.NewUint64(tableName, "id")
_question.Sn = field.NewString(tableName, "sn")
_question.Question = field.NewString(tableName, "question")
_question.Options = field.NewString(tableName, "options")
_question.Answer = field.NewString(tableName, "answer")
_question.Explanation = field.NewString(tableName, "explanation")
_question.Difficulty = field.NewInt32(tableName, "difficulty")
_question.Category = field.NewString(tableName, "category")
_question.CreatedAt = field.NewTime(tableName, "created_at")
_question.UpdatedAt = field.NewTime(tableName, "updated_at")
_question.DeletedAt = field.NewField(tableName, "deleted_at")
_question.fillFieldMap()
return _question
}
type question struct {
questionDo questionDo
ALL field.Asterisk
ID field.Uint64
Sn field.String // 业务唯一编号
Question field.String // 题干
Options field.String // 选项
Answer field.String // 答案
Explanation field.String // 解析
Difficulty field.Int32 // 难度分 0 - 100
Category field.String // 分类
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
fieldMap map[string]field.Expr
}
func (q question) Table(newTableName string) *question {
q.questionDo.UseTable(newTableName)
return q.updateTableName(newTableName)
}
func (q question) As(alias string) *question {
q.questionDo.DO = *(q.questionDo.As(alias).(*gen.DO))
return q.updateTableName(alias)
}
func (q *question) updateTableName(table string) *question {
q.ALL = field.NewAsterisk(table)
q.ID = field.NewUint64(table, "id")
q.Sn = field.NewString(table, "sn")
q.Question = field.NewString(table, "question")
q.Options = field.NewString(table, "options")
q.Answer = field.NewString(table, "answer")
q.Explanation = field.NewString(table, "explanation")
q.Difficulty = field.NewInt32(table, "difficulty")
q.Category = field.NewString(table, "category")
q.CreatedAt = field.NewTime(table, "created_at")
q.UpdatedAt = field.NewTime(table, "updated_at")
q.DeletedAt = field.NewField(table, "deleted_at")
q.fillFieldMap()
return q
}
func (q *question) WithContext(ctx context.Context) *questionDo { return q.questionDo.WithContext(ctx) }
func (q question) TableName() string { return q.questionDo.TableName() }
func (q question) Alias() string { return q.questionDo.Alias() }
func (q question) Columns(cols ...field.Expr) gen.Columns { return q.questionDo.Columns(cols...) }
func (q *question) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := q.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (q *question) fillFieldMap() {
q.fieldMap = make(map[string]field.Expr, 11)
q.fieldMap["id"] = q.ID
q.fieldMap["sn"] = q.Sn
q.fieldMap["question"] = q.Question
q.fieldMap["options"] = q.Options
q.fieldMap["answer"] = q.Answer
q.fieldMap["explanation"] = q.Explanation
q.fieldMap["difficulty"] = q.Difficulty
q.fieldMap["category"] = q.Category
q.fieldMap["created_at"] = q.CreatedAt
q.fieldMap["updated_at"] = q.UpdatedAt
q.fieldMap["deleted_at"] = q.DeletedAt
}
func (q question) clone(db *gorm.DB) question {
q.questionDo.ReplaceConnPool(db.Statement.ConnPool)
return q
}
func (q question) replaceDB(db *gorm.DB) question {
q.questionDo.ReplaceDB(db)
return q
}
type questionDo struct{ gen.DO }
func (q questionDo) Debug() *questionDo {
return q.withDO(q.DO.Debug())
}
func (q questionDo) WithContext(ctx context.Context) *questionDo {
return q.withDO(q.DO.WithContext(ctx))
}
func (q questionDo) ReadDB() *questionDo {
return q.Clauses(dbresolver.Read)
}
func (q questionDo) WriteDB() *questionDo {
return q.Clauses(dbresolver.Write)
}
func (q questionDo) Session(config *gorm.Session) *questionDo {
return q.withDO(q.DO.Session(config))
}
func (q questionDo) Clauses(conds ...clause.Expression) *questionDo {
return q.withDO(q.DO.Clauses(conds...))
}
func (q questionDo) Returning(value interface{}, columns ...string) *questionDo {
return q.withDO(q.DO.Returning(value, columns...))
}
func (q questionDo) Not(conds ...gen.Condition) *questionDo {
return q.withDO(q.DO.Not(conds...))
}
func (q questionDo) Or(conds ...gen.Condition) *questionDo {
return q.withDO(q.DO.Or(conds...))
}
func (q questionDo) Select(conds ...field.Expr) *questionDo {
return q.withDO(q.DO.Select(conds...))
}
func (q questionDo) Where(conds ...gen.Condition) *questionDo {
return q.withDO(q.DO.Where(conds...))
}
func (q questionDo) Order(conds ...field.Expr) *questionDo {
return q.withDO(q.DO.Order(conds...))
}
func (q questionDo) Distinct(cols ...field.Expr) *questionDo {
return q.withDO(q.DO.Distinct(cols...))
}
func (q questionDo) Omit(cols ...field.Expr) *questionDo {
return q.withDO(q.DO.Omit(cols...))
}
func (q questionDo) Join(table schema.Tabler, on ...field.Expr) *questionDo {
return q.withDO(q.DO.Join(table, on...))
}
func (q questionDo) LeftJoin(table schema.Tabler, on ...field.Expr) *questionDo {
return q.withDO(q.DO.LeftJoin(table, on...))
}
func (q questionDo) RightJoin(table schema.Tabler, on ...field.Expr) *questionDo {
return q.withDO(q.DO.RightJoin(table, on...))
}
func (q questionDo) Group(cols ...field.Expr) *questionDo {
return q.withDO(q.DO.Group(cols...))
}
func (q questionDo) Having(conds ...gen.Condition) *questionDo {
return q.withDO(q.DO.Having(conds...))
}
func (q questionDo) Limit(limit int) *questionDo {
return q.withDO(q.DO.Limit(limit))
}
func (q questionDo) Offset(offset int) *questionDo {
return q.withDO(q.DO.Offset(offset))
}
func (q questionDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *questionDo {
return q.withDO(q.DO.Scopes(funcs...))
}
func (q questionDo) Unscoped() *questionDo {
return q.withDO(q.DO.Unscoped())
}
func (q questionDo) Create(values ...*model.Question) error {
if len(values) == 0 {
return nil
}
return q.DO.Create(values)
}
func (q questionDo) CreateInBatches(values []*model.Question, batchSize int) error {
return q.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (q questionDo) Save(values ...*model.Question) error {
if len(values) == 0 {
return nil
}
return q.DO.Save(values)
}
func (q questionDo) First() (*model.Question, error) {
if result, err := q.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.Question), nil
}
}
func (q questionDo) Take() (*model.Question, error) {
if result, err := q.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.Question), nil
}
}
func (q questionDo) Last() (*model.Question, error) {
if result, err := q.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.Question), nil
}
}
func (q questionDo) Find() ([]*model.Question, error) {
result, err := q.DO.Find()
return result.([]*model.Question), err
}
func (q questionDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Question, err error) {
buf := make([]*model.Question, 0, batchSize)
err = q.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (q questionDo) FindInBatches(result *[]*model.Question, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return q.DO.FindInBatches(result, batchSize, fc)
}
func (q questionDo) Attrs(attrs ...field.AssignExpr) *questionDo {
return q.withDO(q.DO.Attrs(attrs...))
}
func (q questionDo) Assign(attrs ...field.AssignExpr) *questionDo {
return q.withDO(q.DO.Assign(attrs...))
}
func (q questionDo) Joins(fields ...field.RelationField) *questionDo {
for _, _f := range fields {
q = *q.withDO(q.DO.Joins(_f))
}
return &q
}
func (q questionDo) Preload(fields ...field.RelationField) *questionDo {
for _, _f := range fields {
q = *q.withDO(q.DO.Preload(_f))
}
return &q
}
func (q questionDo) FirstOrInit() (*model.Question, error) {
if result, err := q.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.Question), nil
}
}
func (q questionDo) FirstOrCreate() (*model.Question, error) {
if result, err := q.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.Question), nil
}
}
func (q questionDo) FindByPage(offset int, limit int) (result []*model.Question, count int64, err error) {
result, err = q.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = q.Offset(-1).Limit(-1).Count()
return
}
func (q questionDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = q.Count()
if err != nil {
return
}
err = q.Offset(offset).Limit(limit).Scan(result)
return
}
func (q questionDo) Scan(result interface{}) (err error) {
return q.DO.Scan(result)
}
func (q questionDo) Delete(models ...*model.Question) (result gen.ResultInfo, err error) {
return q.DO.Delete(models)
}
func (q *questionDo) withDO(do gen.Dao) *questionDo {
q.DO = *do.(*gen.DO)
return q
}

View File

@@ -28,9 +28,11 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user {
tableName := _user.userDo.TableName()
_user.ALL = field.NewAsterisk(tableName)
_user.ID = field.NewUint64(tableName, "id")
_user.Sn = field.NewString(tableName, "sn")
_user.Sn = field.NewInt64(tableName, "sn")
_user.Name = field.NewString(tableName, "name")
_user.Phone = field.NewString(tableName, "phone")
_user.WxUnionID = field.NewString(tableName, "wx_union_id")
_user.WxMiniOpenID = field.NewString(tableName, "wx_mini_open_id")
_user.CreatedAt = field.NewTime(tableName, "created_at")
_user.UpdatedAt = field.NewTime(tableName, "updated_at")
_user.DeletedAt = field.NewField(tableName, "deleted_at")
@@ -45,9 +47,11 @@ type user struct {
ALL field.Asterisk
ID field.Uint64
Sn field.String // 业务唯一编号
Sn field.Int64 // 业务唯一编号
Name field.String
Phone field.String
WxUnionID field.String // 微信用户唯一标识
WxMiniOpenID field.String // 微信小程序的openID
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
@@ -68,9 +72,11 @@ func (u user) As(alias string) *user {
func (u *user) updateTableName(table string) *user {
u.ALL = field.NewAsterisk(table)
u.ID = field.NewUint64(table, "id")
u.Sn = field.NewString(table, "sn")
u.Sn = field.NewInt64(table, "sn")
u.Name = field.NewString(table, "name")
u.Phone = field.NewString(table, "phone")
u.WxUnionID = field.NewString(table, "wx_union_id")
u.WxMiniOpenID = field.NewString(table, "wx_mini_open_id")
u.CreatedAt = field.NewTime(table, "created_at")
u.UpdatedAt = field.NewTime(table, "updated_at")
u.DeletedAt = field.NewField(table, "deleted_at")
@@ -98,11 +104,13 @@ func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (u *user) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 7)
u.fieldMap = make(map[string]field.Expr, 9)
u.fieldMap["id"] = u.ID
u.fieldMap["sn"] = u.Sn
u.fieldMap["name"] = u.Name
u.fieldMap["phone"] = u.Phone
u.fieldMap["wx_union_id"] = u.WxUnionID
u.fieldMap["wx_mini_open_id"] = u.WxMiniOpenID
u.fieldMap["created_at"] = u.CreatedAt
u.fieldMap["updated_at"] = u.UpdatedAt
u.fieldMap["deleted_at"] = u.DeletedAt

View File

@@ -3,6 +3,7 @@ package repository
import (
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/mysql"
"git.hlsq.asia/mmorpg/service-user/internal/dao/query"
)
var dbName mysql.DBName = "user_db"
@@ -12,7 +13,11 @@ var (
userCacheByPhone = "c:user:p:%v"
)
func keyCacheBySn(sn string, tableName string) string {
func Query() *query.Query {
return query.Use(mysql.GetDB(dbName))
}
func keyCacheBySn(sn int64, tableName string) string {
return fmt.Sprintf(cacheBySn, tableName, sn)
}

View File

@@ -1,83 +0,0 @@
package repository
import (
"context"
"git.hlsq.asia/mmorpg/service-common/db/mysql"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/utils"
"git.hlsq.asia/mmorpg/service-user/internal/dao/model"
"git.hlsq.asia/mmorpg/service-user/internal/dao/query"
"gorm.io/gorm"
"time"
)
type QuestionDao struct {
ctx context.Context
query *query.Query
cache *redis.CacheClient
}
func NewQuestionDao(ctx context.Context, cache ...*redis.CacheClient) *QuestionDao {
dao := &QuestionDao{
ctx: ctx,
query: query.Use(mysql.GetDB(dbName)),
}
if len(cache) > 0 {
dao.cache = cache[0]
}
return dao
}
func (d *QuestionDao) Create(question *model.Question) error {
err := d.query.Question.WithContext(d.ctx).
Create(question)
return err
}
func (d *QuestionDao) FindByRandom() (*model.Question, error) {
count, err := d.query.Question.WithContext(d.ctx).Count()
if err != nil {
return nil, err
}
if count == 0 {
return nil, gorm.ErrRecordNotFound
}
first, err := d.query.Question.WithContext(d.ctx).
Offset(utils.RandInt(0, int(count-1))).
First()
if err != nil {
return nil, err
}
return first, nil
}
func (d *QuestionDao) FindBySn(sn string) (*model.Question, error) {
if d.cache != nil {
var question model.Question
if ok := d.cache.Get(d.ctx, keyCacheBySn(sn, question.TableName()), &question); ok {
return &question, nil
}
}
first, err := d.query.Question.WithContext(d.ctx).
Where(d.query.Question.Sn.Eq(sn)).
First()
if err != nil {
return nil, err
}
if d.cache != nil {
d.cache.Set(d.ctx, keyCacheBySn(sn, first.TableName()), first, 5*time.Minute)
}
return first, nil
}
func (d *QuestionDao) FindCategory() ([]string, error) {
var categories []string
err := d.query.Question.WithContext(d.ctx).
Select(d.query.Question.Category).
Distinct().
Scan(&categories)
if err != nil {
return nil, err
}
return categories, nil
}

View File

@@ -2,7 +2,6 @@ package repository
import (
"context"
"git.hlsq.asia/mmorpg/service-common/db/mysql"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-user/internal/dao/model"
"git.hlsq.asia/mmorpg/service-user/internal/dao/query"
@@ -15,10 +14,10 @@ type UserDao struct {
cache *redis.CacheClient
}
func NewUserDao(ctx context.Context, cache ...*redis.CacheClient) *UserDao {
func NewUserDao(ctx context.Context, query *query.Query, cache ...*redis.CacheClient) *UserDao {
dao := &UserDao{
ctx: ctx,
query: query.Use(mysql.GetDB(dbName)),
query: query,
}
if len(cache) > 0 {
dao.cache = cache[0]
@@ -26,10 +25,10 @@ func NewUserDao(ctx context.Context, cache ...*redis.CacheClient) *UserDao {
return dao
}
func (d *UserDao) Create(user *model.User) error {
func (d *UserDao) Create(user *model.User) (*model.User, error) {
err := d.query.User.WithContext(d.ctx).
Create(user)
return err
return user, err
}
func (d *UserDao) Updates(user *model.User) error {
@@ -45,7 +44,7 @@ func (d *UserDao) Updates(user *model.User) error {
return info.Error
}
func (d *UserDao) FindBySn(sn string) (*model.User, error) {
func (d *UserDao) FindBySn(sn int64) (*model.User, error) {
if d.cache != nil {
var user model.User
if ok := d.cache.Get(d.ctx, keyCacheBySn(sn, user.TableName()), &user); ok {
@@ -82,3 +81,18 @@ func (d *UserDao) FindByPhone(phone string) (*model.User, error) {
}
return first, nil
}
// FindByWxUnionIDOrOpenID 通过微信unionID或openID查找用户
func (d *UserDao) FindByWxUnionIDOrOpenID(unionID, openID string) (*model.User, error) {
q := d.query.User.WithContext(d.ctx)
if unionID != "" {
q = q.Where(d.query.User.WxUnionID.Eq(unionID))
} else {
q = q.Where(d.query.User.WxMiniOpenID.Eq(openID))
}
first, err := q.First()
if err != nil {
return nil, err
}
return first, nil
}

View File

@@ -0,0 +1,82 @@
package grpc_server
import (
"context"
"errors"
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/net/http/http_resp"
"git.hlsq.asia/mmorpg/service-common/proto/rs/grpc_pb"
"git.hlsq.asia/mmorpg/service-common/utils"
"git.hlsq.asia/mmorpg/service-user/internal/dao/model"
"git.hlsq.asia/mmorpg/service-user/internal/dao/repository"
"git.hlsq.asia/mmorpg/service-user/internal/wechat"
"gorm.io/gorm"
)
func (s *Server) PhoneLogin(ctx context.Context, req *grpc_pb.PhoneLoginReq) (*grpc_pb.PhoneLoginResp, error) {
userDao := repository.NewUserDao(ctx, s.query, redis.GetCacheClient())
user, err := userDao.FindByPhone(req.Phone)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if user, err = userDao.Create(&model.User{
Phone: req.Phone,
}); err != nil {
return nil, utils.ErrorsWrap(err)
}
user.Name = fmt.Sprintf("user_%v", user.Sn)
_ = userDao.Updates(user)
} else {
return nil, utils.ErrorsWrap(err)
}
}
return &grpc_pb.PhoneLoginResp{
USN: user.Sn,
Name: user.Name,
}, nil
}
func (s *Server) WxMiniLogin(ctx context.Context, req *grpc_pb.WxMiniLoginReq) (*grpc_pb.WxMiniLoginResp, error) {
session, err := wechat.MiniCode2Session(req.Code)
if err != nil {
return nil, utils.ErrorsWrap(err)
}
userDao := repository.NewUserDao(ctx, s.query, redis.GetCacheClient())
user, err := userDao.FindByWxUnionIDOrOpenID(session.UnionID, session.OpenID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if user, err = userDao.Create(&model.User{
WxUnionID: session.UnionID,
WxMiniOpenID: session.OpenID,
}); err != nil {
return nil, utils.ErrorsWrap(err)
}
user.Name = fmt.Sprintf("user_%v", user.Sn)
_ = userDao.Updates(user)
} else {
return nil, utils.ErrorsWrap(err)
}
}
return &grpc_pb.WxMiniLoginResp{
USN: user.Sn,
Name: user.Name,
}, nil
}
func (s *Server) GetUserInfo(ctx context.Context, req *grpc_pb.GetUserInfoReq) (*grpc_pb.GetUserInfoResp, error) {
if !utils.ShouldBindUsn(ctx, &req.USN) {
return nil, utils.ErrorsWrap(http_resp.ParamError)
}
userDao := repository.NewUserDao(ctx, s.query, redis.GetCacheClient())
user, err := userDao.FindBySn(req.USN)
if err != nil {
return nil, utils.ErrorsWrap(err)
}
return &grpc_pb.GetUserInfoResp{
USN: user.Sn,
Name: user.Name,
}, nil
}

View File

@@ -1,11 +0,0 @@
package server
import (
"fmt"
"testing"
)
func TestName(t *testing.T) {
t.Logf("step: %v", fmt.Sprintf("aa %v bb", []string{"1", "2"}))
}

View File

@@ -1,54 +0,0 @@
package server
import (
"context"
"errors"
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/net/http/http_resp"
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
"git.hlsq.asia/mmorpg/service-common/utils"
"git.hlsq.asia/mmorpg/service-user/internal/dao/model"
"git.hlsq.asia/mmorpg/service-user/internal/dao/repository"
"gorm.io/gorm"
)
func (s *Server) Login(ctx context.Context, req *grpc_pb.LoginReq) (*grpc_pb.LoginResp, error) {
userDao := repository.NewUserDao(ctx, redis.GetCacheClient())
user, err := userDao.FindByPhone(req.Phone)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
user = &model.User{
Phone: req.Phone,
}
if err := userDao.Create(user); err != nil {
return nil, err
}
user.Name = fmt.Sprintf("user_%v", user.Sn)
_ = userDao.Updates(user)
} else {
return nil, err
}
}
return &grpc_pb.LoginResp{
USN: user.Sn,
Name: user.Name,
}, nil
}
func (s *Server) GetUserInfo(ctx context.Context, req *grpc_pb.GetUserInfoReq) (*grpc_pb.GetUserInfoResp, error) {
if !utils.ShouldBindUsn(ctx, &req.USN) {
return nil, http_resp.ParamError
}
userDao := repository.NewUserDao(ctx, redis.GetCacheClient())
user, err := userDao.FindBySn(req.USN)
if err != nil {
return nil, err
}
return &grpc_pb.GetUserInfoResp{
USN: user.Sn,
Name: user.Name,
}, nil
}

View File

@@ -1,32 +0,0 @@
package server
import (
"git.hlsq.asia/mmorpg/service-common/discover/common"
"git.hlsq.asia/mmorpg/service-common/net/grpc/service"
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
"google.golang.org/grpc"
)
type Server struct {
grpc_pb.UnimplementedUserServer
service.Base
}
func NewServer(ttl int64) *Server {
s := &Server{
Base: service.Base{
Target: common.KeyDiscoverUser,
EtcdTTL: ttl,
},
}
s.Base.OnInit = s.OnInit
s.Base.OnClose = s.OnClose
return s
}
func (s *Server) OnInit(serve *grpc.Server) {
grpc_pb.RegisterUserServer(serve, s)
}
func (s *Server) OnClose() {
}

View File

@@ -1,156 +0,0 @@
package server
import (
"context"
"encoding/json"
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
"git.hlsq.asia/mmorpg/service-user/internal/ai"
"git.hlsq.asia/mmorpg/service-user/internal/dao/model"
"git.hlsq.asia/mmorpg/service-user/internal/dao/repository"
"time"
)
//var prompt = []string{`
//你是一个微信小游戏的内容策划,请生成 %v 道“每日趣味题”,要求:
//- 避免敏感、争议或超纲内容
//- 每次从 [动物冷知识, 科学趣理, 语言陷阱, 历史轶事, 地理奇观, 数学谜题, 艺术人文, 综合杂学] 中**随机选一个类型**
//- 确保选项有迷惑性,解析有趣
//- 绝对要避免重复,现在的时间是:%v
//- 输出格式为 JSON 数组不要任何解释、不要Markdown、不要任何其他字符
// [{
// "question": "题目文本", // 简洁30字以内
// "options": ["A. 选项1", "B. 选项2", "C. 选项3", "D. 选项4"], // 提供4个选项A/B/C/D其中仅1个正确
// "answer": "C", // 答案
// "explanation": "解析文本", // 200字以内尽量幽默有趣
// "category": "分类", // 只能从上面列出的类型中选择
// "difficulty": 100, // 难度分 0 - 100
// }]
//`}
var prompt = []string{`
你是一个微信小游戏的内容策划,我需要生成“每日趣味题”,要求:
- 避免敏感、争议或超纲内容
- 确保选项有迷惑性,解析有趣
- 绝对要避免重复,现在的时间是:%v
- 这些是我目前的分类:%v
- 输出格式为 JSON 数组不要任何解释、不要Markdown、不要任何其他字符
[{
"question": "题目文本", // 简洁30字以内
"options": ["A. 选项1", "B. 选项2", "C. 选项3", "D. 选项4"], // 提供4个选项A/B/C/D其中仅1个正确
"answer": "C", // 答案
"explanation": "解析文本", // 200字以内尽量幽默有趣
"category": "分类", // 尽量从上述分类中选择,你也可以增加,但是命名风格要类似
"difficulty": 100, // 难度分 0 - 100
}]
如果你准备好了,请回答”好的“,不要有其他任何字符
`, `
请帮我生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`}
type Question struct {
Question string `json:"question"` // 题干
Options []string `json:"options"` // 选项
Answer string `json:"answer"` // 答案
Explanation string `json:"explanation"` // 解析
Category string `json:"category"` // 分类
Difficulty int32 `json:"difficulty"` // 难度分
}
func (s *Server) GenerateQuestion(ctx context.Context, req *grpc_pb.GenerateQuestionReq) (*grpc_pb.GenerateQuestionResp, error) {
category, err := repository.NewQuestionDao(ctx).FindCategory()
if err != nil {
log.Errorf("GenerateQuestion FindCategory error: %v", err)
return nil, err
}
question := make([]*Question, 0)
err = ai.NewAIClient(false, "", 0.9).
RequestAI(
[]string{
fmt.Sprintf(prompt[0], time.Now().Format("2006-01-02 15:04:05"), category),
fmt.Sprintf(prompt[1], req.Num, req.Category),
fmt.Sprintf(prompt[2], req.Num),
fmt.Sprintf(prompt[3], req.Num),
fmt.Sprintf(prompt[4], req.Num),
fmt.Sprintf(prompt[5], req.Num),
},
func(content string, i int) error {
if i == 0 {
return nil
}
step := make([]*Question, 0)
if err := json.Unmarshal([]byte(content), &step); err != nil {
log.Errorf("RequestAI json.Unmarshal error: %v, data: %v", err, content)
return err
}
question = append(question, step...)
return nil
},
)
if err != nil {
log.Errorf("RequestAI error: %v", err)
return nil, err
}
questionDao := repository.NewQuestionDao(ctx, redis.GetCacheClient())
for _, q := range question {
marshal, _ := json.Marshal(q.Options)
if err = questionDao.Create(&model.Question{
Question: q.Question,
Options: string(marshal),
Answer: q.Answer,
Explanation: q.Explanation,
Category: q.Category,
Difficulty: q.Difficulty,
}); err != nil {
log.Errorf("GenerateQuestion Create error: %v", err)
return nil, err
}
}
return nil, nil
}
func (s *Server) GetQuestion(ctx context.Context, req *grpc_pb.GetQuestionReq) (*grpc_pb.GetQuestionResp, error) {
question, err := repository.NewQuestionDao(ctx).FindByRandom()
if err != nil {
log.Errorf("GetQuestion error: %v", err)
return nil, err
}
options := make([]string, 0)
if err = json.Unmarshal([]byte(question.Options), &options); err != nil {
log.Errorf("GetQuestion json.Unmarshal error: %v, data: %v", err, question.Options)
return nil, err
}
return &grpc_pb.GetQuestionResp{
Sn: question.Sn,
Question: question.Question,
Options: options,
}, nil
}
func (s *Server) AnswerQuestion(ctx context.Context, req *grpc_pb.AnswerQuestionReq) (*grpc_pb.AnswerQuestionResp, error) {
question, err := repository.NewQuestionDao(ctx).FindBySn(req.Sn)
if err != nil {
log.Errorf("AnswerQuestion error: %v", err)
return nil, err
}
options := make([]string, 0)
if err = json.Unmarshal([]byte(question.Options), &options); err != nil {
log.Errorf("AnswerQuestion json.Unmarshal error: %v, data: %v", err, question.Options)
return nil, err
}
return &grpc_pb.AnswerQuestionResp{
Answer: question.Answer,
Explanation: question.Explanation,
}, nil
}

View File

@@ -1,161 +0,0 @@
package server
//
//import (
// "bytes"
// "context"
// "encoding/json"
// "git.hlsq.asia/mmorpg/service-common/log"
// "git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
// "io"
// "net/http"
//)
//
//var question = []string{
// "本次对话 数据来源必须:东方财富,巨潮资讯,官网,数据截止:自上市至2025年第3季度\n帮我查询一下京东方科技集团股份有限公司公司的所有财报数量",
// "帮我从东方财富 / 巨潮资讯 / 官网这三个来源整理一下重大事项公告的数量,按照三个维度划分( 并购重组公告披露,关联交易公告,对外投资公告)",
// "帮我从东方财富 / 巨潮资讯 / 官网这三个来源整理一下投资者关系活动,按照三个维度划分( 年度业绩说明次数, 投资者调研次数,接待机构数量)",
// "帮我查询一下ESG与治理的信息各个维度评分评级",
// "帮我查询一下这个公司监管合规信息,综合评估一下本年度监管合规(信披评分,公司治理,内控合规,ESG表现,财务合规,业务运营合规,股东与投资者权益保护合规,合规风险管理)百分制",
// "将本次对话的所有内容总结和完整的装入这个结构体生成json对象数据返回,注意必须以json(markdown代码)的形式返回,并且只输出json即可不用输出其它说明,下面内容就是结构体: \n// CompanyComplianceScore 公司合规评分\ntype CompanyComplianceScore struct {\n\tInformationDisclosureRating string `json:\"informationDisclosureRating\" bson:\"information_disclosure_rating\" comment:\"信息披露评级\"`//获取交易所的信披评级如A/B/C等\n\tRegularReportFrequencyCount *RegularReportFrequency `json:\"regularReportFrequency\" bson:\"regular_report_frequency\" comment:\"定期报告披露频次\"`\n\tMajorAnnouncementCount *MajorAnnouncementCount `json:\"majorAnnouncementCount\" bson:\"major_announcement_count\" comment:\"重大事项公告\"`\n\tInvestorRelationsActivity *InvestorRelationsActivity `json:\"InvestorRelationsActivity\" bson:\"investor_relations_activity\" comment:\"投资者关系活动\"`\n\tEsgReport *EsgReport `json:\"esgReport\" bson:\"esg_report\" comment:\"ESG与治理\"`\n\tDisclosureScore float64 `json:\"disclosureScore\" bson:\"disclosure_score\" comment:\"信息披露专项评分\"`\n\tCorporateGovernanceScore float64 `json:\"corporateGovernanceScore\" bson:\"corporate_governance_score\" comment:\"公司治理评分\"`\n\tInternalControlCompliance float64 `json:\"internalControlCompliance\" bson:\"internal_control_compliance\" comment:\"内控合规评分\"`\n\tEsgPerformanceScore float64 `json:\"esgPerformanceScore\" bson:\"esg_performance_score\" comment:\"ESG表现评分\"`\n\tFinancialComplianceScore float64 `json:\"financialComplianceScore\" bson:\"financial_compliance_score\" comment:\"财务合规评分\"`\n\tBusinessOperationCompliance float64 `json:\"businessOperationCompliance\" bson:\"business_operation_compliance\" comment:\"业务运营合规评分\"`\n\tShareholderRightsCompliance float64 `json:\"shareholderRightsCompliance\" bson:\"shareholder_rights_compliance\" comment:\"股东权益保护合规评分\"`\n\tComplianceRiskManagement float64 `json:\"complianceRiskManagement\" bson:\"compliance_risk_management\" comment:\"合规风险管理评分\"`\n\tOverallComprehensiveScore float64 `json:\"overallComprehensiveScore\" bson:\"overall_comprehensive_score\" comment:\"综合评分\"`\n}\n\n// RegularReportFrequency 定期报告披露频次\ntype RegularReportFrequency struct {\n\tAnnualReportCount int `json:\"annualReportCount\" bson:\"annual_report_count\" comment:\"年报数量\"`\n\tSemiAnnualReportCount int `json:\"semiAnnualReportCount\" bson:\"semi_annual_report_count\" comment:\"半年报数量\"`\n\tQuarterlyReportCount int `json:\"quarterlyReportCount\" bson:\"quarterly_report_count\" comment:\"季度报告数量\"`\n\tTotalReportCount int `json:\"totalReportCount\" bson:\"total_report_count\" comment:\"报告总数\"`\n}\n\n// MajorAnnouncementCount 重大事项公告\ntype MajorAnnouncementCount struct {\n\tMnaAnnouncementCount int `json:\"mnaAnnouncementCount\" bson:\"mna_announcement_count\" comment:\"并购重组公告数量\"`\n\tRelatedTransactionCount int `json:\"relatedTransactionCount\" bson:\"related_transaction_count\" comment:\"关联交易公告数量\"`\n\tForeignInvestmentCount int `json:\"foreignInvestmentCount\" bson:\"foreign_investment_count\" comment:\"对外投资公告数量\"`\n}\n\n// InvestorRelationsActivity 投资者关系活动\ntype InvestorRelationsActivity struct {\n\tAnnualPerformanceBriefings int `json:\"annualPerformanceBriefings\" bson:\"annual_performance_briefings\" comment:\"年度业绩说明次数\"`\n\tInvestorResearchCount int `json:\"investorResearchCount\" bson:\"investor_research_count\" comment:\"投资者调研次数\"`\n\tInstitutionsReceivedCount int `json:\"institutionsReceivedCount\" bson:\"institutions_received_count\" comment:\"接待机构数量\"`\n}\n\n// EsgReport ESG与治理\ntype EsgReport struct {\n\tEsgOverallScore float64 `json:\"esgOverallScore\" bson:\"esg_overall_score\" comment:\"ESG综合评分\"`//通过【上海华证指数信息服务有限公司】披露的公司ESG评级例如BBB不允许返回分数\n\tEnvironmentalScore float64 `json:\"environmentalScore\" bson:\"environmental_score\" comment:\"环境评分\"`\n\tSocialScore float64 `json:\"socialScore\" bson:\"social_score\" comment:\"社会评分\"`\n\tGovernanceScore float64 `json:\"governanceScore\" bson:\"governance_score\" comment:\"治理评分\"`\n}",
//}
//
//type Message struct {
// Role string `json:"role"`
// Content string `json:"content"`
//}
//
//type Input struct {
// Messages []Message `json:"messages"`
//}
//
//type Parameters struct {
// EnableSearch bool `json:"enable_search"`
// ResultFormat string `json:"result_format"`
// SearchOptions SearchOptions `json:"search_options"`
//}
//
//type SearchOptions struct {
// SearchStrategy string `json:"search_strategy"`
//}
//
//type RequestBody struct {
// Model string `json:"model"`
// Input Input `json:"input"`
// Parameters Parameters `json:"parameters"`
//}
//
//type ResponseBody struct {
// Output struct {
// Choices []struct {
// Message Message `json:"message"`
// FinishReason string `json:"finish_reason"`
// } `json:"choices"`
// } `json:"output"`
// Usage struct {
// InputTokens int32 `json:"input_tokens"`
// OutputTokens int32 `json:"output_tokens"`
// TotalTokens int32 `json:"total_tokens"`
// } `json:"usage"`
//}
//
//func (s *Server) GenerateQuestion(ctx context.Context, req *grpc_pb.GenerateQuestionReq) (*grpc_pb.GenerateQuestionResp, error) {
// inToken, outToken := int32(0), int32(0)
//
// messages := make([]Message, 0)
// for i, step := range question {
// messages = append(messages, newUserMessage(step))
//
// //chatCompletion, err := client.Chat.Completions.New(
// // context.Background(), openai.ChatCompletionNewParams{
// // Messages: messages,
// // Model: "qwen3-max",
// // },
// //)
// //if err != nil {
// // return nil, err
// //}
// r, err := request(messages)
// if err != nil {
// return nil, err
// }
// inToken += r.Usage.InputTokens
// outToken += r.Usage.OutputTokens
// log.Infof("回答 %v%v", i, r)
// //break
// messages = append(messages, r.Output.Choices[0].Message)
//
// //log.Infof("回答 %v%v", i, chatCompletion.Choices[0].Message.Content)
// //messages = append(messages, openai.AssistantMessage(chatCompletion.Choices[0].Message.Content))
// }
// log.Infof("返回:%v", messages[len(messages)-1].Content)
// //log.Infof("消耗token%v %v, 费用:%v", inToken, outToken, float64(inToken)/1000*0.0032+float64(outToken)/1000*0.0128)
// log.Infof("消耗token%v %v, 费用:%v", inToken, outToken, float64(inToken)/1000*0.002+float64(outToken)/1000*0.003)
//
// //chatCompletion, err := client.Chat.Completions.New(
// // context.Background(), openai.ChatCompletionNewParams{
// // Messages: []openai.ChatCompletionMessageParamUnion{
// // openai.UserMessage("你能做什么"),
// // },
// // Model: "qwen3-max",
// // },
// //)
// //if err != nil {
// // return nil, err
// //}
// //for i, choice := range chatCompletion.Choices {
// // log.Infof("chatCompletion %v: %#+v \n", i, choice)
// //}
// //log.Infof("返回:%v", chatCompletion.Choices[0].Message.Content)
// return nil, nil
//}
//
//func newUserMessage(content string) Message {
// return Message{
// Role: "user",
// Content: content,
// }
//}
//
//func request(messages []Message) (*ResponseBody, error) {
// client := &http.Client{}
// requestBody := RequestBody{
// //Model: "qwen3-max",
// Model: "deepseek-v3.2",
// Input: Input{
// Messages: messages,
// },
// Parameters: Parameters{
// EnableSearch: true,
// SearchOptions: SearchOptions{
// SearchStrategy: "max",
// },
//
// ResultFormat: "message",
// },
// }
// jsonData, _ := json.Marshal(requestBody)
//
// req, err := http.NewRequest("POST", "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", bytes.NewBuffer(jsonData))
// if err != nil {
// return nil, err
// }
// req.Header.Set("Authorization", "Bearer "+"sk-4daf94ad2fa94288b198d2a1d8924cef")
// req.Header.Set("Content-Type", "application/json")
//
// resp, err := client.Do(req)
// if err != nil {
// return nil, err
// }
// defer resp.Body.Close()
//
// body, err := io.ReadAll(resp.Body)
// if err != nil {
// return nil, err
// }
// var res ResponseBody
// if err = json.Unmarshal(body, &res); err != nil {
// return nil, err
// }
// return &res, nil
//}

View File

@@ -0,0 +1,43 @@
package grpc_server
import (
"git.hlsq.asia/mmorpg/service-common/config"
"git.hlsq.asia/mmorpg/service-common/discover/common"
"git.hlsq.asia/mmorpg/service-common/net/grpc/service"
"git.hlsq.asia/mmorpg/service-common/proto/rs/grpc_pb"
"git.hlsq.asia/mmorpg/service-user/internal/dao/query"
"git.hlsq.asia/mmorpg/service-user/internal/dao/repository"
"google.golang.org/grpc"
)
type Server struct {
grpc_pb.UnimplementedUserServer
service.Base
query *query.Query
}
func NewServer(cfg *config.GrpcConfig) *Server {
s := &Server{
Base: service.Base{
Target: common.KeyDiscoverUser,
ServiceName: common.KeyDiscoverServiceNameUser,
Cfg: cfg,
},
}
s.Base.OnCustomGrpcServerOption = s.OnCustomGrpcServerOption
s.Base.OnInit = s.OnInit
s.Base.OnClose = s.OnClose
return s
}
func (s *Server) OnCustomGrpcServerOption() []grpc.ServerOption {
return nil
}
func (s *Server) OnInit(serve *grpc.Server) {
grpc_pb.RegisterUserServer(serve, s)
s.query = repository.Query()
}
func (s *Server) OnClose() {
}

View File

@@ -1,84 +0,0 @@
package stream_client
import (
"context"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/net/grpc/service"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
"strconv"
"sync"
)
type GatewayFun int
const (
FunToClient GatewayFun = iota
)
var gatewayServer sync.Map // map[string]*gatewayStream
type gatewayStream struct {
mu sync.Mutex
stream grpc.ClientStream
}
func findGatewayBySID(sid string, fun GatewayFun) (*gatewayStream, error) {
key := gatewayKey(sid, fun)
if v, ok := gatewayServer.Load(key); ok {
return v.(*gatewayStream), nil
}
client, err := service.GatewayNewClient(sid)
if err != nil {
log.Errorf("findGatewayBySID cannot find client: %v", err)
return nil, err
}
var stream grpc.ClientStream
switch fun {
case FunToClient:
stream, err = client.ToClient(context.Background())
}
if err != nil {
log.Errorf("findGatewayBySID %v err: %v, sid: %v", fun, err, sid)
return nil, err
}
ss := &gatewayStream{stream: stream}
if actual, loaded := gatewayServer.LoadOrStore(key, ss); loaded {
go func() { _ = stream.CloseSend() }()
return actual.(*gatewayStream), nil
}
return ss, nil
}
func SendMessageToGateway(sid string, fun GatewayFun, msg proto.Message, re ...bool) error {
ss, err := findGatewayBySID(sid, fun)
if err != nil {
return err
}
ss.mu.Lock()
err = ss.stream.SendMsg(msg)
ss.mu.Unlock()
if err != nil {
key := gatewayKey(sid, fun)
if v, ok := gatewayServer.Load(key); ok && v == ss {
gatewayServer.Delete(key)
_ = ss.stream.CloseSend()
}
// 如果没有标识本次是重试的,就重试一次(默认重试)
if re == nil || !re[0] {
return SendMessageToGateway(sid, fun, msg, true)
}
return err
}
return nil
}
func gatewayKey(sid string, fun GatewayFun) string {
return sid + "-" + strconv.Itoa(int(fun))
}

29
internal/wechat/mini.go Normal file
View File

@@ -0,0 +1,29 @@
package wechat
import (
"errors"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-user/config"
"net/http"
"net/url"
)
// MiniCode2Session 根据code获取openID
func MiniCode2Session(code string) (*Code2SessionResp, error) {
values := &url.Values{}
values.Set("appid", config.Get().WxMini.AppID)
values.Set("secret", config.Get().WxMini.Secret)
values.Set("js_code", code)
values.Set("grant_type", "authorization_code")
resp := &Code2SessionResp{}
err := RequestWechatMini("/sns/jscode2session", http.MethodGet, values, nil, resp)
if err != nil {
return nil, err
}
if resp.ErrCode != ErrorCodeOK {
log.Errorf("[WechatMini] MiniCode2Session err: response.Code = %v, msg: %v, req: %v", resp.ErrCode, resp.ErrMsg, values.Encode())
return nil, errors.New(resp.ErrMsg)
}
return resp, nil
}

View File

@@ -0,0 +1,54 @@
package wechat
type ResponseBase struct {
ErrCode int32 `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
type GetAccessTokenResp struct {
ResponseBase
AccessToken string `json:"access_token"`
ExpiresIn int32 `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
OpenID string `json:"openid"`
Scope string `json:"scope"`
UnionID string `json:"unionid"`
}
type GetUserInfoResp struct {
ResponseBase
NickName string `json:"nickname"`
HeadImgURL string `json:"headimgurl"`
UnionID string `json:"unionid"`
}
type Code2SessionResp struct {
ResponseBase
OpenID string `json:"openid"`
UnionID string `json:"unionid"`
}
type GetUserPhoneNumberResp struct {
ResponseBase
PhoneInfo *struct {
CountryCode string `json:"countryCode"`
PurePhoneNumber string `json:"purePhoneNumber"`
} `json:"phone_info"`
}
type GenerateSchemeResp struct {
ResponseBase
OpenLink string `json:"openlink"`
}
type GenerateURLLinkReq struct {
Path string `json:"path"` // 小程序页面路径
Query string `json:"query"` // 参数
ExpireTime int64 `json:"expire_time"` // 失效间隔时间
EnvVersion string `json:"env_version"` // 版本
}
type GenerateURLLinkResp struct {
ResponseBase
UrlLink string `json:"url_link"`
}

View File

@@ -0,0 +1,58 @@
package wechat
import (
"bytes"
"encoding/json"
"errors"
"git.hlsq.asia/mmorpg/service-common/log"
"io"
"net/http"
"net/url"
"time"
)
type ErrorCode int32
const (
ErrorCodeOK = 0
)
func RequestWechatMini(path string, method string, params *url.Values, values []byte, response any) error {
u := &url.URL{}
u.Scheme = "https"
u.Host = "api.weixin.qq.com"
u.Path = path
client := &http.Client{Timeout: 10 * time.Second}
if params != nil {
u.RawQuery = params.Encode()
}
var resp *http.Response
var err error
if method == http.MethodGet {
resp, err = client.Get(u.String())
} else {
resp, err = client.Post(u.String(), "application/json", bytes.NewBuffer(values))
}
if err != nil {
log.Errorf("[WechatMini] %v err: %v", path, err)
return err
}
if resp.StatusCode != http.StatusOK {
log.Errorf("[WechatMini] %v err: resp.StatusCode = %v", path, resp.StatusCode)
return errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Errorf("[WechatMini] %v err: %v", path, err)
return err
}
err = json.Unmarshal(body, response)
if err != nil {
log.Errorf("[WechatMini] %v err: %v", path, err)
return err
}
return nil
}