From 9968887665618894bb8c7d9e4539cac181d0c974 Mon Sep 17 00:00:00 2001 From: kanade Date: Wed, 19 Nov 2025 14:05:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(ik3cloud):=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=9F=BA=E7=A1=80=E9=85=8D=E7=BD=AE=E4=B8=8E?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 .gitignore 忽略规则 - 实现应用配置加载与管理逻辑 - 添加默认配置文件 app.ini - 配置 Gitea CI/CD 工作流用于构建和部署 - 实现金蝶云客户端初始化功能 - 添加 RPC 插件支持 Consul 注册中心 - 实现部门数据获取及树形结构处理逻辑 - 添加通用工具函数库 - 初始化 Go 模块依赖管理 - 创建 Dockerfile 用于服务容器化部署 --- .gitea/workflows/build.yaml | 39 +++ .gitea/workflows/buildProd.yaml | 39 +++ .gitignore | 10 + Dockerfile | 7 + app/common/function.go | 338 ++++++++++++++++++++++++ app/config/app.go | 90 +++++++ app/config/ik3cloud.go | 11 + app/config/log.go | 12 + app/config/page.go | 7 + app/config/server.go | 14 + app/controller/department.go | 17 ++ app/controller/staff.go | 21 ++ app/lib/ik3cloud/client.go | 39 +++ app/lib/logger/logger.go | 152 +++++++++++ app/lib/rpcplugin/consul.go | 291 ++++++++++++++++++++ app/logic/department.go | 68 +++++ app/logic/staff.go | 101 +++++++ app/router/router.go | 19 ++ client/rpc/main.go | 71 +++++ config/app.ini | 32 +++ go.mod | 76 ++++++ go.sum | 452 ++++++++++++++++++++++++++++++++ init.go | 110 ++++++++ 23 files changed, 2016 insertions(+) create mode 100644 .gitea/workflows/build.yaml create mode 100644 .gitea/workflows/buildProd.yaml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 app/common/function.go create mode 100644 app/config/app.go create mode 100644 app/config/ik3cloud.go create mode 100644 app/config/log.go create mode 100644 app/config/page.go create mode 100644 app/config/server.go create mode 100644 app/controller/department.go create mode 100644 app/controller/staff.go create mode 100644 app/lib/ik3cloud/client.go create mode 100644 app/lib/logger/logger.go create mode 100644 app/lib/rpcplugin/consul.go create mode 100644 app/logic/department.go create mode 100644 app/logic/staff.go create mode 100644 app/router/router.go create mode 100644 client/rpc/main.go create mode 100644 config/app.ini create mode 100644 go.mod create mode 100644 go.sum create mode 100644 init.go diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..537caf3 --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,39 @@ +name: Go +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_PAT }} + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + - name: Update service + run: go get git.kumo.work/shama/service + - name: Build + run: GOPROXY=https://goproxy.cn GOSUMDB=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --tags netgo -ldflags '-w -s' -o bin/server client/rpc/main.go + + - name: Log in to Docker + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + registry: hub.kumo.work + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: hub.kumo.work/erp/ik3cloud:latest + + - name: webhook 101.34.58.98:9000 + run: curl -X POST http://101.34.58.98:9000/api/webhooks/6975b2a4-f99b-4862-8292-91744a3790ea diff --git a/.gitea/workflows/buildProd.yaml b/.gitea/workflows/buildProd.yaml new file mode 100644 index 0000000..f663241 --- /dev/null +++ b/.gitea/workflows/buildProd.yaml @@ -0,0 +1,39 @@ +name: Go +on: + push: + branches: + - prod + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_PAT }} + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + - name: Update service + run: go get git.kumo.work/shama/service + - name: Build + run: GOPROXY=https://goproxy.cn GOSUMDB=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --tags netgo -ldflags '-w -s' -o bin/server client/rpc/main.go + + - name: Log in to Docker + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + registry: hub.kumo.work + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: hub.kumo.work/erp/ik3cloud:prod + + - name: webhook + run: curl -X POST ${{ secrets.WEBHOOK_IK3CLOUD_URL }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..08f0fc2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.idea +*_test.go +app.dev.ini +app.local.ini +bin/ +log/ +main_test.go +.DS_Store +go.work* +service \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a8da27a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM hub.kumo.work/alpine +# 拷贝编译结果到当前镜像中 +COPY ./bin/server / +# 拷贝配置文件 +COPY ./config/app.ini /data/config/app.ini +WORKDIR /data +ENTRYPOINT ["/server"] \ No newline at end of file diff --git a/app/common/function.go b/app/common/function.go new file mode 100644 index 0000000..3367187 --- /dev/null +++ b/app/common/function.go @@ -0,0 +1,338 @@ +package common + +import ( + "bytes" + "crypto/md5" + "encoding/hex" + "io" + "math/rand" + "net/http" + "os" + "path/filepath" + "reflect" + "regexp" + "strings" + "time" + + "github.com/shopspring/decimal" + "golang.org/x/text/encoding/simplifiedchinese" + "golang.org/x/text/transform" +) + +// @Title 随机数种子 +func init() { + // 随机数种子 + rand.Seed(time.Now().UnixNano()) +} + +// MD5 @Title md5加密 +func MD5(str string) string { + h := md5.New() + h.Write([]byte(str)) + return hex.EncodeToString(h.Sum(nil)) +} + +// RandStr @Title 生成随机数 +func RandStr(n int, str ...string) string { + s := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + if len(str) > 0 { + s = str[0] + } + res := "" + for i := 0; i < n; i++ { + res += string(s[rand.Intn(len(s))]) + } + return res +} + +// InArray @Title 是否在数组中 +func InArray[T comparable](need T, array []T) bool { + for _, item := range array { + if item == need { + return true + } + } + return false +} + +// CreateDateDir 根据当前日期来创建文件夹 +func CreateDateDir(Path string) string { + folderName := time.Now().Format("20060102") + folderPath := filepath.Join(Path, folderName) + if _, err := os.Stat(folderPath); os.IsNotExist(err) { + os.MkdirAll(folderPath, 0755) + } + return folderName +} + +// DownloadFormUrl @Title 下载文件 +func DownloadFormUrl(src string, filename string) error { + res, err := http.Get(src) + if err != nil { + return err + } + defer res.Body.Close() + // 获得get请求响应的reader对象 + body, err := io.ReadAll(res.Body) + if err != nil { + return err + } + out, err := os.Create(filename) + if err != nil { + return err + } + if _, err := io.Copy(out, bytes.NewReader(body)); err != nil { + return err + } + return nil +} + +// Utf8ToGbk @Title utf8转gbk +func Utf8ToGbk(source string) string { + result, _, _ := transform.String(simplifiedchinese.GBK.NewEncoder(), source) + return result +} + +// GbkToUtf8 @Title gbk转utf8 +func GbkToUtf8(source string) string { + result, _, _ := transform.String(simplifiedchinese.GBK.NewDecoder(), source) + return result +} + +// GetPassword @Title 密码加密 +func GetPassword(password, salt string) string { + return MD5(salt + MD5(password+salt)) +} + +// IsPhone @Title 是否手机号 +func IsPhone(phone string) bool { + return regexp.MustCompile(`^1\d{10}$`).MatchString(phone) +} + +// Equal @TITLE 数据比较 +func Equal[T any](a, b T, fun func(a, b T) bool) bool { + return fun(a, b) +} + +// Ptr @TITLE 返回指针 +func Ptr[T any](data T) *T { + return &data +} + +// Split @TITLE 字符串分隔 +func Split(s, sep string) []string { + if s == "" { + return nil + } + return strings.Split(s, sep) +} + +// PtrData @TITLE 指针数据 +func PtrData[T any](data *T) T { + if data != nil { + return *data + } + return *new(T) +} + +// PtrDecimal @TITLE Decimal比较数据 +func PtrDecimal(a *decimal.Decimal, b *decimal.Decimal) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + return a.Cmp(*b) == 0 +} + +// PtrCmp @TITLE 客户比较数据引用比较 +func PtrCmp[T comparable](a *T, b *T) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + return *a == *b +} + +// DefaultData @TITLE 反射创建默认值 +func DefaultData(data any) any { + var value reflect.Value + if reflect.TypeOf(data).Kind() != reflect.Ptr { + value = reflect.ValueOf(&data).Elem() + } else { + value = reflect.ValueOf(data).Elem() + } + if value.Kind() == reflect.Interface { + value = reflect.New(value.Elem().Type()).Elem() + } + + labels := map[string]string{} + + typeOf := value.Type() + for i := 0; i < typeOf.NumField(); i++ { + field := typeOf.Field(i) + name := field.Name + if field.IsExported() { + if !field.Anonymous { + labels[name] = field.Tag.Get("label") + } else { + name = "" + } + if field.Type.Kind() == reflect.Struct { + _, valueLabels := DefaultValue(value.Field(i), name) + for valueKey, valueLabel := range valueLabels { + labels[valueKey] = valueLabel + } + } + if field.Type.Kind() == reflect.Slice { + newValue := reflect.New(field.Type.Elem()).Elem() + defaultValue, valueLabels := DefaultValue(newValue, name) + for valueKey, valueLabel := range valueLabels { + labels[valueKey] = valueLabel + } + value.Field(i).Set(reflect.Append(value.Field(i), defaultValue)) + } + } + } + return map[string]interface{}{ + "Data": value.Interface(), + "Label": labels, + } +} + +func DefaultValue(value reflect.Value, name string) (reflect.Value, map[string]string) { + typeOf := value.Type() + labels := map[string]string{} + if typeOf.Kind() == reflect.Struct { + for i := 0; i < typeOf.NumField(); i++ { + field := typeOf.Field(i) + fieldName := field.Name + if field.IsExported() { + if !field.Anonymous { + labels[strings.Trim(name+"."+fieldName, ".")] = field.Tag.Get("label") + } else { + fieldName = "" + } + labels[strings.Trim(name+"."+fieldName, ".")] = field.Tag.Get("label") + if field.Type.Kind() == reflect.Struct { + _, valueLabels := DefaultValue(value.Field(i), fieldName) + for valueKey, valueLabel := range valueLabels { + labels[strings.Trim(name+"."+valueKey, ".")] = valueLabel + } + } + if field.Type.Kind() == reflect.Slice { + newValue := reflect.New(field.Type.Elem()).Elem() + defaultValue, valueLabels := DefaultValue(newValue, fieldName) + for valueKey, valueLabel := range valueLabels { + labels[strings.Trim(name+"."+valueKey, ".")] = valueLabel + } + value.Field(i).Set(reflect.Append(value.Field(i), defaultValue)) + } + } + } + } + return value, labels +} + +func wrapIfStruct[T any](data T) T { + v := reflect.ValueOf(data) + if v.Kind() == reflect.Struct { + ptr := reflect.New(v.Type()) + ptr.Elem().Set(v) + return ptr.Interface().(T) + } + return data +} +func DefaultSlice[T any](data T) T { + data = wrapIfStruct(data) + value := reflect.ValueOf(data).Elem() + typeOf := value.Type() + + switch typeOf.Kind() { + case reflect.Struct: + DefaultSliceValue(value) + case reflect.Slice: + if value.IsNil() { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + } + for j := 0; j < value.Len(); j++ { + DefaultSliceValue(value.Index(j)) + } + } + + if reflect.TypeOf(data).Kind() != reflect.Ptr { + return value.Interface().(T) + } else { + return value.Addr().Interface().(T) + } +} + +func DefaultSliceValue(value reflect.Value) reflect.Value { + typeOf := value.Type() + if typeOf.Kind() == reflect.Struct { + for i := 0; i < typeOf.NumField(); i++ { + DefaultSliceType(value.Field(i)) + } + } + return value +} +func DefaultSliceType(value reflect.Value) reflect.Value { + switch value.Type().Kind() { + case reflect.Ptr: + if !value.IsNil() { + DefaultSliceType(value.Elem()) + } else { + valueType := value.Type().Elem() + if valueType.Kind() == reflect.Slice { + slice := reflect.MakeSlice(valueType, 0, 0) + ptr := reflect.New(valueType) + ptr.Elem().Set(slice) + value.Set(ptr) + } + } + case reflect.Struct: + DefaultSliceValue(value) + case reflect.Slice: + if value.IsNil() { + if value.CanSet() { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + } + } + for j := 0; j < value.Len(); j++ { + DefaultSliceValue(value.Index(j)) + } + } + return value +} + +// Unique @Title 去重 +func Unique[T comparable](array []T) (result []T) { + for _, item := range array { + if !InArray(item, result) { + result = append(result, item) + } + } + return +} + +// InsertSorted @TITLE array插入排序 +func InsertSorted[T any](array []T, value T, comp func(int) bool) []T { + i, j := 0, len(array) + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if !comp(h) { + i = h + 1 // preserves f(i-1) == false + } else { + j = h // preserves f(j) == true + } + } + // 插入:保持有序 + array = append(array, value) // 增加一个空位 + copy(array[i+1:], array[i:]) // 后移 + array[i] = value // 插入值 + return array +} diff --git a/app/config/app.go b/app/config/app.go new file mode 100644 index 0000000..513ab35 --- /dev/null +++ b/app/config/app.go @@ -0,0 +1,90 @@ +package config + +import ( + "fmt" + "log" + "os" + "path/filepath" + + "gopkg.in/ini.v1" +) + +var Config = &App{} + +type App struct { + iniLoader *ini.File + initConfig *IniConfig + Debug bool `ini:"debug"` + Log Log `ini:"log"` + Server Server `ini:"server"` + Ik3cloud Ik3cloud `ini:"ik3cloud"` + Page Page `ini:"page"` +} +type IniConfig struct { + ConfigPath string + ConfigName string + RunModelName string + RunModel string + RunModelErrAllow bool // 允许不使用拓展配置文件 +} + +// InitConfig @TITLE 初始化配置 +func InitConfig(config *IniConfig) { + if config.ConfigName == "" { + config.ConfigName = "app.ini" + } + // 读取配置文件 + load, err := ini.Load(filepath.Join(config.ConfigPath, config.ConfigName)) + if err != nil { + log.Fatal("配置文件读取错误,err:", err) + return + } + // 环境配置 + if config.RunModel == "" { + config.RunModel = os.Getenv("RunModel") + if config.RunModel == "" { + config.RunModel = load.Section("").Key("defaultModel").String() + if config.RunModel == "" { + config.RunModel = "test" + } + } + } + if config.RunModelName == "" { + config.RunModelName = fmt.Sprintf("app.%s.ini", config.RunModel) + } + if err := load.Append(filepath.Join(config.ConfigPath, config.RunModelName)); err != nil { + if config.RunModelErrAllow { + log.Println("环境配置文件读取错误,err:", err) + } else { + log.Fatal("环境配置文件读取错误,err:", err) + } + } + // 运行配置 + load.Append(filepath.Join(config.ConfigPath, "app.run.ini")) + // 映射配置 + if err := load.MapTo(Config); err != nil { + log.Fatal("配置文件映射错误,err:", err) + return + } + Config.iniLoader = load + Config.initConfig = config +} + +// SetConfig @Title 写入配置 +func (a *App) SetConfig(section, name, value string) error { + runConfig := filepath.Join(Config.initConfig.ConfigPath, "app.run.ini") + load, err := ini.LooseLoad(runConfig) + if err != nil { + return err + } + load.Section(section).Key(name).SetValue(value) + load.SaveTo(runConfig) + Config.iniLoader.Reload() + Config.iniLoader.MapTo(Config) + return nil +} + +// GetRunModel @Title 获取RunModel +func (a *App) GetRunModel() string { + return a.initConfig.RunModel +} diff --git a/app/config/ik3cloud.go b/app/config/ik3cloud.go new file mode 100644 index 0000000..d4fe557 --- /dev/null +++ b/app/config/ik3cloud.go @@ -0,0 +1,11 @@ +package config + +type Ik3cloud struct { + Host string `ini:"host"` // 接口地址 + AccountId string `ini:"accountId"` // 账套ID + Username string `ini:"username"` // 用户名 + AppId string `ini:"appId"` // 应用ID + AppSecret string `ini:"appSecret"` // 应用秘钥 + LanguageId string `ini:"languageId"` // 语言ID + OrganizationNumber string `ini:"organizationNumber"` // 组织编码 +} diff --git a/app/config/log.go b/app/config/log.go new file mode 100644 index 0000000..3044e4b --- /dev/null +++ b/app/config/log.go @@ -0,0 +1,12 @@ +package config + +type Log struct { + Director string `ini:"director"` + Levels []int64 `ini:"levels"` + ShowLine bool `ini:"showLine"` + LogInConsole bool `ini:"logInConsole"` + Prefix string `ini:"prefix"` + MaxAge int `ini:"maxAge"` + MaxSize int `ini:"maxSize"` + MaxBackups int `ini:"maxBackups"` +} diff --git a/app/config/page.go b/app/config/page.go new file mode 100644 index 0000000..7868f28 --- /dev/null +++ b/app/config/page.go @@ -0,0 +1,7 @@ +package config + +type Page struct { + MaxLimit int `ini:"maxLimit"` + MinLimit int `ini:"minLimit"` + DefaultLimit int `ini:"defaultLimit"` +} diff --git a/app/config/server.go b/app/config/server.go new file mode 100644 index 0000000..e94dc7e --- /dev/null +++ b/app/config/server.go @@ -0,0 +1,14 @@ +package config + +type Server struct { + RegistryServer []string `ini:"registryServer"` + Addr string `ini:"addr"` + Host string `ini:"host"` + Port uint `ini:"port"` + BasePath string `ini:"basePath"` + FilePath string `ini:"filePath"` + WorkerId int64 `ini:"workerId"` + Segment string `ini:"segment"` + YzmExpiry int `ini:"yzmExpiry"` + YzmRate int `ini:"yzmRate"` +} diff --git a/app/controller/department.go b/app/controller/department.go new file mode 100644 index 0000000..ea6f82a --- /dev/null +++ b/app/controller/department.go @@ -0,0 +1,17 @@ +package controller + +import ( + "context" + "ik3cloud/app/logic" + + "git.kumo.work/shama/service/ik3cloud" +) + +type Department struct { +} + +// All @TITLE 获取部门 +func (d *Department) All(ctx context.Context, args int, reply *[]ik3cloud.DepartmentItem) (err error) { + *reply, err = logic.DepartmentLogic.All() + return err +} diff --git a/app/controller/staff.go b/app/controller/staff.go new file mode 100644 index 0000000..27af7bf --- /dev/null +++ b/app/controller/staff.go @@ -0,0 +1,21 @@ +package controller + +import ( + "context" + "ik3cloud/app/logic" + + "git.kumo.work/shama/service/ik3cloud" +) + +type Staff struct { +} + +// List @TITLE 员工列表 +func (s *Staff) List(ctx context.Context, args ik3cloud.ArgsStaffList, reply *ik3cloud.ReplyStaffList) error { + list, total, err := logic.StaffLogic.List(args.Page, args.Search) + *reply = ik3cloud.ReplyStaffList{ + List: list, + Total: total, + } + return err +} diff --git a/app/lib/ik3cloud/client.go b/app/lib/ik3cloud/client.go new file mode 100644 index 0000000..bd7ad29 --- /dev/null +++ b/app/lib/ik3cloud/client.go @@ -0,0 +1,39 @@ +package ik3cloud + +import ( + "github.com/deep-project/kingdee" + "github.com/deep-project/kingdee/adapters" + client2 "github.com/deep-project/kingdee/pkg/client" +) + +var Client = &client{} + +type client struct { + config *Config + *client2.Client +} + +type Config struct { + Host string // 接口地址 + AccountId string // 账套ID + Username string // 用户名 + AppId string // 应用ID + AppSecret string // 应用秘钥 + LanguageId string // 语言ID +} + +func InitClient(config *Config) (*client, error) { + var err error + Client.Client, err = kingdee.New(config.Host, &adapters.LoginBySign{ + AccountID: config.AccountId, + Username: config.Username, + AppID: config.AppId, + AppSecret: config.AppSecret, + LanguageID: config.LanguageId, + }) + if err != nil { + return nil, err + } + Client.config = config + return Client, nil +} diff --git a/app/lib/logger/logger.go b/app/lib/logger/logger.go new file mode 100644 index 0000000..1832e94 --- /dev/null +++ b/app/lib/logger/logger.go @@ -0,0 +1,152 @@ +package logger + +import ( + "io" + "os" + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const ( + // DebugLevel logs are typically voluminous, and are usually disabled in + // production. + DebugLevel = zapcore.DebugLevel + // InfoLevel is the default logging priority. + InfoLevel = zapcore.InfoLevel + // WarnLevel logs are more important than Info, but don't need individual + // human review. + WarnLevel = zapcore.WarnLevel + // ErrorLevel logs are high-priority. If an application is running smoothly, + // it shouldn't generate any error-level logs. + ErrorLevel = zapcore.ErrorLevel + // DPanicLevel logs are particularly important errors. In development the + // logger panics after writing the message. + DPanicLevel = zapcore.DPanicLevel + // PanicLevel logs a message, then panics. + PanicLevel = zapcore.PanicLevel + // FatalLevel logs a message, then calls os.Exit(1). + FatalLevel = zapcore.FatalLevel +) + +var ( + Logger = &logger{} + + LowercaseLevelEncoder = zapcore.LowercaseLevelEncoder + LowercaseColorLevelEncoder = zapcore.LowercaseColorLevelEncoder + CapitalLevelEncoder = zapcore.CapitalLevelEncoder + CapitalColorLevelEncoder = zapcore.CapitalColorLevelEncoder +) + +type logger struct { + *zap.Logger + Config *LoggerConfig + hasShowLine bool +} + +type LoggerConfig struct { + Levels []zapcore.Level `json:"level"` + ShowLine bool `json:"showLine"` + LogInConsole bool `json:"logInConsole"` + Format string `json:"format"` + EncodeLevel zapcore.LevelEncoder `json:"encodeLevel"` + Prefix string `json:"prefix"` + Writer func(config *LoggerConfig, filename string, level zapcore.Level) io.Writer +} + +// InitLogger @Title 初始化日志工具 +func InitLogger(config *LoggerConfig) *logger { + Logger.Config = config + + Logger.Logger = zap.New(zapcore.NewTee( + Logger.getEncoderCore("debug", zapcore.DebugLevel), + Logger.getEncoderCore("info", zapcore.InfoLevel), + Logger.getEncoderCore("Warn", zapcore.WarnLevel), + Logger.getEncoderCore("error", zapcore.ErrorLevel), + ), zap.AddCaller()) + if config.ShowLine { + Logger.Logger = Logger.Logger.WithOptions(zap.AddCaller()) + } + return Logger +} + +// getEncoderConfig 获取zapcore.EncoderConfig +func (l *logger) getEncoderConfig() (config zapcore.EncoderConfig) { + config = zapcore.EncoderConfig{ + MessageKey: "message", + LevelKey: "level", + TimeKey: "time", + NameKey: "logger", + CallerKey: "caller", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: l.Config.EncodeLevel, + EncodeTime: l.CustomTimeEncoder, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.FullCallerEncoder, + } + if config.EncodeLevel == nil { + config.EncodeLevel = zapcore.LowercaseLevelEncoder + } + return config +} + +// getEncoder 获取zapcore.Encoder +func (l *logger) getEncoder() zapcore.Encoder { + if l.Config.Format == "json" { + return zapcore.NewJSONEncoder(l.getEncoderConfig()) + } + return zapcore.NewConsoleEncoder(l.getEncoderConfig()) +} + +// getEncoderCore 获取Encoder的zapcore.Core +func (l *logger) getEncoderCore(filename string, level zapcore.Level) (core zapcore.Core) { + return zapcore.NewCore(l.getEncoder(), l.getWriteSyncer(filename, level), zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return l.inLevel(level) && lvl >= level + })) +} + +func (l *logger) inLevel(level zapcore.Level) bool { + for _, cLevel := range l.Config.Levels { + if cLevel == level { + return true + } + } + return false +} + +// CustomTimeEncoder 自定义日志输出时间格式 +func (l *logger) CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format(l.Config.Prefix + "2006/01/02 - 15:04:05.000")) +} + +// @author: [piexlmax](https://github.com/piexlmax) +// @function: PathExists +// @description: 文件目录是否存在 +// @param: path string +// @return: bool, error +func (l *logger) pathExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +func (l *logger) getWriteSyncer(filename string, level zapcore.Level) zapcore.WriteSyncer { + var fileWriter io.Writer + // 日志切割 + if l.Config.Writer != nil { + fileWriter = l.Config.Writer(l.Config, filename, level) + } else { + return zapcore.AddSync(os.Stdout) + } + if l.Config.LogInConsole && !l.hasShowLine && l.inLevel(level) { + l.hasShowLine = true + return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(fileWriter)) + } + return zapcore.AddSync(fileWriter) +} diff --git a/app/lib/rpcplugin/consul.go b/app/lib/rpcplugin/consul.go new file mode 100644 index 0000000..71bd392 --- /dev/null +++ b/app/lib/rpcplugin/consul.go @@ -0,0 +1,291 @@ +package rpcplugin + +import ( + "context" + "errors" + "fmt" + "net" + "net/url" + "strings" + "sync" + "time" + + metrics "github.com/rcrowley/go-metrics" + "github.com/rpcxio/libkv" + "github.com/rpcxio/libkv/store" + "github.com/rpcxio/libkv/store/consul" + "github.com/smallnest/rpcx/log" +) + +func init() { + consul.Register() +} + +// ConsulRegisterPlugin implements consul registry. +type ConsulRegisterPlugin struct { + // service address, for example, tcp@127.0.0.1:8972, quic@127.0.0.1:1234 + ServiceAddress string + // consul addresses + ConsulServers []string + // base path for rpcx server, for example com/example/rpcx + BasePath string + Metrics metrics.Registry + // Registered services + Services []string + metasLock sync.RWMutex + metas map[string]string + UpdateInterval time.Duration + + Options *store.Config + kv store.Store + + dying chan struct{} + done chan struct{} +} + +// Start starts to connect consul cluster +func (p *ConsulRegisterPlugin) Start() error { + if p.done == nil { + p.done = make(chan struct{}) + } + if p.dying == nil { + p.dying = make(chan struct{}) + } + + if p.kv == nil { + kv, err := libkv.NewStore(store.CONSUL, p.ConsulServers, p.Options) + if err != nil { + log.Errorf("cannot create consul registry: %v", err) + close(p.done) + return err + } + p.kv = kv + } + + if p.BasePath[0] == '/' { + p.BasePath = p.BasePath[1:] + } + + err := p.kv.Put(p.BasePath, []byte("rpcx_path"), &store.WriteOptions{IsDir: true}) + if err != nil { + log.Errorf("cannot create consul path %s: %v", p.BasePath, err) + close(p.done) + return err + } + + if p.UpdateInterval > 0 { + go func() { + ticker := time.NewTicker(p.UpdateInterval) + + defer ticker.Stop() + defer p.kv.Close() + + // refresh service TTL + for { + select { + case <-p.dying: + close(p.done) + return + case <-ticker.C: + extra := make(map[string]string) + if p.Metrics != nil { + extra["calls"] = fmt.Sprintf("%.2f", metrics.GetOrRegisterMeter("calls", p.Metrics).RateMean()) + extra["connections"] = fmt.Sprintf("%.2f", metrics.GetOrRegisterMeter("connections", p.Metrics).RateMean()) + } + + //set this same metrics for all services at this server + for _, name := range p.Services { + nodePath := fmt.Sprintf("%s/%s/%s", p.BasePath, name, p.ServiceAddress) + kvPaire, err := p.kv.Get(nodePath) + if err != nil { + log.Warnf("can't get data of node: %s, will re-create, because of %v", nodePath, err.Error()) + + p.metasLock.RLock() + meta := p.metas[name] + p.metasLock.RUnlock() + + err = p.kv.Put(nodePath, []byte(meta), &store.WriteOptions{TTL: p.UpdateInterval * 2}) + if err != nil { + log.Errorf("cannot re-create consul path %s: %v", nodePath, err) + } + } else { + v, _ := url.ParseQuery(string(kvPaire.Value)) + for key, value := range extra { + v.Set(key, value) + } + _ = p.kv.Put(nodePath, []byte(v.Encode()), &store.WriteOptions{TTL: p.UpdateInterval * 2}) + } + } + } + } + }() + } + + return nil +} + +// Stop unregister all services. +func (p *ConsulRegisterPlugin) Stop() error { + if p.kv == nil { + kv, err := libkv.NewStore(store.CONSUL, p.ConsulServers, p.Options) + if err != nil { + log.Errorf("cannot create consul registry: %v", err) + return err + } + p.kv = kv + } + + if p.BasePath[0] == '/' { + p.BasePath = p.BasePath[1:] + } + + for _, name := range p.Services { + nodePath := fmt.Sprintf("%s/%s/%s", p.BasePath, name, p.ServiceAddress) + exist, err := p.kv.Exists(nodePath) + if err != nil { + log.Errorf("cannot delete path %s: %v", nodePath, err) + continue + } + if exist { + _ = p.kv.Delete(nodePath) + log.Infof("delete path %s", nodePath, err) + } + } + + close(p.dying) + <-p.done + return nil +} + +// HandleConnAccept handles connections from clients +func (p *ConsulRegisterPlugin) HandleConnAccept(conn net.Conn) (net.Conn, bool) { + if p.Metrics != nil { + metrics.GetOrRegisterMeter("connections", p.Metrics).Mark(1) + } + return conn, true +} + +// PreCall handles rpc call from clients +func (p *ConsulRegisterPlugin) PreCall(_ context.Context, _, _ string, args interface{}) (interface{}, error) { + if p.Metrics != nil { + metrics.GetOrRegisterMeter("calls", p.Metrics).Mark(1) + } + return args, nil +} + +// Register handles registering event. +// this service is registered at BASE/serviceName/thisIpAddress node +func (p *ConsulRegisterPlugin) Register(name string, rcvr interface{}, metadata string) (err error) { + if strings.TrimSpace(name) == "" { + err = errors.New("Register service `name` can't be empty") + return + } + + if p.kv == nil { + consul.Register() + kv, err := libkv.NewStore(store.CONSUL, p.ConsulServers, nil) + if err != nil { + log.Errorf("cannot create consul registry: %v", err) + return err + } + p.kv = kv + } + + if p.BasePath[0] == '/' { + p.BasePath = p.BasePath[1:] + } + err = p.kv.Put(p.BasePath, []byte("rpcx_path"), &store.WriteOptions{IsDir: true}) + if err != nil { + log.Errorf("cannot create consul path %s: %v", p.BasePath, err) + return err + } + + //nodePath := fmt.Sprintf("%s/%s", p.BasePath, name) + //err = p.kv.Put(nodePath, []byte(name), &store.WriteOptions{IsDir: true}) + //if err != nil { + // log.Errorf("cannot create consul path %s: %v", nodePath, err) + // return err + //} + + nodePath := fmt.Sprintf("%s/%s/%s", p.BasePath, name, p.ServiceAddress) + err = p.kv.Put(nodePath, []byte(metadata), &store.WriteOptions{TTL: p.UpdateInterval * 2}) + if err != nil { + log.Errorf("cannot create consul path %s: %v", nodePath, err) + return err + } + + p.Services = append(p.Services, name) + + p.metasLock.Lock() + if p.metas == nil { + p.metas = make(map[string]string) + } + p.metas[name] = metadata + p.metasLock.Unlock() + return +} + +func (p *ConsulRegisterPlugin) RegisterFunction(serviceName, fname string, fn interface{}, metadata string) error { + return p.Register(serviceName, fn, metadata) +} + +func (p *ConsulRegisterPlugin) Unregister(name string) (err error) { + if len(p.Services) == 0 { + return nil + } + if strings.TrimSpace(name) == "" { + err = errors.New("Unregister service `name` can't be empty") + return + } + + if p.kv == nil { + consul.Register() + kv, err := libkv.NewStore(store.CONSUL, p.ConsulServers, nil) + if err != nil { + log.Errorf("cannot create consul registry: %v", err) + return err + } + p.kv = kv + } + + if p.BasePath[0] == '/' { + p.BasePath = p.BasePath[1:] + } + err = p.kv.Put(p.BasePath, []byte("rpcx_path"), &store.WriteOptions{IsDir: true}) + if err != nil { + log.Errorf("cannot create consul path %s: %v", p.BasePath, err) + return err + } + + //nodePath := fmt.Sprintf("%s/%s", p.BasePath, name) + // + //err = p.kv.Put(nodePath, []byte(name), &store.WriteOptions{IsDir: true}) + //if err != nil { + // log.Errorf("cannot create consul path %s: %v", nodePath, err) + // return err + //} + + nodePath := fmt.Sprintf("%s/%s/%s", p.BasePath, name, p.ServiceAddress) + + err = p.kv.Delete(nodePath) + if err != nil { + log.Errorf("cannot remove consul path %s: %v", nodePath, err) + return err + } + + var services = make([]string, 0, len(p.Services)-1) + for _, s := range p.Services { + if s != name { + services = append(services, s) + } + } + p.Services = services + + p.metasLock.Lock() + if p.metas == nil { + p.metas = make(map[string]string) + } + delete(p.metas, name) + p.metasLock.Unlock() + return +} diff --git a/app/logic/department.go b/app/logic/department.go new file mode 100644 index 0000000..23673ec --- /dev/null +++ b/app/logic/department.go @@ -0,0 +1,68 @@ +package logic + +import ( + "encoding/json" + "ik3cloud/app/common" + "ik3cloud/app/config" + "ik3cloud/app/lib/ik3cloud" + + ik3cloud2 "git.kumo.work/shama/service/ik3cloud" +) + +var DepartmentLogic = &departmentLogic{} + +type departmentLogic struct { +} + +// All @TITLE 全部部门 +func (d *departmentLogic) All() (result []ik3cloud2.DepartmentItem, err error) { + raw, err := ik3cloud.Client.ExecuteBillQuery(map[string]interface{}{ + "FormId": "BD_Department", + "FieldKeys": "FNumber,FName,FParentID.FNumber,FParentID.FName", + "FilterString": []map[string]interface{}{{ + "FieldName": "FUseOrgId.FNumber", + "Compare": "67", + "Value": config.Config.Ik3cloud.OrganizationNumber, + "Left": "", + "Right": "", + "Logic": "", + }}, + }) + if err != nil { + return + } + var data [][]*string + if err = json.Unmarshal(raw, &data); err != nil { + return + } + for _, item := range data { + result = append(result, ik3cloud2.DepartmentItem{ + Number: item[0], + Name: item[1], + ParentNumber: item[2], + ParentName: item[3], + }) + } + return d.getTree(result), nil +} + +// @Title 获取菜单树 +func (d *departmentLogic) getTree(datas []ik3cloud2.DepartmentItem) (result []ik3cloud2.DepartmentItem) { + result = []ik3cloud2.DepartmentItem{} + for i, item := range datas { + if item.ParentNumber != nil { + for index, value := range datas { + if common.PtrCmp(item.ParentNumber, value.Number) { + datas[index].Children = append(datas[index].Children, &datas[i]) + break + } + } + } + } + for _, item := range datas { + if item.ParentNumber != nil { + result = append(result, item) + } + } + return +} diff --git a/app/logic/staff.go b/app/logic/staff.go new file mode 100644 index 0000000..30c454c --- /dev/null +++ b/app/logic/staff.go @@ -0,0 +1,101 @@ +package logic + +import ( + "encoding/json" + "ik3cloud/app/common" + "ik3cloud/app/config" + "ik3cloud/app/lib/ik3cloud" + + ik3cloud2 "git.kumo.work/shama/service/ik3cloud" + "git.kumo.work/shama/service/lib/bean" +) + +var StaffLogic = &staffLogic{} + +type staffLogic struct { +} + +// List @TITLE 员工列表 +func (s *staffLogic) List(page bean.Page, search ik3cloud2.StaffSearch) (list []ik3cloud2.StaffItem, total int64, err error) { + where := []map[string]interface{}{ + { + "FieldName": "FCreateOrgId.FNumber", + "Compare": "67", + "Value": config.Config.Ik3cloud.OrganizationNumber, + "Left": "", + "Right": "", + "Logic": 0, + }, + } + { + // 搜索 + // 状态 + if search.Status > 0 { + status := "B" + if search.Status == 1 { + status = "A" + } + where = append(where, map[string]interface{}{ + "FieldName": "FForbidStatus", + "Compare": "105", + "Value": status, + "Left": "", + "Right": "", + "Logic": 0, + }) + } + + // 姓名 + if search.Name != "" { + where = append(where, map[string]interface{}{ + "FieldName": "FName", + "Compare": "17", + "Value": search.Name, + "Left": "", + "Right": "", + "Logic": 0, + }) + } + + // 手机号 + if search.Phone != "" { + where = append(where, map[string]interface{}{ + "FieldName": "FBaseProperty", + "Compare": "17", + "Value": search.Phone, + "Left": "", + "Right": "", + "Logic": 0, + }) + } + } + raw, err := ik3cloud.Client.ExecuteBillQuery(map[string]interface{}{ + "FormId": "BD_Empinfo", + "FieldKeys": "FNumber,FName,FParentID.FNumber,FParentID.FName", + "FilterString": where, + "StartRow": page.GetStart(), + "Limit": page.GetLimit(), + }) + if err != nil { + return + } + var data [][]*string + if err = json.Unmarshal(raw, &data); err != nil { + return + } + for _, item := range data { + status := "禁用" + if common.PtrCmp(item[5], common.Ptr("A")) { + status = "启用" + } + list = append(list, ik3cloud2.StaffItem{ + Number: item[0], + Name: item[1], + Position: item[2], + Phone: item[3], + Mobile: item[4], + Status: common.Ptr(status), + }) + } + return +} diff --git a/app/router/router.go b/app/router/router.go new file mode 100644 index 0000000..881d2ef --- /dev/null +++ b/app/router/router.go @@ -0,0 +1,19 @@ +package router + +import ( + "ik3cloud/app/controller" + + "github.com/smallnest/rpcx/server" +) + +// SetRouter @TITLE 配置路由 +func SetRouter(server *server.Server) { + // 员工 + if err := server.RegisterName("staff", &controller.Staff{}, ""); err != nil { + return + } + // 部门 + if err := server.RegisterName("department", &controller.Department{}, ""); err != nil { + return + } +} diff --git a/client/rpc/main.go b/client/rpc/main.go new file mode 100644 index 0000000..5061089 --- /dev/null +++ b/client/rpc/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "fmt" + "ik3cloud" + "ik3cloud/app/config" + "ik3cloud/app/router" + "strings" + "time" + "unsafe" + + jsoniter "github.com/json-iterator/go" + "github.com/smallnest/rpcx/server" +) + +func main() { + // 初始化项目 + closes := ik3cloud.InitApp() + // 关闭资源 + for _, fn := range closes { + defer fn() + } + + //query.SetDefault(mysql.Db) + + s := server.NewServer() + + // 注册中心 + ik3cloud.AddRegistryPlugin(s) + + // 设置路由 + router.SetRouter(s) + + // json处理 + jsoniter.RegisterTypeEncoderFunc("time.Time", func(ptr unsafe.Pointer, stream *jsoniter.Stream) { + t := *((*time.Time)(ptr)) + stream.WriteInt64(t.Unix()) + }, nil) + // 去除首尾空格 + jsoniter.RegisterTypeDecoderFunc("string", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + *((*string)(ptr)) = strings.TrimSpace(iter.ReadString()) + }) + jsoniter.RegisterTypeDecoderFunc("*time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + strTime := iter.ReadString() + if strTime == "" { + return + } + formatTime := "2006-01-02 15:04:05" + location, err := time.ParseInLocation(formatTime[0:len(strTime)], strTime, time.Local) + if err != nil { + iter.Error = err + return + } + *((**time.Time)(ptr)) = &location + }) + + jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + strTime := iter.ReadString() + formatTime := "2006-01-02 15:04:05" + location, err := time.ParseInLocation(formatTime[0:len(strTime)], strTime, time.Local) + if err != nil { + iter.Error = err + return + } + *((*time.Time)(ptr)) = location + }) + + if err := s.Serve("tcp", fmt.Sprintf(":%d", config.Config.Server.Port)); err != nil { + return + } +} diff --git a/config/app.ini b/config/app.ini new file mode 100644 index 0000000..981c691 --- /dev/null +++ b/config/app.ini @@ -0,0 +1,32 @@ +defaultModel = test +debug = true + +[server] +host=localhost +port=8081 +registryServer=127.0.0.1:8500 +basePath=ik3cloud + +[log] +director=log +levels=-1,2 +showLine=true +logInConsole=true +prefix= +maxAge=7 +maxSize=100 +maxBackups=30 + +[page] +maxLimit=100 +minLimit=1 +defaultLimit=15 + +[ik3cloud] +host=https://zjyc.ik3cloud.com/k3cloud/ +accountId=58f38bcd87527c +username=朱继峰 +appId=342005_7eduWcHKQlGeR5XtXZ0qSwWtSM0YTOPL +appSecret=a3d7dbf55b60406b8981d864c72b2047 +languageId=2052 +organizationNumber=666 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f9e848b --- /dev/null +++ b/go.mod @@ -0,0 +1,76 @@ +module ik3cloud + +go 1.24.10 + +require ( + git.kumo.work/shama/service v0.0.0-20251111075102-390a971a4ec1 + github.com/deep-project/kingdee v0.4.3 + github.com/json-iterator/go v1.1.12 + github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 + github.com/rpcxio/libkv v0.5.1 + github.com/shopspring/decimal v1.4.0 + github.com/smallnest/rpcx v1.9.1 + github.com/vmihailenco/msgpack/v5 v5.4.1 + go.uber.org/zap v1.27.0 + gopkg.in/ini.v1 v1.67.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 +) + +require ( + github.com/akutz/memconn v0.1.0 // indirect + github.com/alitto/pond v1.9.2 // indirect + github.com/apache/thrift v0.21.0 // indirect + github.com/armon/go-metrics v0.3.6 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/pprof v0.0.0-20250128161936-077ca0a936bf // indirect + github.com/hashicorp/consul/api v1.8.1 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v0.16.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/serf v0.9.5 // indirect + github.com/julienschmidt/httprouter v1.3.0 // indirect + github.com/kavu/go_reuseport v1.5.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/reedsolomon v1.12.4 // indirect + github.com/libp2p/go-sockaddr v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/quic-go/quic-go v0.49.0 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/smallnest/quick v0.2.0 // indirect + github.com/smallnest/rsocket v0.0.0-20241130031020-4a72eb6ff62a // indirect + github.com/soheilhy/cmux v0.1.5 // indirect + github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect + github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tinylib/msgp v1.2.5 // indirect + github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xtaci/kcp-go v5.4.20+incompatible // indirect + go.uber.org/mock v0.5.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/tools v0.29.0 // indirect + google.golang.org/protobuf v1.36.4 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e614827 --- /dev/null +++ b/go.sum @@ -0,0 +1,452 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +git.kumo.work/shama/service v0.0.0-20251111075102-390a971a4ec1 h1:XjculKI2f8EoSs5W39sfLFr7O67kPydFvddV4EImnao= +git.kumo.work/shama/service v0.0.0-20251111075102-390a971a4ec1/go.mod h1:cSaHYmAu1MLKgVBgXGTzYN/m7I3Z0JDI8HTyZW3UaIM= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= +github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs= +github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI= +github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= +github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.6 h1:x/tmtOF9cDBoXH7XoAGOz2qqm1DknFD1590XmD/DUJ8= +github.com/armon/go-metrics v0.3.6/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenk/backoff v2.2.1+incompatible h1:djdFT7f4gF2ttuzRKPbMOWgZajgesItGLwG5FTQKmmE= +github.com/cenk/backoff v2.2.1+incompatible/go.mod h1:7FtoeaSnHoZnmZzz47cM35Y9nSW7tNyaidugnHTaFDE= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/deep-project/kingdee v0.4.3 h1:qysts9Z4RCyNQJHfyIMGUktPfmMM97hPpoNWkA73s5A= +github.com/deep-project/kingdee v0.4.3/go.mod h1:4v5HGsVJp8hoByyHSI7ZEF//N6H80n0v3DIxD0XYIqU= +github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0 h1:0wH6nO9QEa02Qx8sIQGw6ieKdz+BXjpccSOo9vXNl4U= +github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0/go.mod h1:4hKCXuwrJoYvHZxJ86+bRVTOMyJ0Ej+RqfSm8mHi6KA= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/edwingeng/doublejump v1.0.1 h1:wJ6QgNyyF23Of9vw+ThbwJ/obe9KdxaWEg/Brpv5S1o= +github.com/edwingeng/doublejump v1.0.1/go.mod h1:ykMWX8JWePtMtk2OGjNE9kwtgpI+SF2FNIyXV4gS36k= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= +github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +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-ping/ping v1.2.0 h1:vsJ8slZBZAXNCK4dPcI2PEE9eM9n9RbXbGouVQ/Y4yQ= +github.com/go-ping/ping v1.2.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= +github.com/go-redis/redis/v8 v8.8.2/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5 h1:5zELAgnSz0gqmr4Q5DWCoOzNHoeBAxVUXB7LS1eG+sw= +github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5/go.mod h1:ermjEDUoT/fS+3Ona5Vd6t6mZkw1eHp99ILO5jGRBkM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250128161936-077ca0a936bf h1:BvBLUD2hkvLI3dJTJMiopAq8/wp43AAZKTP7qdpptbU= +github.com/google/pprof v0.0.0-20250128161936-077ca0a936bf/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +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/grandcat/zeroconf v1.0.0 h1:uHhahLBKqwWBV6WZUDAT71044vwOTL+McW0mBJvo6kE= +github.com/grandcat/zeroconf v1.0.0/go.mod h1:lTKmG1zh86XyCoUeIHSA4FJMBwCJiQmGfcP2PdzytEs= +github.com/hashicorp/consul/api v1.8.1 h1:BOEQaMWoGMhmQ29fC26bi0qb7/rId9JzZP2V0Xmx7m8= +github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/sdk v0.7.0 h1:H6R9d008jDcHPQPAqPNuydAshJ4v5/8URdFnUvK/+sc= +github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.0 h1:uCeOEwSWGMwhJUdpUjk+1cVKIEfGu2/1nFXukimi2MU= +github.com/hashicorp/go-hclog v0.16.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= +github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kavu/go_reuseport v1.5.0 h1:UNuiY2OblcqAtVDE8Gsg1kZz8zbBWg907sP1ceBV+bk= +github.com/kavu/go_reuseport v1.5.0/go.mod h1:CG8Ee7ceMFSMnx/xr25Vm0qXaj2Z4i5PWoUx+JZ5/CU= +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/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA= +github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-sockaddr v0.2.0 h1:Alhhj6lGxVAon9O32tOO89T601EugSx6YiGjy5BVjWk= +github.com/libp2p/go-sockaddr v0.2.0/go.mod h1:5NxulaB17yJ07IpzRIleys4un0PJ7WLWgMDLBBWrGw8= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= +github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s= +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/rpcxio/libkv v0.5.1 h1:M0/QqwTcdXz7us0NB+2i8Kq5+wikTm7zZ4Hyb/jNgME= +github.com/rpcxio/libkv v0.5.1/go.mod h1:zHGgtLr3cFhGtbalum0BrMPOjhFZFJXCKiws/25ewls= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rubyist/circuitbreaker v2.2.1+incompatible h1:KUKd/pV8Geg77+8LNDwdow6rVCAYOp8+kHUyFvL6Mhk= +github.com/rubyist/circuitbreaker v2.2.1+incompatible/go.mod h1:Ycs3JgJADPuzJDwffe12k6BZT8hxVi6lFK+gWYJLN4A= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smallnest/quick v0.2.0 h1:AEvm7ZovZ6Utv+asFDBh866G4ufMNhRNMKbZHVMFYPE= +github.com/smallnest/quick v0.2.0/go.mod h1:ODNivpfZTaMgYrNb/fhDtqoEe2TTPxSRo8JaIT/QThI= +github.com/smallnest/rpcx v1.9.1 h1:fGw+qMcDRPm7Ei9fdEfqteYY6qQqgVsoyxoUw6hEXy0= +github.com/smallnest/rpcx v1.9.1/go.mod h1:owr4mDCReTn+dy9m5ilof0mBivFBeK0XrkYfZYdDGb4= +github.com/smallnest/rsocket v0.0.0-20241130031020-4a72eb6ff62a h1:GI6kCNC5AVFbKA6ZKbVd4r+fk+Z7XZCRQm9LURZY4t4= +github.com/smallnest/rsocket v0.0.0-20241130031020-4a72eb6ff62a/go.mod h1:VJeIKKrDEzT4ZNVe87JN9uRLw1XLp/ZnnE9PfsyJ1jY= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= +github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= +github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= +github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg= +github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= +github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg= +go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc= +go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA= +go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg= +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/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae h1:COZdc9Ut6wLq7MO9GIYxfZl4n4ScmgqQLoHocKXrxco= +golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/init.go b/init.go new file mode 100644 index 0000000..f768a36 --- /dev/null +++ b/init.go @@ -0,0 +1,110 @@ +package ik3cloud + +import ( + "encoding" + "fmt" + "ik3cloud/app/config" + "ik3cloud/app/lib/logger" + "ik3cloud/app/lib/rpcplugin" + "io" + "path" + "reflect" + "time" + + config2 "git.kumo.work/shama/service/config" + + "github.com/rcrowley/go-metrics" + "github.com/shopspring/decimal" + "github.com/smallnest/rpcx/server" + "github.com/vmihailenco/msgpack/v5" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" +) + +// RegisterBinaryExt registers a binary marshaler/unmarshaler for the given type. +// The type must be implemented both interfaces. +func RegisterBinaryExt[T encoding.BinaryMarshaler, _ interface { + encoding.BinaryUnmarshaler + *T +}](extID int8) { + var zero T + msgpack.RegisterExtEncoder(extID, zero, func(e *msgpack.Encoder, v reflect.Value) ([]byte, error) { + m := v.Interface().(encoding.BinaryMarshaler) + return m.MarshalBinary() + }) + msgpack.RegisterExtDecoder(extID, zero, func(d *msgpack.Decoder, v reflect.Value, extLen int) error { + u := v.Addr().Interface().(encoding.BinaryUnmarshaler) + b := make([]byte, extLen) + if err := d.ReadFull(b); err != nil { + return err + } + return u.UnmarshalBinary(b) + }) +} + +// InitApp 初始化 +func InitApp() (closes []func()) { + // 关闭资源 + closes = []func(){} + // 初始化配置文件 + config.InitConfig(&config.IniConfig{ + ConfigPath: "config", + RunModelErrAllow: true, + }) + + var levels []zapcore.Level + for _, level := range config.Config.Log.Levels { + levels = append(levels, zapcore.Level(level)) + } + // 初始化日志 + logger.InitLogger(&logger.LoggerConfig{ + Levels: levels, + ShowLine: config.Config.Log.ShowLine, + LogInConsole: config.Config.Log.LogInConsole, + EncodeLevel: logger.LowercaseColorLevelEncoder, + Prefix: config.Config.Log.Prefix, + Writer: func(conf *logger.LoggerConfig, filename string, level zapcore.Level) io.Writer { + maxAge := config.Config.Log.MaxAge + maxSize := config.Config.Log.MaxSize + maxBackups := config.Config.Log.MaxBackups + if level == zapcore.ErrorLevel { + maxAge = 0 + maxSize = 0 + maxBackups = 0 + } + return &lumberjack.Logger{ + Filename: path.Join(config.Config.Log.Director, filename+".log"), + MaxAge: maxAge, // days + Compress: true, // disabled by default + MaxSize: maxSize, + MaxBackups: maxBackups, + } + }, + }) + + // 初始化rpc服务 + config2.InitConfig(config2.Config{ + RegistryServer: config.Config.Server.RegistryServer, + }) + + // 注册序列化 + RegisterBinaryExt[decimal.Decimal](1) + return +} + +// AddRegistryPlugin @Title 注册中心 +func AddRegistryPlugin(s *server.Server) { + r := &rpcplugin.ConsulRegisterPlugin{ + ServiceAddress: fmt.Sprintf("tcp@%s:%d", config.Config.Server.Host, config.Config.Server.Port), + ConsulServers: config.Config.Server.RegistryServer, + BasePath: config.Config.Server.BasePath, + Metrics: metrics.NewRegistry(), + UpdateInterval: time.Minute, + } + err := r.Start() + if err != nil { + logger.Logger.Fatal("注册中心初始化失败", zap.Error(err)) + } + s.Plugins.Add(r) +}