Browse Source

Merge branch 'customer-ht' of eta_server/eta_bridge into master

chenhan 3 months ago
parent
commit
08dbe77b22

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@ latest_log
 latest_binlog
 latest_filelog
 /config/*.yaml
+/config/*.pem
 .DS_Store
 /binlog
 /rdlucklog

+ 34 - 9
config/config.go

@@ -1,15 +1,16 @@
 package config
 
 type Config struct {
-	Log      Log      `mapstructure:"log" json:"log" yaml:"log"`
-	Serve    Serve    `mapstructure:"serve" json:"serve" yaml:"serve"`
-	Mysql    Mysql    `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
-	Redis    Redis    `mapstructure:"redis" json:"redis" yaml:"redis"`
-	OracleJY OracleJY `mapstructure:"oracle_jy" json:"oracle_jy" yaml:"oracle_jy"`
-	Business Business `mapstructure:"business" json:"business" yaml:"business"`
-	Smm      Smm      `mapstructure:"smm" json:"smm" yaml:"smm"`
-	Xiangyu  Xiangyu  `mapstructure:"xiangyu" json:"xiangyu" yaml:"xiangyu"`
-	PCSG     PCSG     `mapstructure:"pcsg" json:"pcsg" yaml:"pcsg"`
+	Log       Log       `mapstructure:"log" json:"log" yaml:"log"`
+	Serve     Serve     `mapstructure:"serve" json:"serve" yaml:"serve"`
+	Mysql     Mysql     `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
+	Redis     Redis     `mapstructure:"redis" json:"redis" yaml:"redis"`
+	OracleJY  OracleJY  `mapstructure:"oracle_jy" json:"oracle_jy" yaml:"oracle_jy"`
+	Business  Business  `mapstructure:"business" json:"business" yaml:"business"`
+	Smm       Smm       `mapstructure:"smm" json:"smm" yaml:"smm"`
+	Xiangyu   Xiangyu   `mapstructure:"xiangyu" json:"xiangyu" yaml:"xiangyu"`
+	PCSG      PCSG      `mapstructure:"pcsg" json:"pcsg" yaml:"pcsg"`
+	HTFutures HTFutures `mapstructure:"htFutures" json:"htFutures" yaml:"htFutures"`
 }
 
 // Serve gin服务配置
@@ -115,6 +116,30 @@ type Xiangyu struct {
 	IndexCrmTarget        string `mapstructure:"index-crm-target" json:"index-crm-target" yaml:"index-crm-target" description:"crm指标平台编码"`
 }
 
+// 海通的配置
+type HTFutures struct {
+	APIAuth           bool     `mapstructure:"api-auth" json:"api-auth" yaml:"api-auth" description:"海通SSO登录签名认证"`
+	PrivateKeyPemPath string   `mapstructure:"private-key-pem-path" json:"private-key-pem-path" yaml:"private-key-pem-path" description:"私钥文件目录"`
+	SSOAuthHost       string   `mapstructure:"sso-auth-host" json:"sso-auth-host" yaml:"sso-auth-host" description:"用户认证平台地址"`
+	OaDBDns           string   `mapstructure:"oa-db-dns" json:"oa-db-dns" yaml:"oa-db-dns" description:"OA数据库连接地址"`
+	OaDBDnsOrm        string   `mapstructure:"oa-db-dns-orm" json:"oa-db-dns-orm" yaml:"oa-db-dns-orm" description:"OA数据库连接地址-orm"`
+	SyncTask          SyncTask `mapstructure:"sync-task" json:"sync-task" yaml:"sync-task" description:"同步任务"`
+	//UserKey               string `mapstructure:"user-key" json:"user-key" yaml:"user-key" description:"统一平台秘钥"`
+	//DefaultRoleId         int    `mapstructure:"default-role-id" json:"default-role-id" yaml:"default-role-id" description:"默认的角色id"`
+	//IndexSyncHost         string `mapstructure:"index-sync-host" json:"index-sync-host" yaml:"index-sync-host" description:"指标同步平台地址"`
+	//IndexSyncAuthUserName string `mapstructure:"index-sync-auth-user-name" json:"index-sync-auth-user-name" yaml:"index-sync-auth-user-name" description:"用户统一身份的鉴权username"`
+	//IndexSyncAuthPwd      string `mapstructure:"index-sync-auth-pwd" json:"index-sync-auth-pwd" yaml:"index-sync-auth-pwd" description:"用户统一身份的鉴权password"`
+	//IndexKey              string `mapstructure:"index-key" json:"index-key" yaml:"index-key" description:"统一平台秘钥"`
+	//IndexSyncTarget       string `mapstructure:"index-sync-target" json:"index-sync-target" yaml:"index-sync-target" description:"指标同步平台编码"`
+	//IndexCrmHost          string `mapstructure:"index-crm-host" json:"index-crm-host" yaml:"index-crm-host" description:"crm指标平台地址"`
+	//IndexCrmTarget        string `mapstructure:"index-crm-target" json:"index-crm-target" yaml:"index-crm-target" description:"crm指标平台编码"`
+}
+
+type SyncTask struct {
+	EnableTask       bool `mapstructure:"enable-task" json:"enable-task" yaml:"enable-task" description:"是否启动同步任务"`
+	SyncTaskInterval int  `mapstructure:"sync-task-interval" json:"sync-task-interval" yaml:"sync-task-interval" description:"定时任务时间间隔"`
+	SyncRoleId       int  `mapstructure:"sync_role_id" json:"sync_role_id" yaml:"sync_role_id" description:"同步用户角色id"`
+}
 type PCSG struct {
 	BloombergApiUrl string `mapstructure:"bloomberge-api-url" json:"bloomberge-api-url" yaml:"bloomberge-api-url" description:"彭博API服务地址"`
 }

+ 51 - 0
controller/haitong/auth_controller.go

@@ -0,0 +1,51 @@
+package haitong
+
+import (
+	"encoding/json"
+	"eta/eta_bridge/controller/resp"
+	"eta/eta_bridge/global"
+	"eta/eta_bridge/logic/htfutures"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-playground/validator/v10"
+)
+
+type GetTokenReq struct {
+	Code string `json:"code" form:"code" description:"code编码"`
+}
+
+type SSOLoginController struct {
+}
+
+// SSOLogin
+// @Description: 用code换取token
+// @author: CH
+// @receiver xc
+// @datetime 2024-01-23 17:06:34
+// @param c *gin.Context
+func (xc *SSOLoginController) SSOLogin(c *gin.Context) {
+	var req GetTokenReq
+	if e := c.Bind(&req); e != nil {
+		err, ok := e.(validator.ValidationErrors)
+		if !ok {
+			resp.FailData("参数解析失败", "Err:"+e.Error(), c)
+			return
+		}
+		resp.FailData("参数解析失败", err.Translate(global.Trans), c)
+		return
+	}
+	if req.Code == "" {
+		resp.FailMsg("请传入code码", "请输入指标code码", c)
+		return
+	}
+	result, err, errMsg := htfutures.LoginEta(req.Code)
+	global.FILE_LOG.Info("oss 请求结束")
+	if err != nil {
+		resp.FailData(errMsg, err.Error(), c)
+		return
+	}
+	str, err := json.Marshal(result)
+	global.FILE_LOG.Info(fmt.Sprintf("请求成功,返回响应体:%s", str))
+	resp.OkData("获取成功", result, c)
+	return
+}

+ 39 - 2
core/run_server.go

@@ -3,7 +3,17 @@ package core
 import (
 	"eta/eta_bridge/global"
 	"eta/eta_bridge/init_serve"
+	"eta/eta_bridge/rpc/sso"
+	_ "eta/eta_bridge/rpc/sso"
+	HTtask "eta/eta_bridge/task/htfutures"
+	"flag"
 	"fmt"
+	"google.golang.org/grpc"
+	"net"
+)
+
+var (
+	port = flag.Int("port", 50051, "")
 )
 
 func RunServe() {
@@ -18,14 +28,22 @@ func RunServe() {
 
 	// 初始化mysql数据库
 	init_serve.Mysql()
-
+	//初始化海通的相关逻辑
+	if global.CONFIG.HTFutures.OaDBDns != "" {
+		init_serve.DMDataBase()
+		//init_serve.DMDataBaseORM()
+	}
+	if global.CONFIG.HTFutures.SyncTask.EnableTask {
+		HTtask.StartCronJob()
+	}
 	if global.CONFIG.OracleJY.Account != "" {
 		//初始化oracle
 		init_serve.OracleJy()
 	}
 	// 启动任务
 	init_serve.InitTask()
-
+	//启动oss服务
+	go startGRPCServer()
 	fmt.Println("port:", global.CONFIG.Serve.Port)
 	err := r.Run(fmt.Sprint("0.0.0.0:", global.CONFIG.Serve.Port)) // 监听并在 0.0.0.0:8080 上启动服务
 	if err != nil {
@@ -34,3 +52,22 @@ func RunServe() {
 		fmt.Println("Run:", fmt.Sprint("0.0.0.0:", global.CONFIG.Serve.Port))
 	}
 }
+
+func startGRPCServer() {
+	flag.Parse()
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
+	if err != nil {
+		global.LOG.Fatal(err)
+	}
+	// 建立rpc服务,并注册SensitiveServer
+	s := grpc.NewServer(
+	//grpc.UnaryInterceptor(rpc.SignatureInterceptor),
+	//grpc.UnaryInterceptor(rpc.EncryptInterceptor),
+	)
+	sso.RegisterSSOLoginServer(s, &sso.SSOService{})
+	// 启动服务
+	err = s.Serve(lis)
+	if err != nil {
+		global.LOG.Fatal("rpc 服务启动失败,Err:", err)
+	}
+}

BIN
eta_bridge


+ 24 - 8
global/global.go

@@ -22,24 +22,40 @@ var (
 	//Redis         *redis.Client //redis链接
 	OracleJy *sql.DB //嘉悦物产数据库连接
 
+	OaDbHT    *gorm.DB
+	OaDbHTORM *sql.DB
 	//Rc *cache.Cache //redis缓存
 	Rc utils.RedisClient //redis缓存
 	Re error             //redis错误
 )
 
-const ConfigFile = "config/config_debug.yaml" //本地(测试)环境下的配置文件地址
-const ProConfigFile = "config/config.yaml"    //生产环境下的配置文件地址
+const ConfigFile = "config_debug.yaml"
+const ProConfigFile = "config.yaml"
+const DefaultFilePath = "config"
+const ConfigFilePath = "/home/code/config/eta_bridge/config" //生产环境下的配置文件地址
 
 func init() {
 	v := viper.New()
 
-	configFilePath := ConfigFile
-
-	//如果不存在该配置文件,那么应该是线上环境,那么去寻找线上配置文件的路径
-	if !utils.FileIsExist(configFilePath) {
-		configFilePath = ProConfigFile
-	}
+	configFilePath, _ := utils.ExistFiles(map[string][]string{
+		DefaultFilePath: {
+			ConfigFile,
+			ProConfigFile,
+		},
+		ConfigFilePath: {
+			ProConfigFile,
+		},
+	})
 
+	//configFilePath := ConfigFile
+	////如果不存在该配置文件,那么应该是线上环境,那么去寻找线上配置文件的路径
+	//if !utils.FileIsExist(configFilePath) {
+	//	configFilePath = ProConfigFile
+	//}
+	////如果该配置文件,那么应该是线上环境,那么去寻找线上配置文件的路径
+	//if !utils.FileIsExist(configFilePath) {
+	//	configFilePath = ConfigFilePath
+	//}
 	fmt.Println("configFilePath->", configFilePath)
 
 	//设置配置文件

+ 38 - 31
go.mod

@@ -5,91 +5,98 @@ go 1.21.7
 require (
 	github.com/astaxie/beego v1.12.3
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
-	github.com/fsnotify/fsnotify v1.6.0
-	github.com/gin-gonic/gin v1.9.1
+	github.com/fsnotify/fsnotify v1.7.0
+	github.com/gin-gonic/gin v1.10.0
+	github.com/go-mysql-org/go-mysql v1.7.0
 	github.com/go-playground/locales v0.14.1
 	github.com/go-playground/universal-translator v0.18.1
-	github.com/go-playground/validator/v10 v10.14.0
+	github.com/go-playground/validator/v10 v10.20.0
 	github.com/go-redis/redis/v8 v8.11.5
+	github.com/go-sql-driver/mysql v1.8.1
 	github.com/godror/godror v0.40.3
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
 	github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
+	github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63
 	github.com/rdlucklib/rdluck_tools v1.0.3
-	github.com/spf13/viper v1.16.0
+	github.com/robfig/cron/v3 v3.0.1
+	github.com/spf13/viper v1.19.0
 	github.com/swaggo/swag v1.16.1
 	github.com/tealeg/xlsx v1.0.5
 	golang.org/x/image v0.9.0
+	google.golang.org/grpc v1.65.0
+	google.golang.org/protobuf v1.34.2
 	gorm.io/driver/mysql v1.5.1
 	gorm.io/gorm v1.25.2
 )
 
 require (
+	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/BurntSushi/toml v0.3.1 // indirect
 	github.com/KyleBanks/depth v1.2.1 // indirect
 	github.com/PuerkitoBio/purell v1.1.1 // indirect
 	github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
 	github.com/benbjohnson/clock v1.1.0 // indirect
-	github.com/bytedance/sonic v1.9.1 // indirect
-	github.com/cespare/xxhash/v2 v2.2.0 // indirect
-	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
+	github.com/bytedance/sonic v1.11.6 // indirect
+	github.com/bytedance/sonic/loader v0.1.1 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
+	github.com/cloudwego/base64x v0.1.4 // indirect
+	github.com/cloudwego/iasm v0.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/gabriel-vasile/mimetype v1.4.2 // indirect
-	github.com/garyburd/redigo v1.6.3 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-logfmt/logfmt v0.6.0 // indirect
-	github.com/go-mysql-org/go-mysql v1.7.0 // indirect
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
 	github.com/go-openapi/jsonreference v0.19.6 // indirect
 	github.com/go-openapi/spec v0.20.4 // indirect
 	github.com/go-openapi/swag v0.19.15 // indirect
-	github.com/go-sql-driver/mysql v1.7.0 // indirect
 	github.com/goccy/go-json v0.10.2 // indirect
 	github.com/godror/knownpb v0.1.1 // indirect
-	github.com/google/uuid v1.3.0 // indirect
+	github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
+	github.com/google/uuid v1.6.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/jonboulle/clockwork v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.4 // indirect
-	github.com/leodido/go-urn v1.2.4 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/lestrrat-go/strftime v1.0.6 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.6 // indirect
-	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
-	github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
 	github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d // indirect
 	github.com/pkg/errors v0.9.1 // indirect
-	github.com/robfig/cron/v3 v3.0.1 // indirect
+	github.com/sagikazarmark/locafero v0.4.0 // indirect
+	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
 	github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
 	github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
 	github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 // indirect
-	github.com/spf13/afero v1.9.5 // indirect
-	github.com/spf13/cast v1.5.1 // indirect
-	github.com/spf13/jwalterweatherman v1.1.0 // indirect
+	github.com/sourcegraph/conc v0.3.0 // indirect
+	github.com/spf13/afero v1.11.0 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
-	github.com/subosito/gotenv v1.4.2 // indirect
+	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
-	github.com/ugorji/go/codec v1.2.11 // indirect
+	github.com/ugorji/go/codec v1.2.12 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
-	go.uber.org/multierr v1.8.0 // indirect
+	go.uber.org/multierr v1.9.0 // indirect
 	go.uber.org/zap v1.21.0 // indirect
-	golang.org/x/arch v0.3.0 // indirect
-	golang.org/x/crypto v0.13.0 // indirect
+	golang.org/x/arch v0.8.0 // indirect
+	golang.org/x/crypto v0.26.0 // indirect
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
-	golang.org/x/net v0.15.0 // indirect
-	golang.org/x/sys v0.12.0 // indirect
-	golang.org/x/text v0.13.0 // indirect
-	golang.org/x/tools v0.13.0 // indirect
-	google.golang.org/protobuf v1.30.0 // indirect
+	golang.org/x/net v0.28.0 // indirect
+	golang.org/x/sys v0.24.0 // indirect
+	golang.org/x/text v0.17.0 // indirect
+	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect

+ 96 - 437
go.sum

@@ -1,44 +1,7 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
@@ -62,25 +25,19 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 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/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
-github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
-github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
+github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
+github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
-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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+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/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
+github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
+github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
+github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
 github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
 github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
 github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
@@ -90,8 +47,9 @@ github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs
 github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
 github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
@@ -99,28 +57,19 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
 github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
-github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
-github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
-github.com/garyburd/redigo v1.6.3 h1:HCeeRluvAgMusMomi1+6Y5dmFOdYV/JzoRrrbFlkGIc=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
 github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
-github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
+github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
 github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 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=
@@ -140,19 +89,21 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
 github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
 github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
-github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
 github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@@ -163,77 +114,32 @@ github.com/godror/knownpb v0.1.1/go.mod h1:4nRFbQo1dDuwKnblRXDxrfCFYeT4hjg3GjMqe
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 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.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/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.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/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.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+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/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -247,26 +153,24 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
 github.com/json-iterator/go v1.1.10/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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
-github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 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.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
-github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
-github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+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/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
 github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
@@ -282,8 +186,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+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/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -299,19 +203,24 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=
+github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
-github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
+github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
 github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
 github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
 github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
@@ -324,15 +233,14 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 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/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
-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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/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.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
@@ -344,8 +252,12 @@ github.com/rdlucklib/rdluck_tools v1.0.3/go.mod h1:9Onw9o4w19C8KE5lxb8GyxgRBbZwe
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
@@ -360,35 +272,35 @@ github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKz
 github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
 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/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
-github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
-github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
-github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
-github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
-github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
-github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
+github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
+github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
 github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 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.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
-github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
-github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
 github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
 github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
@@ -398,379 +310,136 @@ github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCn
 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 v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
 github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
 go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
 go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
 go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
-golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
 golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
 golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
 golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
-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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-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/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-20190108225652-1e06a53dbb7e/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/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-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 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-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
-golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 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/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-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/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
-google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 h1:XQMA2e105XNlEZ8NRF0HqnUOZzP14sUSsgL09kpdNnU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
 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.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -779,7 +448,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
@@ -806,13 +474,6 @@ gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5
 gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
 gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
 modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=
 modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
@@ -826,7 +487,5 @@ modernc.org/sortutil v1.0.0/go.mod h1:1QO0q8IlIlmjBIwm6t/7sof874+xCfZouyqZMLIAtx
 modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
 modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
 modernc.org/y v1.0.1/go.mod h1:Ho86I+LVHEI+LYXoUKlmOMAM1JTXOCfj8qi1T8PsClE=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

+ 50 - 0
init_serve/dm_database.go

@@ -0,0 +1,50 @@
+package init_serve
+
+import (
+	_ "dm"
+	dm "dmgorm2"
+	"eta/eta_bridge/global"
+	"fmt"
+	"gorm.io/gorm"
+	"gorm.io/gorm/logger"
+	"io"
+	"log"
+	"os"
+	"time"
+)
+
+type Product struct {
+	gorm.Model
+	Code  string
+	Price uint
+}
+
+func DMDataBase() {
+	mysqlConf := global.CONFIG.Mysql
+	if len(mysqlConf.List) <= 0 {
+		global.LOG.Error("mysql链接未配置")
+		panic(fmt.Errorf("mysql链接未配置"))
+	}
+
+	//开启日志
+	logWriter := io.MultiWriter(global.MYSQL_LOG) //binlog日志,记录到文件中去
+	if global.CONFIG.Mysql.Stdout {
+		logWriter = io.MultiWriter(global.MYSQL_LOG, os.Stdout)
+	}
+	newLogger := logger.New(log.New(logWriter, "\r\n", log.LstdFlags), logger.Config{
+		SlowThreshold:             200 * time.Millisecond, //慢sql :200ms
+		LogLevel:                  logger.Info,            //记录的日志类型,info代表所有信息都记录
+		IgnoreRecordNotFoundError: true,                   //是否忽略找不到数据错误信息(只是日志记录记录成err还是普通的输出的区别,并不影响业务代码中的:找不到数据行error)
+		Colorful:                  true,                   //是否颜色输出
+	})
+	htConfig := global.CONFIG.HTFutures
+	db, err := gorm.Open(dm.Open(htConfig.OaDBDns), &gorm.Config{
+		Logger: newLogger,
+	})
+	if err != nil {
+		global.LOG.Errorf("海通OA数据库 启动异常,数据库:", ";Err:", err)
+		panic(fmt.Errorf("海通OA数据库 启动异常,数据库:", "Err:%s", err))
+	}
+	global.OaDbHT = db
+	fmt.Println("ht oa database init end")
+}

+ 45 - 0
init_serve/dm_database_orm.go

@@ -0,0 +1,45 @@
+package init_serve
+
+//import (
+//	_ "github.com/alexbrainman/odbc"
+//	"github.com/astaxie/beego/orm"
+//)
+//
+//const (
+//	DR_ODBC orm.DriverType = 6
+//)
+
+//
+//func DMDataBaseORM() {
+//
+//	//开启日志
+//	err := orm.RegisterDriver("odbc", orm.DRTiDB)
+//	if err != nil {
+//		fmt.Println("注册数据库驱动失败,数据库:", ";Err:", err)
+//		return
+//	}
+//	dsn := "Driver={DM8 ODBC DRIVER};Server=localhost:5236;Database=ETA;UID=ETA;PWD=Han6258199118`;"
+//	err = orm.RegisterDataBase("default", "odbc", dsn)
+//	orm.SetMaxIdleConns("default", 50)
+//	orm.SetMaxOpenConns("default", 100)
+//	orm.RegisterModel(new(oa.HrmResource))
+//	orm.RegisterModel(new(oa.HrmDepartment))
+//	orm.RegisterModel(new(oa.HrmSubCompany))
+//	if err != nil {
+//		fmt.Println("注册数据库失败,数据库:", ";Err:", err)
+//		return
+//	}
+//	//ormdb, err := orm.GetDB("defalut")
+//	//if err != nil {
+//	//	fmt.Println("获取数据库连接失败,数据库:", ";Err:", err)
+//	//	return
+//	//}
+//
+//	//ormdb.SetConnMaxLifetime(10 * time.Minute)
+//	if err != nil {
+//		global.LOG.Errorf("海通OA数据库 启动异常,数据库:", ";Err:", err)
+//		panic(fmt.Errorf("海通OA数据库 启动异常,数据库:", "Err:%s", err))
+//	}
+//	//global.OaDbHTORM = ormdb
+//	fmt.Println("ht oa database init end")
+//}

+ 1 - 0
init_serve/router.go

@@ -22,5 +22,6 @@ func InitRouter() (r *gin.Engine) {
 	routers.InitIndexData(rBase)
 	routers.InitXiangyu(rBase)
 	routers.InitPCSG(rBase)
+	routers.InitHTSSO(rBase)
 	return
 }

+ 206 - 0
logic/htfutures/http_client.go

@@ -0,0 +1,206 @@
+package htfutures
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"eta/eta_bridge/global"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+	"time"
+)
+
+const (
+	get  = "GET"
+	post = "POST"
+)
+
+type HttpClient[T any] interface {
+	Get(url string, head http.Header, params map[string]interface{}) (Response[T], error)
+	Post(url string, head http.Header, data interface{}) (Response[T], error)
+	PostFromData(url string, fromData url.Values) (Response[T], error)
+	doRequest(req *http.Request) (Response[T], error)
+}
+
+type Response[T any] struct {
+	Code    int    `json:"code"`
+	Message string `json:"message"`
+	Data    T      `json:"data"`
+	TraceId string `json:"traceId"`
+}
+
+// DefaultHttpClient 结构体实现 SSOClient 接口
+type DefaultHttpClient[T any] struct {
+	client        *http.Client
+	retryStrategy RetryStrategy
+}
+
+func (c *DefaultHttpClient[T]) PostFromData(urlStr string, fromData url.Values) (Response[T], error) {
+	dataStr, err := json.Marshal(fromData)
+	if err != nil {
+		global.FILE_LOG.Error("formData参数json序列化失败,err:" + err.Error())
+	}
+	global.FILE_LOG.Info("post请求:" + urlStr + ",formData:" + string(dataStr))
+	return c.doPostForm(urlStr, fromData)
+}
+func (c *DefaultHttpClient[T]) Post(urlStr string, head http.Header, data interface{}) (response Response[T], err error) {
+	dataStr, err := json.Marshal(data)
+	if err != nil {
+		global.FILE_LOG.Error("请求data json序列化失败,err:" + err.Error())
+	}
+	global.FILE_LOG.Info("post请求:" + urlStr + ",data:" + string(dataStr))
+	body := io.NopCloser(strings.NewReader(string(dataStr)))
+	req, err := http.NewRequest(post, urlStr, body)
+	if err != nil {
+		global.FILE_LOG.Error("创建http求求失败:" + err.Error())
+		return
+	}
+	if head != nil {
+		req.Header = head
+		var headStr []byte
+		headStr, err = json.Marshal(head)
+		if err != nil {
+			global.FILE_LOG.Error("请求头json序列化失败,err:" + err.Error())
+		}
+		global.FILE_LOG.Info("自定义请求头:" + string(headStr))
+	}
+	return c.doRequest(req)
+}
+
+func (c *DefaultHttpClient[T]) Get(urlStr string, head http.Header, params map[string]interface{}) (response Response[T], err error) {
+	if len(params) > 0 {
+		queryParams := url.Values{}
+		for key, value := range params {
+			queryParams.Add(key, fmt.Sprintf("%v", value))
+		}
+		urlStr = urlStr + "?" + queryParams.Encode()
+		global.FILE_LOG.Info("带参get请求:" + urlStr)
+	}
+	req, err := http.NewRequest(get, urlStr, nil)
+	if err != nil {
+		global.FILE_LOG.Error("创建http求求失败:" + err.Error())
+		return
+	}
+	if head != nil {
+		req.Header = head
+		headStr, _ := json.Marshal(head)
+		global.FILE_LOG.Info("自定义请求头:" + string(headStr))
+	}
+	return c.doRequest(req)
+}
+
+func (c *DefaultHttpClient[T]) RetryStrategy(retryStrategy RetryStrategy) *DefaultHttpClient[T] {
+	c.retryStrategy = retryStrategy
+	return c
+}
+
+// retryRequest 尝试执行请求并根据重试策略重试
+// retryRequest 尝试执行请求并根据重试策略重试
+func (c *DefaultHttpClient[T]) retryRequest(requestFunc func() (*http.Response, error)) (result *http.Response, err error) {
+	for i := 0; ; i++ {
+		result, err = requestFunc()
+		if err == nil || !c.retryStrategy.ShouldRetry(i, err) {
+			return
+		}
+		global.FILE_LOG.Error("http请求失败,开始第" + string(rune(i+1)) + "次重试,最近一次错误:[" + err.Error() + "]")
+		time.Sleep(c.retryStrategy.RetryDelay(i))
+	}
+}
+
+func (c *DefaultHttpClient[T]) doPostForm(urlStr string, values url.Values) (response Response[T], err error) {
+	global.FILE_LOG.Info("发送请求:" + urlStr)
+	//ctx 用Background
+	resp, err := c.retryRequest(func() (*http.Response, error) {
+		return c.client.PostForm(urlStr, values)
+	})
+	if err != nil {
+		global.FILE_LOG.Error("http请求失败:" + err.Error())
+		return
+	}
+	defer resp.Body.Close()
+	repBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		global.FILE_LOG.Error("http请求失败,读取body失败:" + err.Error())
+		return
+	}
+	if resp.StatusCode != http.StatusOK {
+		global.FILE_LOG.Error("http请求异常,请求状态为:" + resp.Status)
+	}
+	global.FILE_LOG.Info("http应答为:" + string(repBody))
+	err = json.Unmarshal(repBody, &response)
+	if err != nil {
+		global.FILE_LOG.Error("解析应答失败,反序列化失败:" + err.Error())
+	}
+	return
+}
+
+// DoRequest 执行 HTTP 请求
+func (c *DefaultHttpClient[T]) doRequest(req *http.Request) (response Response[T], err error) {
+	global.FILE_LOG.Info("发送请求:")
+	//ctx 用Background
+	resp, err := c.retryRequest(func() (*http.Response, error) {
+		return c.client.Do(req)
+	})
+	if err != nil {
+		global.FILE_LOG.Error("http请求失败:" + err.Error())
+		return
+	}
+	defer resp.Body.Close()
+	repBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		global.FILE_LOG.Error("http请求失败,读取body失败:" + err.Error())
+		return
+	}
+	if resp.StatusCode != http.StatusOK {
+		global.FILE_LOG.Error("http请求异常,请求状态为:" + resp.Status)
+		return
+	}
+	global.FILE_LOG.Info("htt请求成功,body:" + string(repBody))
+	return
+}
+
+// RetryStrategy 接口定义
+type RetryStrategy interface {
+	ShouldRetry(attempt int, err error) bool
+	RetryDelay(attempt int) time.Duration
+}
+
+// FixedRetryStrategy 实现 RetryStrategy 接口
+type FixedRetryStrategy struct {
+	maxAttempts int
+	delay       time.Duration
+}
+
+// NewFixedRetryStrategy 创建 FixedRetryStrategy 实例
+func newFixedRetryStrategy(maxAttempts int, delay time.Duration) *FixedRetryStrategy {
+	return &FixedRetryStrategy{
+		maxAttempts: maxAttempts,
+		delay:       delay,
+	}
+}
+
+// ShouldRetry 判断是否应该重试
+func (s *FixedRetryStrategy) ShouldRetry(attempt int, err error) bool {
+	return attempt < s.maxAttempts && retryErr(err)
+}
+func (s *FixedRetryStrategy) Header() {
+
+}
+func retryErr(err error) bool {
+	return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled)
+}
+
+// RetryDelay 返回重试延迟时间
+func (s *FixedRetryStrategy) RetryDelay(attempt int) time.Duration {
+	return time.Duration(attempt) * s.delay
+}
+
+func CreateDefault[T any]() *DefaultHttpClient[T] {
+	return &DefaultHttpClient[T]{
+		client:        &http.Client{Timeout: 10 * time.Second},
+		retryStrategy: newFixedRetryStrategy(3, 3*time.Second),
+	}
+}

+ 455 - 0
logic/htfutures/sso_auth.go

@@ -0,0 +1,455 @@
+package htfutures
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_bridge/global"
+	"eta/eta_bridge/models/eta"
+	"eta/eta_bridge/models/response"
+	"eta/eta_bridge/services"
+	"eta/eta_bridge/services/xiangyu"
+	"fmt"
+	"gorm.io/gorm"
+	"net/url"
+	"strings"
+	"time"
+)
+
+const (
+	token_url     = "/frameauth/api/user/getTokenByAuthCode"
+	user_info_url = "/frameauth/api/user/getUserInfoByAccessToken"
+	authCode      = "authCode"
+	accessToken   = "accessToken"
+	sysType       = "systemType"
+	etaAdmin      = "etaadmin"
+	etaCrm        = "weapp"
+)
+
+var (
+	base_url                             = global.CONFIG.HTFutures.SSOAuthHost
+	clientToken HttpClient[string]       = CreateDefault[string]()
+	clientUser  HttpClient[UserInfoResp] = CreateDefault[UserInfoResp]()
+)
+
+type UserInfoResp struct {
+	UserId     string `json:"userId"`
+	Status     string `json:"status"`
+	WorkStatus string `json:"workStatus"`
+	Username   string `json:"username"`
+	Name       string `json:"name"`
+	Nickname   string `json:"nickname"`
+	LastLogin  string `json:"lastLogin"`
+	LastIp     string `json:"lastIp"`
+	GivenName  string `json:"givenName"`
+	FamilyName string `json:"familyName"`
+	MiddleName string `json:"middleName"`
+}
+
+func ssoLogin(code string, systemType string) (token string, userInfo UserInfoResp, err error) {
+	//  获取ht token
+	token, err = GetToken(code, systemType)
+	if err != nil {
+		global.FILE_LOG.Error("获取token失败" + err.Error())
+		return
+	}
+	// 获取用户信息
+	userInfo, err = GetUserInfo(token, systemType)
+	if err != nil {
+		global.FILE_LOG.Error("获取ht域用户信息失败:" + err.Error())
+		return
+	}
+	return
+}
+
+// LoginCRM
+// @Description: 获取eta的session
+// @author: Roc
+// @datetime 2024-01-23 17:44:15
+// @param code string
+// @return resp response.LoginResp
+// @return err error
+// @return errMsg string
+func LoginCRM(code string) (resp response.LoginResp, err error, errMsg string) {
+	// 获取用户信息
+	token, userInfo, err := ssoLogin(code, etaCrm)
+	if err != nil {
+		global.FILE_LOG.Error("获取sso用户信息失败:" + err.Error())
+		errMsg = "获取sso用户信息失败:" + err.Error()
+		return
+	}
+	if userInfo.Username == "" {
+		global.FILE_LOG.Error("sso用户信息不存在")
+		errMsg = "sso用户信息不存在"
+		return
+	}
+	//获取eta用户信息
+	adminInfo, err := eta.GetSysUserByAdminName(userInfo.Username)
+	if err != nil {
+		global.FILE_LOG.Error("获取eta用户信息失败:" + err.Error())
+		errMsg = "获取eta用户信息失败:" + err.Error()
+		return
+	}
+	adminInfo.LastLoginTime, err = time.Parse(time.RFC3339, userInfo.LastLogin)
+	if err != nil {
+		adminInfo.LastLoginTime = time.Now()
+	}
+	// 新增登录记录
+	{
+		record := new(eta.SysUserLoginRecord)
+		record.Uid = adminInfo.AdminId
+		record.UserName = adminInfo.AdminName
+		record.Ip = userInfo.LastIp
+		record.Stage = "login"
+		record.CreateTime = time.Now()
+		go func() {
+			err = eta.AddSysUserLoginRecord(record)
+			if err != nil {
+				global.FILE_LOG.Error("生成登录session失败:" + err.Error())
+			}
+		}()
+	}
+	// 生成登录session
+	resp, session, err, errMsg := services.CreateEtaSession(adminInfo)
+	if err != nil {
+		global.FILE_LOG.Error("生成登录session失败:" + err.Error())
+		return
+	}
+	// 记录两方session的绑定信息
+	thirdSession := &eta.SysThirdSession{
+		ID:               0,
+		SysUserID:        uint64(session.SysUserId),
+		UserName:         session.UserName,
+		AccessToken:      session.AccessToken,
+		ThirdAccessToken: token,
+		//ThirdRefreshToken: tokenResp.RefreshToken,
+		//ThirdExpiredTime: time.Now().Add(time.Duration(tokenResp.ExpiresIn-100) * time.Second),
+		CreatedTime:     time.Now(),
+		LastUpdatedTime: time.Now(),
+	}
+	err = eta.AddSysThirdSession(thirdSession)
+	if err != nil {
+		global.FILE_LOG.Error("记录两方session的绑定信息失败:" + err.Error())
+		errMsg = "记录两方session的绑定信息失败"
+		return
+	}
+	return
+}
+
+// LoginEta
+// @Description: 获取eta的session
+// @author: Roc
+// @datetime 2024-01-23 17:44:15
+// @param code string
+// @return resp response.LoginResp
+// @return err error
+// @return errMsg string
+func LoginEta(code string) (resp response.LoginResp, err error, errMsg string) {
+	// 获取用户信息
+	token, userInfo, err := ssoLogin(code, etaAdmin)
+	if err != nil {
+		global.FILE_LOG.Error("获取sso用户信息失败:" + err.Error())
+		errMsg = "获取sso用户信息失败::" + err.Error()
+		return
+	}
+	if userInfo.Username == "" {
+		global.FILE_LOG.Error("sso用户信息不存在")
+		errMsg = "sso用户信息不存在,获取的用户名为空"
+		return
+	}
+	//获取eta用户信息
+	adminInfo, err := eta.GetSysUserByAdminName(userInfo.Username)
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			global.FILE_LOG.Error("eta用户信息不存在:" + err.Error())
+			errMsg = "eta用户信息不存在"
+		} else {
+			global.FILE_LOG.Error("获取eta用户信息失败:" + err.Error())
+			errMsg = "获取eta用户信息失败" + err.Error()
+		}
+		return
+	}
+	adminInfo.LastLoginTime, err = time.Parse(time.RFC3339, userInfo.LastLogin)
+	if err != nil {
+		adminInfo.LastLoginTime = time.Now()
+	}
+	// 新增登录记录
+	{
+		record := new(eta.SysUserLoginRecord)
+		record.Uid = adminInfo.AdminId
+		record.UserName = adminInfo.AdminName
+		record.Ip = userInfo.LastIp
+		record.Stage = "login"
+		record.CreateTime = time.Now()
+		go func() {
+			err = eta.AddSysUserLoginRecord(record)
+			if err != nil {
+				global.FILE_LOG.Error("生成登录session失败:" + err.Error())
+			}
+		}()
+	}
+	// 生成登录session
+	resp, session, err, errMsg := services.CreateEtaSession(adminInfo)
+	if err != nil {
+		global.FILE_LOG.Error("生成登录session失败:" + err.Error())
+		return
+	}
+	str, _ := json.Marshal(resp)
+	global.FILE_LOG.Info(fmt.Sprintf("session json 序列化结果为:%s", str))
+	// 记录两方session的绑定信息
+	thirdSession := &eta.SysThirdSession{
+		ID:               0,
+		SysUserID:        uint64(session.SysUserId),
+		UserName:         session.UserName,
+		AccessToken:      session.AccessToken,
+		ThirdAccessToken: token,
+		//ThirdRefreshToken: tokenResp.RefreshToken,
+		//ThirdExpiredTime: time.Now().Add(time.Duration(tokenResp.ExpiresIn-100) * time.Second),
+		CreatedTime:     time.Now(),
+		LastUpdatedTime: time.Now(),
+	}
+	err = eta.AddSysThirdSession(thirdSession)
+	if err != nil {
+		global.FILE_LOG.Error("记录两方session的绑定信息失败:" + err.Error())
+		errMsg = "记录两方session的绑定信息失败"
+		return
+	}
+	return
+}
+
+func handleUser(xyUserInfo xiangyu.UserData, xyUserId string, departmentMap, departmentNameMap map[string]*eta.SysDepartment, groupMap, groupNameMap map[string]*eta.SysGroup, userMap map[string]*eta.Admin, roleInfo *eta.SysRole) (err error) {
+	// 判断公司id是否存在,如果不存在,那么就去创建
+	departmentInfo, ok := departmentMap[xyUserInfo.CompanyId]
+	if !ok {
+		// 没有外部id的部门,那么用名称去匹配
+		departmentInfo, ok = departmentNameMap[xyUserInfo.CompanyName]
+		if !ok {
+			// 如果没有的话,那么就创建该部门
+			departmentInfo = &eta.SysDepartment{
+				DepartmentId:   0,
+				DepartmentName: xyUserInfo.CompanyName,
+				OutID:          xyUserInfo.CompanyId,
+				CreateTime:     time.Now(),
+				Sort:           0,
+			}
+			err = departmentInfo.Create()
+
+			if err != nil {
+				return
+			}
+		} else {
+			// 如果通过名称找到了,那么就更新一下外部id
+			departmentInfo.OutID = xyUserInfo.CompanyId
+			err = departmentInfo.Update([]string{"OutID"})
+			if err != nil {
+				return
+			}
+			delete(departmentNameMap, xyUserInfo.CompanyName)
+		}
+
+		departmentMap[xyUserInfo.CompanyId] = departmentInfo
+	}
+
+	// 判断部门id是否存在,如果不存在,那么就去创建
+	groupInfo, ok := groupMap[xyUserInfo.DepartId]
+	if !ok {
+		groupInfo, ok = groupNameMap[fmt.Sprint(departmentInfo.DepartmentId, "_", xyUserInfo.DepartmentName)]
+		if !ok {
+			// 如果通过名称还是没有找到,那么就创建一个分组
+			groupInfo = &eta.SysGroup{
+				GroupId:      0,
+				DepartmentId: departmentInfo.DepartmentId,
+				GroupName:    xyUserInfo.DepartmentName,
+				CreateTime:   time.Now(),
+				ParentId:     0,
+				Sort:         0,
+				OutID:        xyUserInfo.DepartId,
+			}
+
+			// 如果没有的话,那么就创建该分组
+			err = groupInfo.Create()
+			if err != nil {
+				return
+			}
+		} else {
+			// 如果通过名称找到了,那么就更新一下外部id
+			groupInfo.OutID = xyUserInfo.DepartId
+			err = groupInfo.Update([]string{"OutID"})
+			if err != nil {
+				return
+			}
+			delete(groupNameMap, xyUserInfo.DepartmentName)
+		}
+		groupMap[xyUserInfo.DepartId] = groupInfo
+	}
+
+	enabled := 1
+	if xyUserInfo.IsDisabled {
+		enabled = 0
+	}
+	// 判断用户是否存在,如果不存在,那么就去创建
+	userInfo, ok := userMap[xyUserInfo.Username]
+	if !ok {
+		userInfo = &eta.Admin{
+			AdminId:     0,
+			AdminName:   xyUserInfo.Username,
+			AdminAvatar: "",
+			RealName:    xyUserInfo.FullName,
+			Password:    xyUserInfo.Password,
+			//LastUpdatedPasswordTime:   time.Time{},
+			Enabled: enabled,
+			Email:   "",
+			//LastLoginTime:             time.Time{},
+			CreatedTime:     time.Now(),
+			LastUpdatedTime: time.Now(),
+			//Role:            roleInfo.,
+			Mobile:         xyUserInfo.Mobile,
+			RoleType:       0,
+			RoleId:         roleInfo.RoleId,
+			RoleName:       roleInfo.RoleName,
+			RoleTypeCode:   roleInfo.RoleTypeCode,
+			DepartmentId:   departmentInfo.DepartmentId,
+			DepartmentName: departmentInfo.DepartmentName,
+			GroupId:        groupInfo.GroupId,
+			GroupName:      groupInfo.GroupName,
+			Authority:      0,
+			Position:       xyUserInfo.PositionName,
+			//DisableTime:               time.Time{},
+			ChartPermission:           0,
+			EdbPermission:             0,
+			MysteelChemicalPermission: 0,
+			OpenId:                    "",
+			UnionId:                   "",
+			PredictEdbPermission:      0,
+			Province:                  "",
+			ProvinceCode:              "",
+			City:                      "",
+			CityCode:                  "",
+			EmployeeId:                xyUserInfo.EmployeeNo,
+			TelAreaCode:               "",
+			OutID:                     xyUserId,
+		}
+
+		if strings.Contains(roleInfo.RoleTypeCode, "researcher") {
+			userInfo.Role = "researcher"
+		} else if strings.Contains(userInfo.RoleTypeCode, "seller") {
+			userInfo.Role = "sales"
+		} else {
+			userInfo.Role = "admin"
+		}
+
+		// 如果没有的话,那么就创建该用户
+		err = userInfo.Create()
+		if err != nil {
+			return
+		}
+
+	} else {
+		updateColList := make([]string, 0)
+
+		//状态
+		if userInfo.Enabled != enabled {
+			updateColList = append(updateColList, "Enabled")
+			userInfo.Enabled = enabled
+		}
+
+		// 部门
+		if userInfo.DepartmentId != departmentInfo.DepartmentId {
+			updateColList = append(updateColList, "DepartmentId", "DepartmentName")
+			userInfo.DepartmentId = departmentInfo.DepartmentId
+			userInfo.DepartmentName = departmentInfo.DepartmentName
+		}
+
+		// 分组
+		if userInfo.GroupId != groupInfo.GroupId {
+			updateColList = append(updateColList, "GroupId", "GroupName")
+			userInfo.GroupId = groupInfo.GroupId
+			userInfo.GroupName = groupInfo.GroupName
+		}
+
+		// 职位
+		if userInfo.Position != xyUserInfo.PositionName {
+			updateColList = append(updateColList, "Position")
+			userInfo.Position = xyUserInfo.PositionName
+		}
+
+		// 姓名
+		if userInfo.RealName != xyUserInfo.FullName {
+			updateColList = append(updateColList, "RealName")
+			userInfo.RealName = xyUserInfo.FullName
+		}
+
+		// 手机号
+		if userInfo.Mobile != xyUserInfo.Mobile {
+			updateColList = append(updateColList, "Mobile")
+			userInfo.Mobile = xyUserInfo.Mobile
+		}
+
+		// 外部id
+		if userInfo.OutID == `` {
+			updateColList = append(updateColList, "OutID")
+			userInfo.OutID = xyUserId
+		}
+
+		// 工号
+		if userInfo.EmployeeId != xyUserInfo.EmployeeNo {
+			updateColList = append(updateColList, "EmployeeId")
+			userInfo.OutID = xyUserInfo.EmployeeNo
+		}
+
+		if len(updateColList) > 0 {
+			updateColList = append(updateColList, "LastUpdatedTime")
+			userInfo.LastUpdatedTime = time.Now()
+			err = userInfo.Update(updateColList)
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	userMap[xyUserInfo.Username] = userInfo
+
+	return
+}
+
+func GetToken(code string, systemType string) (token string, err error) {
+	urlStr := base_url + token_url
+	params := url.Values{}
+	params.Add(authCode, code)
+	params.Add(sysType, systemType)
+	resp, err := clientToken.PostFromData(urlStr, params)
+	if err != nil {
+		global.FILE_LOG.Error("获取token失败:" + err.Error())
+		return
+	}
+	if resp.Code != 0 {
+		global.FILE_LOG.Error("请求接口应答异常:" + resp.Message)
+		err = errors.New("接口异常应答:" + resp.Message)
+		return
+	}
+	token = resp.Data
+	return
+}
+
+func GetUserInfo(token string, systemType string) (userinfo UserInfoResp, err error) {
+	urlStr := base_url + user_info_url
+	params := url.Values{}
+	params.Add(accessToken, token)
+	params.Add(sysType, systemType)
+	resp, err := clientUser.PostFromData(urlStr, params)
+	if err != nil {
+		global.FILE_LOG.Error("获取用户信息失败:" + err.Error())
+		return
+	}
+	if resp.Code != 0 {
+		global.FILE_LOG.Error("请求接口应答异常:" + resp.Message)
+		err = errors.New("接口异常应答:" + resp.Message)
+		return
+	}
+	userinfo = resp.Data
+	//err = json.Unmarshal([]byte(resp.Data), &userinfo)
+	//if err != nil {
+	//	global.FILE_LOG.Error("解析用户信息失败:" + err.Error())
+	//	return
+	//}
+	return
+}

+ 1 - 1
logic/xiangyu/auth.go

@@ -25,7 +25,7 @@ func LoginEta(code string) (resp response.LoginResp, err error, errMsg string) {
 	}
 
 	//// 获取eta用户信息
-	//adminInfo, err := eta.GetSysUserByOutId(tokenResp.Uid)
+	//adminInfo, err := wx_crm.GetSysUserByOutId(tokenResp.Uid)
 	//if err != nil {
 	//	return
 	//}

+ 22 - 0
main.go

@@ -6,5 +6,27 @@ import (
 
 // @BasePath /
 func main() {
+	//	resp := `{
+	//    "data": {
+	//        "riskInfo": {
+	//            "corp_begin_date": "开始时间",
+	//            "corp_end_date": "结束时间",
+	//            "user_invest_term": "投资期限",
+	//            "user_invest_kind": "投资品种",
+	//            "corp_risk_level": "风险等级"
+	//        },
+	//        "custInfo": {
+	//            "mobile_tel": "手机号",
+	//            "client_name": "客户姓名",
+	//            "id_kind": "证件类型",
+	//            "id_no": "证件号"
+	//        }
+	//    }
+	//}`
+	//	publicKey, _ := utils.ParsePublicKeyFromPEM()
+	//	rsa, _ := utils.EncryptWithRSA(publicKey, []byte(resp))
+	//	fmt.Printf(base64.StdEncoding.EncodeToString(rsa))
+	//	_, _ = utils.ParsePrivateKeyFromPEM("./config/")
+
 	core.RunServe()
 }

+ 12 - 0
models/eta/admin.go

@@ -3,6 +3,7 @@ package eta
 import (
 	"errors"
 	"eta/eta_bridge/global"
+	"gorm.io/gorm/clause"
 	"time"
 )
 
@@ -97,3 +98,14 @@ func GetSysUserByOutId(outId string) (item *Admin, err error) {
 	err = global.MYSQL["hz_eta"].Where("out_id = ?", outId).First(&item).Error
 	return
 }
+
+func BatchInsertOrUpdateAdmin(admins []Admin) (err error) {
+	db := global.MYSQL["hz_eta"]
+	OnConflictFunc := clause.OnConflict{
+		Columns:   []clause.Column{{Name: "admin_name"}, {Name: "enabled"}},
+		DoUpdates: clause.AssignmentColumns([]string{"real_name", "email", "mobile", "department_id", "department_name", "group_id", "group_name", "employee_id"}),
+	}
+	// 执行批量插入或更新操作
+	err = db.Clauses(OnConflictFunc).Create(&admins).Error
+	return
+}

+ 12 - 0
models/eta/sys_department.go

@@ -2,6 +2,7 @@ package eta
 
 import (
 	"eta/eta_bridge/global"
+	"gorm.io/gorm/clause"
 	"time"
 )
 
@@ -47,3 +48,14 @@ func DeleteDepartmentById(departmentId int) (err error) {
 	err = global.MYSQL["hz_eta"].Exec(sql, departmentId).Error
 	return
 }
+
+func BatchInsertOrUpdate(departments []SysDepartment) (err error) {
+	db := global.MYSQL["hz_eta"]
+	OnConflictFunc := clause.OnConflict{
+		Columns:   []clause.Column{{Name: "department_id"}},
+		DoUpdates: clause.AssignmentColumns([]string{"department_name", "sort"}),
+	}
+	// 执行批量插入或更新操作
+	err = db.Clauses(OnConflictFunc).Create(&departments).Error
+	return
+}

+ 11 - 0
models/eta/sys_group.go

@@ -2,6 +2,7 @@ package eta
 
 import (
 	"eta/eta_bridge/global"
+	"gorm.io/gorm/clause"
 	"time"
 )
 
@@ -55,3 +56,13 @@ func DeleteGroupByGroupId(groupId int) (err error) {
 	err = global.MYSQL["hz_eta"].Exec(sql, groupId).Error
 	return
 }
+func BatchInsertOrUpdateGroup(departments []SysGroup) (err error) {
+	db := global.MYSQL["hz_eta"]
+	OnConflictFunc := clause.OnConflict{
+		Columns:   []clause.Column{{Name: "group_id"}},
+		DoUpdates: clause.AssignmentColumns([]string{"department_id", "group_name", "parent_id", "sort"}),
+	}
+	// 执行批量插入或更新操作
+	err = db.Clauses(OnConflictFunc).Create(&departments).Error
+	return
+}

+ 51 - 0
models/ht/oa/hrm_department.go

@@ -0,0 +1,51 @@
+package oa
+
+import (
+	"eta/eta_bridge/global"
+)
+
+type HrmDepartment struct {
+	ID              int    `grom:"column:id"`
+	DEPARTMENTNAME  string `grom:"column:subcompanyname"`
+	SUBCOMPANYID1   int    `grom:"column:companyid"`
+	SUPDEPID        int    `grom:"column:supsbucomiD"`
+	TLEVEL          int    `grom:"column:TLEVEL"`
+	SHOWORDEROFTREE int    `gorm:"column:SHOWORDEROFTREE"`
+}
+
+type HrmDepartmentOrm struct {
+	Id              int    `orm:"column(ID)"`
+	Departmentname  []byte `orm:"column(DEPARTMENTNAME);type(varchar(200))"`
+	Subcompanyid1   int    `orm:"column(SUBCOMPANYID1)"`
+	Supdepid        int    `orm:"column(SUPDEPID)"`
+	Tlevel          int    `orm:"column(TLEVEL)"`
+	Showorderoftree int    `orm:"column(SHOWORDEROFTREE)"`
+}
+
+func (h *HrmDepartment) TableName() string {
+	return "ECOLOGY_TARGET.HRMDEPARTMENT"
+}
+func GetDepartMentList() (list []HrmDepartment, err error) {
+	err = global.OaDbHT.Select("ID,DEPARTMENTNAME,SUBCOMPANYID1,SUPDEPID,TLEVEL,SHOWORDEROFTREE").Where("CANCELED IS NULL").Find(&list).Error
+	if err != nil {
+		global.FILE_LOG.Error("获取子公司列表失败")
+	}
+
+	return
+}
+
+//func GetDepartMentListWithOrm() (list []*HrmDepartmentOrm, err error) {
+//	o := orm.NewOrm()
+//	err = o.Using("default")
+//	if err != nil {
+//		fmt.Sprintln("Using orm error", err)
+//		return nil, err
+//	}
+//	sql := `select ID,DEPARTMENTNAME,SUBCOMPANYID1,SUPDEPID,TLEVEL,SHOWORDEROFTREE from HRMDEPARTMENT where CANCELED IS NULL`
+//	_, err = o.Raw(sql).QueryRows(&list)
+//	if err != nil {
+//		global.FILE_LOG.Error("获取子公司列表失败")
+//	}
+//
+//	return
+//}

+ 27 - 0
models/ht/oa/hrm_resource.go

@@ -0,0 +1,27 @@
+package oa
+
+import "eta/eta_bridge/global"
+
+type HrmResource struct {
+	ID            int    `gorm:"column:ID"`
+	LOGINID       string `gorm:"column:LOGINID"`
+	WORKCODE      string `gorm:"column:WORKCODE"`
+	LASTNAME      string `gorm:"column:LASTNAME"`
+	DEPARTMENTID  int    `gorm:"column:DEPARTMENTID"`
+	SUBCOMPANYID1 int    `gorm:"column:SUBCOMPANYID1"`
+	SECLEVEL      int    `gorm:"column:SECLEVEL"`
+	EMAIL         string `gorm:"column:EMAIL"`
+	MOBILE        string `gorm:"column:MOBILE"`
+}
+
+func (h *HrmResource) TableName() string {
+	return "ECOLOGY_TARGET.HRMRESOURCE"
+}
+func GetEmployeeList() (list []HrmResource, err error) {
+	err = global.OaDbHT.Select("ID,LOGINID,WORKCODE,LASTNAME,DEPARTMENTID,SUBCOMPANYID1,SECLEVEL,EMAIL,MOBILE").Where("STATUS in (0,1,2,3)").Find(&list).Error
+	if err != nil {
+		global.FILE_LOG.Error("获取员工信息列表失败")
+	}
+
+	return
+}

+ 24 - 0
models/ht/oa/hrm_sub_company.go

@@ -0,0 +1,24 @@
+package oa
+
+import "eta/eta_bridge/global"
+
+type HrmSubCompany struct {
+	ID              int    `grom:"column:id"`
+	SUBCOMPANYNAME  string `grom:"column:subcompanyname"`
+	COMPANYID       int    `grom:"column:companyid"`
+	SUPSUBCOMID     int    `grom:"column:supsbucomiD"`
+	TLEVEL          int    `grom:"column:TLEVEL"`
+	SHOWORDEROFTREE int    `gorm:"column:SHOWORDEROFTREE"`
+}
+
+func (h *HrmSubCompany) TableName() string {
+	return "ECOLOGY_TARGET.HRMSUBCOMPANY"
+}
+func GetSubCompanyList() (list []HrmSubCompany, err error) {
+	err = global.OaDbHT.Select("id  ,subcompanyname ,companyid ,supsubcomid ,tlevel ,SHOWORDEROFTREE").Where("CANCELED IS NULL").Find(&list).Error
+	if err != nil {
+		global.FILE_LOG.Error("获取子公司列表失败")
+	}
+
+	return
+}

+ 46 - 0
models/ht/wx_crm/sys_department.go

@@ -0,0 +1,46 @@
+package wx_crm
+
+import (
+	"eta/eta_bridge/global"
+	"gorm.io/gorm/clause"
+)
+
+type DepartmentType string
+
+const (
+	SubCompany DepartmentType = "sub"
+	Department DepartmentType = "department"
+)
+
+type SysDepartment struct {
+	SysDepartmentId   int            `gorm:"primaryKey;column:sys_department_id;type:int(11);not null" json:"department_id"`
+	SysDepartmentName string         `gorm:"unique;column:sys_department_name;type:varchar(255);default:''" json:"department_name"` // 部门名称
+	OutId             int            `gorm:"column:out_id;type:int(11);not null" json:"out_id"`
+	Type              DepartmentType `gorm:"column:type;type:varchar(50);not null" json:"type"`
+	Sort              int            `gorm:"column:sort;type:int(10);not null;default:0" json:"sort"` // 排序
+	Level             int            `gorm:"column:level" json:"level"`                               // 外部id
+	ParentId          int            `gorm:"column:parent_id;type:int(11);not null" json:"parent_id"`
+}
+
+func (m *SysDepartment) TableName() string {
+	return "sys_department"
+}
+func BatchInsertOrUpdate(departments []SysDepartment) (err error) {
+	db := global.MYSQL["ht_crm"]
+	OnConflictFunc := clause.OnConflict{
+		Columns:   []clause.Column{{Name: "out_id"}, {Name: "type"}},
+		DoUpdates: clause.AssignmentColumns([]string{"sys_department_name", "level", "sort", "parent_id"}),
+	}
+	// 执行批量插入或更新操作
+	err = db.Clauses(OnConflictFunc).Create(&departments).Error
+	return
+}
+
+func GetDepartmentList() (list []SysDepartment, err error) {
+	db := global.MYSQL["ht_crm"]
+	err = db.Select("*").Find(&list).Error
+	if err != nil {
+		global.FILE_LOG.Error("获取CRM部门列表失败", err.Error())
+	}
+	return
+}

+ 21 - 0
models/ht/wx_crm/sys_role.go

@@ -0,0 +1,21 @@
+package wx_crm
+
+import (
+	"eta/eta_bridge/global"
+)
+
+// SysRole 角色表
+type SysRole struct {
+	SysRoleId   int    `gorm:"primaryKey;column:sys_role_id;type:int(11);not null" json:"role_id"`
+	SysRoleName string `gorm:"column:sys_role_name;type:varchar(100)" json:"role_name"`
+}
+
+func (m *SysRole) TableName() string {
+	return "sys_role"
+}
+
+// GetSysRoleById 主键获取角色
+func GetSysRoleById(roleId int) (item *SysRole, err error) {
+	err = global.MYSQL["ht_crm"].Where("sys_role_id = ?", roleId).First(&item).Error
+	return
+}

+ 45 - 0
models/ht/wx_crm/sys_user.go

@@ -0,0 +1,45 @@
+package wx_crm
+
+import (
+	"eta/eta_bridge/global"
+	"gorm.io/gorm/clause"
+	"time"
+)
+
+type SysUser struct {
+	SysUserId        int       `orm:"pk" description:"系统用户id"`
+	SysUserName      string    `description:"账号"`
+	SysRealName      string    `description:"姓名"`
+	Password         string    `description:"密码"`
+	Email            string    `description:"邮箱"`
+	Phone            string    `description:"手机号"`
+	AreaCode         string    `description:"手机区号"`
+	SysRoleId        int       `description:"角色id"`
+	SysRoleName      string    `description:"角色名称"`
+	SysDepartmentId  int       `description:"所属部门id"`
+	SysDepartmentId1 int       `description:"所属部门一级id"`
+	SysDepartmentId2 int       `description:"所属部门二级id"`
+	SysDepartmentId3 int       `description:"所属部门三级id"`
+	SysDepartmentId4 int       `description:"所属部门四级id"`
+	Province         string    `description:"省"`
+	City             string    `description:"市"`
+	PositionName     string    `description:"职位名称"`
+	PositionCode     int       `description:"职位编码"`
+	IsEnabled        bool      `description:"是否启用"`
+	CreateTime       time.Time `description:"创建时间"`
+	ModifyTime       time.Time `description:"更新时间"`
+}
+
+func (s *SysUser) TableName() string {
+	return "sys_user"
+}
+func BatchInsertOrUpdateUser(users []SysUser) (err error) {
+	db := global.MYSQL["ht_crm"]
+	OnConflictFunc := clause.OnConflict{
+		Columns:   []clause.Column{{Name: "sys_user_name"}},
+		DoUpdates: clause.AssignmentColumns([]string{"sys_real_name", "email", "phone", "position_name", "position_code", "sys_department_id", "sys_department_id1", "sys_department_id2", "sys_department_id3", "sys_department_id4"}),
+	}
+	// 执行批量插入或更新操作
+	err = db.Clauses(OnConflictFunc).Create(&users).Error
+	return
+}

+ 29 - 0
routers/htsso.go

@@ -0,0 +1,29 @@
+package routers
+
+import (
+	"eta/eta_bridge/controller/haitong"
+	"github.com/gin-gonic/gin"
+)
+
+// InitXiangyu 获取象屿
+func InitHTSSO(r *gin.RouterGroup) {
+	initCRMSSO(r)
+	//group.GET("user/sync", control.SyncUser)
+	//group.GET("user/pull", control.PullUser)
+	//
+	//// 需要内部鉴权的接口
+	//initAuthXiangyu(r)
+	//
+	//// 指标接口
+	//initIndexXiangyu(r)
+	//
+	//// crm数据接口
+	//initCrmXiangyu(r)
+}
+
+func initCRMSSO(r *gin.RouterGroup) {
+	controller := new(haitong.SSOLoginController)
+	//group := r.Group("ht/").Use(middleware.BaseAuthCheck())
+	group := r.Group("ht/")
+	group.POST("login", controller.SSOLogin)
+}

+ 25 - 0
rpc/protos/sso.proto

@@ -0,0 +1,25 @@
+syntax = "proto3";
+//protoc --go_out=. --go-grpc_out=. rpc/protos/sso.proto
+package rpc;
+option go_package = "./rpc/sso/;sso";
+
+service SSOLogin {
+  rpc Login(LoginRequest) returns (LoginResponse) {}
+}
+
+message LoginRequest {
+  string code = 1;
+  string  source = 2;
+}
+
+message UserInfo {
+  string userId = 1;
+  string username = 2;
+  string name = 3;
+}
+message LoginResponse {
+  int32 errCode = 1;
+  string errMsg = 2;
+  string msg = 3;
+  UserInfo data = 4;
+}

+ 54 - 0
rpc/signature_interceptor.go

@@ -0,0 +1,54 @@
+package rpc
+
+import (
+	"context"
+	"crypto"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/pem"
+	"eta/eta_bridge/global"
+	"google.golang.org/grpc"
+	"os"
+)
+
+type encryptedRequest struct {
+	Message   interface{} `json:"ciphertext"`
+	Nonce     string      `json:"nonce"`     // 添加随机字符串
+	Timestamp int64       `json:"timestamp"` // 添加时间戳
+}
+
+// 签名验证拦截器
+func SignatureInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
+
+	return handler(ctx, req)
+}
+
+// 验证签名
+func verifySignature(message []byte, signature string, publicKey *rsa.PublicKey) bool {
+	hash := sha256.Sum256(message)
+	signatureBytes, err := base64.StdEncoding.DecodeString(signature)
+	if err != nil {
+		return false
+	}
+	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hash[:], signatureBytes)
+	return err == nil
+}
+
+func parsePublicKeyFromPEM() (pubKey *rsa.PublicKey, err error) {
+	pemBlock, err := os.ReadFile("./config/rsa_public_key.pem")
+	block, _ := pem.Decode(pemBlock)
+	if block == nil {
+		global.LOG.Error("公钥解析失败")
+	}
+	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
+	pubKey, ok := pubInterface.(*rsa.PublicKey)
+	if !ok {
+		global.LOG.Error("公钥解析失败")
+	}
+	if err != nil {
+		return nil, err
+	}
+	return
+}

+ 333 - 0
rpc/sso/sso.pb.go

@@ -0,0 +1,333 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.34.2
+// 	protoc        v5.28.0--rc2
+// source: rpc/protos/sso.proto
+
+//protoc --go_out=. --go-grpc_out=. rpc/protos/sso.proto
+
+package sso
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type LoginRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Code   string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
+	Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"`
+}
+
+func (x *LoginRequest) Reset() {
+	*x = LoginRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_rpc_protos_sso_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *LoginRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LoginRequest) ProtoMessage() {}
+
+func (x *LoginRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_rpc_protos_sso_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.
+func (*LoginRequest) Descriptor() ([]byte, []int) {
+	return file_rpc_protos_sso_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *LoginRequest) GetCode() string {
+	if x != nil {
+		return x.Code
+	}
+	return ""
+}
+
+func (x *LoginRequest) GetSource() string {
+	if x != nil {
+		return x.Source
+	}
+	return ""
+}
+
+type UserInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserId   string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
+	Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
+	Name     string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *UserInfo) Reset() {
+	*x = UserInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_rpc_protos_sso_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UserInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UserInfo) ProtoMessage() {}
+
+func (x *UserInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_rpc_protos_sso_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UserInfo.ProtoReflect.Descriptor instead.
+func (*UserInfo) Descriptor() ([]byte, []int) {
+	return file_rpc_protos_sso_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *UserInfo) GetUserId() string {
+	if x != nil {
+		return x.UserId
+	}
+	return ""
+}
+
+func (x *UserInfo) GetUsername() string {
+	if x != nil {
+		return x.Username
+	}
+	return ""
+}
+
+func (x *UserInfo) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+type LoginResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ErrCode int32     `protobuf:"varint,1,opt,name=errCode,proto3" json:"errCode,omitempty"`
+	ErrMsg  string    `protobuf:"bytes,2,opt,name=errMsg,proto3" json:"errMsg,omitempty"`
+	Msg     string    `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
+	Data    *UserInfo `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *LoginResponse) Reset() {
+	*x = LoginResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_rpc_protos_sso_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *LoginResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LoginResponse) ProtoMessage() {}
+
+func (x *LoginResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_rpc_protos_sso_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead.
+func (*LoginResponse) Descriptor() ([]byte, []int) {
+	return file_rpc_protos_sso_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *LoginResponse) GetErrCode() int32 {
+	if x != nil {
+		return x.ErrCode
+	}
+	return 0
+}
+
+func (x *LoginResponse) GetErrMsg() string {
+	if x != nil {
+		return x.ErrMsg
+	}
+	return ""
+}
+
+func (x *LoginResponse) GetMsg() string {
+	if x != nil {
+		return x.Msg
+	}
+	return ""
+}
+
+func (x *LoginResponse) GetData() *UserInfo {
+	if x != nil {
+		return x.Data
+	}
+	return nil
+}
+
+var File_rpc_protos_sso_proto protoreflect.FileDescriptor
+
+var file_rpc_protos_sso_proto_rawDesc = []byte{
+	0x0a, 0x14, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x73, 0x6f,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x72, 0x70, 0x63, 0x22, 0x3a, 0x0a, 0x0c, 0x4c,
+	0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63,
+	0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12,
+	0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x49,
+	0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75,
+	0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75,
+	0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x76, 0x0a, 0x0d, 0x4c,
+	0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65,
+	0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x10,
+	0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67,
+	0x12, 0x21, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d,
+	0x2e, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x64,
+	0x61, 0x74, 0x61, 0x32, 0x3c, 0x0a, 0x08, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12,
+	0x30, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c,
+	0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x72, 0x70,
+	0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+	0x00, 0x42, 0x10, 0x5a, 0x0e, 0x2e, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x73, 0x6f, 0x2f, 0x3b,
+	0x73, 0x73, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_rpc_protos_sso_proto_rawDescOnce sync.Once
+	file_rpc_protos_sso_proto_rawDescData = file_rpc_protos_sso_proto_rawDesc
+)
+
+func file_rpc_protos_sso_proto_rawDescGZIP() []byte {
+	file_rpc_protos_sso_proto_rawDescOnce.Do(func() {
+		file_rpc_protos_sso_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_protos_sso_proto_rawDescData)
+	})
+	return file_rpc_protos_sso_proto_rawDescData
+}
+
+var file_rpc_protos_sso_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_rpc_protos_sso_proto_goTypes = []any{
+	(*LoginRequest)(nil),  // 0: rpc.LoginRequest
+	(*UserInfo)(nil),      // 1: rpc.UserInfo
+	(*LoginResponse)(nil), // 2: rpc.LoginResponse
+}
+var file_rpc_protos_sso_proto_depIdxs = []int32{
+	1, // 0: rpc.LoginResponse.data:type_name -> rpc.UserInfo
+	0, // 1: rpc.SSOLogin.Login:input_type -> rpc.LoginRequest
+	2, // 2: rpc.SSOLogin.Login:output_type -> rpc.LoginResponse
+	2, // [2:3] is the sub-list for method output_type
+	1, // [1:2] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_rpc_protos_sso_proto_init() }
+func file_rpc_protos_sso_proto_init() {
+	if File_rpc_protos_sso_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_rpc_protos_sso_proto_msgTypes[0].Exporter = func(v any, i int) any {
+			switch v := v.(*LoginRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_rpc_protos_sso_proto_msgTypes[1].Exporter = func(v any, i int) any {
+			switch v := v.(*UserInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_rpc_protos_sso_proto_msgTypes[2].Exporter = func(v any, i int) any {
+			switch v := v.(*LoginResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_rpc_protos_sso_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_rpc_protos_sso_proto_goTypes,
+		DependencyIndexes: file_rpc_protos_sso_proto_depIdxs,
+		MessageInfos:      file_rpc_protos_sso_proto_msgTypes,
+	}.Build()
+	File_rpc_protos_sso_proto = out.File
+	file_rpc_protos_sso_proto_rawDesc = nil
+	file_rpc_protos_sso_proto_goTypes = nil
+	file_rpc_protos_sso_proto_depIdxs = nil
+}

+ 123 - 0
rpc/sso/sso_grpc.pb.go

@@ -0,0 +1,123 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.5.1
+// - protoc             v5.28.0--rc2
+// source: rpc/protos/sso.proto
+
+//protoc --go_out=. --go-grpc_out=. rpc/protos/sso.proto
+
+package sso
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.64.0 or later.
+const _ = grpc.SupportPackageIsVersion9
+
+const (
+	SSOLogin_Login_FullMethodName = "/rpc.SSOLogin/Login"
+)
+
+// SSOLoginClient is the client API for SSOLogin service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type SSOLoginClient interface {
+	Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
+}
+
+type sSOLoginClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewSSOLoginClient(cc grpc.ClientConnInterface) SSOLoginClient {
+	return &sSOLoginClient{cc}
+}
+
+func (c *sSOLoginClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) {
+	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+	out := new(LoginResponse)
+	err := c.cc.Invoke(ctx, SSOLogin_Login_FullMethodName, in, out, cOpts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// SSOLoginServer is the server API for SSOLogin service.
+// All implementations must embed UnimplementedSSOLoginServer
+// for forward compatibility.
+type SSOLoginServer interface {
+	Login(context.Context, *LoginRequest) (*LoginResponse, error)
+	mustEmbedUnimplementedSSOLoginServer()
+}
+
+// UnimplementedSSOLoginServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedSSOLoginServer struct{}
+
+func (UnimplementedSSOLoginServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
+}
+func (UnimplementedSSOLoginServer) mustEmbedUnimplementedSSOLoginServer() {}
+func (UnimplementedSSOLoginServer) testEmbeddedByValue()                  {}
+
+// UnsafeSSOLoginServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to SSOLoginServer will
+// result in compilation errors.
+type UnsafeSSOLoginServer interface {
+	mustEmbedUnimplementedSSOLoginServer()
+}
+
+func RegisterSSOLoginServer(s grpc.ServiceRegistrar, srv SSOLoginServer) {
+	// If the following call pancis, it indicates UnimplementedSSOLoginServer was
+	// embedded by pointer and is nil.  This will cause panics if an
+	// unimplemented method is ever invoked, so we test this at initialization
+	// time to prevent it from happening at runtime later due to I/O.
+	if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+		t.testEmbeddedByValue()
+	}
+	s.RegisterService(&SSOLogin_ServiceDesc, srv)
+}
+
+func _SSOLogin_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(LoginRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(SSOLoginServer).Login(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: SSOLogin_Login_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(SSOLoginServer).Login(ctx, req.(*LoginRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// SSOLogin_ServiceDesc is the grpc.ServiceDesc for SSOLogin service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var SSOLogin_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "rpc.SSOLogin",
+	HandlerType: (*SSOLoginServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Login",
+			Handler:    _SSOLogin_Login_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "rpc/protos/sso.proto",
+}

+ 110 - 0
rpc/sso/sso_service.go

@@ -0,0 +1,110 @@
+package sso
+
+import (
+	"context"
+	"encoding/base64"
+	"eta/eta_bridge/global"
+	"eta/eta_bridge/logic/htfutures"
+	"eta/eta_bridge/utils"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/grpc/status"
+)
+
+type SSOService struct {
+	UnimplementedSSOLoginServer
+}
+
+var (
+	source = []string{"weapp"}
+)
+
+func (s *SSOService) Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) {
+	// 获取AES秘钥
+	md, ok := metadata.FromIncomingContext(ctx)
+	if !ok {
+		return nil, status.Errorf(codes.InvalidArgument, "元数据为空")
+	}
+	// 从元数据中提取签名相关的信息encrypted-aes-key
+	encryptedAESKey, ok := md["key"]
+	if !ok || len(encryptedAESKey) == 0 {
+		return nil, status.Errorf(codes.InvalidArgument, "encryptedAESKey不能为空")
+	}
+	decryptedAESKey, err := base64Decode(encryptedAESKey[0])
+
+	if err != nil {
+		return nil, status.Errorf(codes.InvalidArgument, "base64解码AES秘钥失败")
+	}
+	//加密code
+	encryptedCode, err := base64Decode(req.Code)
+	if err != nil {
+		return nil, status.Errorf(codes.InvalidArgument, "base64解码code失败")
+	}
+	if len(encryptedCode) == 0 {
+		return &LoginResponse{
+			ErrCode: 10001,
+			ErrMsg:  "登录失败,code不能为空",
+			Msg:     "登录失败",
+		}, nil
+	}
+	privateKey, err := utils.ParsePrivateKeyFromPEM(global.CONFIG.HTFutures.PrivateKeyPemPath)
+	if err != nil {
+		return &LoginResponse{
+			ErrCode: 10002,
+			ErrMsg:  "登录失败,解析私钥失败",
+			Msg:     "登录失败",
+		}, nil
+	}
+	aesKey, err := utils.DecryptWithRSA(privateKey, decryptedAESKey)
+	if err != nil {
+		return &LoginResponse{
+			ErrCode: 10003,
+			ErrMsg:  "登录失败,解密失败",
+			Msg:     "登录失败",
+		}, nil
+	}
+	code, err := utils.DecryptWithAES(aesKey, encryptedCode)
+	if err != nil {
+		return &LoginResponse{
+			ErrCode: 10004,
+			ErrMsg:  "登录失败,解析code失败",
+			Msg:     "登录失败",
+		}, nil
+	}
+	global.FILE_LOG.Info("传入参数code:%v", code)
+	token, err := htfutures.GetToken(string(code), req.Source)
+	if err != nil {
+		return &LoginResponse{
+			ErrCode: 10005,
+			ErrMsg:  "登录失败,获取token失败",
+			Msg:     "登录失败",
+		}, nil
+	}
+	global.FILE_LOG.Info("返回的token结果集%v", token)
+	user, err := htfutures.GetUserInfo(token, req.Source)
+	if err != nil {
+		return &LoginResponse{
+			ErrCode: 10006,
+			ErrMsg:  "登录失败,获取token失败",
+			Msg:     "登录失败",
+		}, nil
+	}
+	global.FILE_LOG.Info("返回的userInfo结果集%v", user)
+	return &LoginResponse{
+		Msg: "登录成功",
+		Data: &UserInfo{
+			Name:     user.Name,
+			UserId:   user.UserId,
+			Username: user.Username,
+		},
+	}, nil
+}
+
+func base64Encode(data []byte) string {
+	return base64.StdEncoding.EncodeToString(data)
+}
+
+// Base64Decode 对数据进行 Base64 解码
+func base64Decode(data string) ([]byte, error) {
+	return base64.StdEncoding.DecodeString(data)
+}

+ 1 - 0
services/htfutures/user.go

@@ -0,0 +1 @@
+package htfutures

+ 3 - 3
services/session.go

@@ -24,12 +24,12 @@ func CreateEtaSession(sysUser *eta.Admin) (login response.LoginResp, session *et
 	account := utils.MD5(sysUser.AdminName)
 	//// 获取用户未过期的session, 避免过于频繁生成token
 	//expired := time.Now().AddDate(0, 0, 1).Format(utils.FormatDateTime)
-	//session, _ = eta.GetUserUnexpiredSysSession(sysUser.AdminName, expired)
+	//session, _ = wx_crm.GetUserUnexpiredSysSession(sysUser.AdminName, expired)
 	//if session != nil && session.AccessToken != "" {
 	//	token = session.AccessToken
 	//} else {
 	//	token = utils.GenToken(account)
-	//	session = new(eta.SysSession)
+	//	session = new(wx_crm.SysSession)
 	//	session.UserName = sysUser.AdminName
 	//	session.SysUserId = sysUser.AdminId
 	//	session.ExpiredTime = time.Now().AddDate(0, 0, 90)
@@ -37,7 +37,7 @@ func CreateEtaSession(sysUser *eta.Admin) (login response.LoginResp, session *et
 	//	session.CreatedTime = time.Now()
 	//	session.LastUpdatedTime = time.Now()
 	//	session.AccessToken = token
-	//	if e := eta.AddSysSession(session); e != nil {
+	//	if e := wx_crm.AddSysSession(session); e != nil {
 	//		errMsg = "新增session失败, err: "
 	//		err = errors.New("新增session失败, err: " + e.Error())
 	//		return

+ 273 - 0
task/htfutures/sync_staff_task.go

@@ -0,0 +1,273 @@
+package HTtask
+
+import (
+	"errors"
+	"eta/eta_bridge/global"
+	"eta/eta_bridge/models/eta"
+	"eta/eta_bridge/models/ht/oa"
+	"eta/eta_bridge/models/ht/wx_crm"
+	"fmt"
+	"github.com/robfig/cron/v3"
+)
+
+func StartCronJob() {
+	// 创建一个新的 cron 实例
+	c := cron.New(cron.WithSeconds())
+	//constr := "0 17 * * * *"
+	constr := "*/5 * * * * *"
+	// 添加定时任务
+	_, err := c.AddFunc(constr, func() {
+
+		go syncCrmOAInfo()
+		go SyncETA()
+	})
+	if err != nil {
+		fmt.Println("添加定时任务失败:", err)
+		return
+	}
+	// 启动定时任务
+	c.Start()
+
+	// 在程序结束时停止定时任务
+	go func() {
+		<-make(chan struct{})
+		c.Stop()
+	}()
+}
+
+func SyncETA() {
+	roleId := global.CONFIG.HTFutures.SyncTask.SyncRoleId
+	role, err := eta.GetSysRoleById(roleId)
+	if err != nil {
+		global.FILE_LOG.Error("获取角色信息失败:", err.Error())
+		return
+	}
+	//先同步分公司列表
+	subCompanylist, err := oa.GetSubCompanyList()
+	if err != nil {
+		global.FILE_LOG.Error("获取海通OA子公司数据失败:", err.Error())
+	}
+	var sysSubCompanyList []eta.SysDepartment
+	for _, item := range subCompanylist {
+		sysDepartment := eta.SysDepartment{
+			DepartmentId:   item.ID,
+			DepartmentName: item.SUBCOMPANYNAME,
+			Sort:           item.SHOWORDEROFTREE,
+		}
+		sysSubCompanyList = append(sysSubCompanyList, sysDepartment)
+	}
+	err = eta.BatchInsertOrUpdate(sysSubCompanyList)
+	if err != nil {
+		global.FILE_LOG.Error("同步海通OA子公司数据失败:", err.Error())
+		return
+	}
+	//同步部门信息
+	DepartmentList, err := oa.GetDepartMentList()
+	if err != nil {
+		global.FILE_LOG.Error("获取海通部门数据失败:", err.Error())
+	}
+	var sysDepartmentList []eta.SysGroup
+	for _, item := range DepartmentList {
+		sysDepartment := eta.SysGroup{
+			GroupId:      item.ID,
+			DepartmentId: item.SUBCOMPANYID1,
+			GroupName:    item.DEPARTMENTNAME,
+			ParentId:     item.SUPDEPID,
+			Sort:         item.SHOWORDEROFTREE,
+		}
+		sysDepartmentList = append(sysDepartmentList, sysDepartment)
+	}
+	err = eta.BatchInsertOrUpdateGroup(sysDepartmentList)
+	if err != nil {
+		global.FILE_LOG.Error("同步海通部门数据数据失败:", err.Error())
+		return
+	}
+	//同步员工信息
+	staffList, err := oa.GetEmployeeList()
+	if err != nil {
+		global.FILE_LOG.Error("获取海通OA员工数据失败:", err.Error())
+	}
+	var Employee []eta.Admin
+	for _, item := range staffList {
+		var department *eta.SysDepartment
+		department, err = eta.GetDepartmentById(item.SUBCOMPANYID1)
+		if err != nil {
+			global.FILE_LOG.Error("获取员工子公司信息失败:", err.Error(), "跳过同步员工", item.WORKCODE)
+			continue
+		}
+		var group *eta.SysGroup
+		group, err = eta.GetSysGroupByGroupId(item.DEPARTMENTID)
+		if err != nil {
+			global.FILE_LOG.Error("获取员工部门组织架信息失败:", err.Error(), "跳过同步员工", item.WORKCODE)
+			continue
+		}
+		sysUser := eta.Admin{
+			AdminName: item.LOGINID,
+			RealName:  item.LASTNAME,
+			Enabled:   1,
+			Email:     item.EMAIL,
+			//Role:           role.RoleName,
+			Mobile:         item.MOBILE,
+			RoleType:       0,
+			RoleId:         role.RoleId,
+			RoleName:       role.RoleName,
+			RoleTypeCode:   role.RoleTypeCode,
+			DepartmentId:   item.SUBCOMPANYID1,
+			DepartmentName: department.DepartmentName,
+			GroupId:        item.DEPARTMENTID,
+			GroupName:      group.GroupName,
+			EmployeeId:     item.WORKCODE,
+		}
+		Employee = append(Employee, sysUser)
+	}
+	err = eta.BatchInsertOrUpdateAdmin(Employee)
+	if err != nil {
+		global.FILE_LOG.Error("同步海通OA员工数据失败:", err.Error())
+		return
+	}
+}
+
+func syncCrmOAInfo() {
+	roleId := global.CONFIG.HTFutures.SyncTask.SyncRoleId
+	role, err := wx_crm.GetSysRoleById(roleId)
+	if err != nil {
+		global.FILE_LOG.Error("获取角色信息失败:", err.Error())
+		return
+	}
+	//先同步分公司列表
+	subCompanylist, err := oa.GetSubCompanyList()
+	if err != nil {
+		global.FILE_LOG.Error("获取海通OA子公司数据失败:", err.Error())
+	}
+	var sysSubCompanyList []wx_crm.SysDepartment
+	for _, item := range subCompanylist {
+		sysDepartment := wx_crm.SysDepartment{
+			SysDepartmentName: item.SUBCOMPANYNAME,
+			Sort:              item.SHOWORDEROFTREE,
+			Level:             item.TLEVEL,
+			OutId:             item.ID,
+			Type:              wx_crm.SubCompany,
+			ParentId:          item.SUPSUBCOMID,
+		}
+		sysSubCompanyList = append(sysSubCompanyList, sysDepartment)
+	}
+	err = wx_crm.BatchInsertOrUpdate(sysSubCompanyList)
+	if err != nil {
+		global.FILE_LOG.Error("同步海通OA子公司数据失败:", err.Error())
+		return
+	}
+	//同步部门信息
+	DepartmentList, err := oa.GetDepartMentList()
+	if err != nil {
+		global.FILE_LOG.Error("获取海通部门数据失败:", err.Error())
+	}
+	var sysDepartmentList []wx_crm.SysDepartment
+	for _, item := range DepartmentList {
+		sysDepartment := wx_crm.SysDepartment{
+			SysDepartmentName: item.DEPARTMENTNAME,
+			Sort:              item.SHOWORDEROFTREE,
+			Level:             item.TLEVEL,
+			OutId:             item.ID,
+			Type:              wx_crm.Department,
+			ParentId:          item.SUPDEPID,
+		}
+		if sysDepartment.Level == 2 && sysDepartment.ParentId == 0 {
+			sysDepartment.ParentId = item.SUBCOMPANYID1
+		}
+		sysDepartmentList = append(sysDepartmentList, sysDepartment)
+	}
+	err = wx_crm.BatchInsertOrUpdate(sysDepartmentList)
+	if err != nil {
+		global.FILE_LOG.Error("同步海通部门数据失败:", err.Error())
+		return
+	}
+	//同步员工信息
+	staffList, err := oa.GetEmployeeList()
+	if err != nil {
+		global.FILE_LOG.Error("获取海通OA员工数据失败:", err.Error())
+	}
+	var Employee []wx_crm.SysUser
+	for _, item := range staffList {
+		idList, departmentErr := GetEmployeeDepartmentList(item.DEPARTMENTID)
+		if departmentErr != nil {
+			global.FILE_LOG.Error("获取员工部门组织架构失败:", departmentErr.Error(), "跳过同步员工", item.WORKCODE)
+			continue
+		}
+		fillSize := 4 - len(idList)
+		var departments []int
+		departments = append(departments, idList...)
+		if fillSize > 0 {
+			for i := 0; i < fillSize; i++ {
+				departments = append([]int{0}, departments...)
+			}
+		}
+		sysUser := wx_crm.SysUser{
+			SysUserName:      item.LOGINID,
+			SysRealName:      item.LASTNAME,
+			Email:            item.EMAIL,
+			Phone:            item.MOBILE,
+			AreaCode:         "86",
+			SysRoleId:        role.SysRoleId,
+			SysRoleName:      role.SysRoleName,
+			SysDepartmentId:  item.DEPARTMENTID,
+			SysDepartmentId1: departments[3],
+			SysDepartmentId2: departments[2],
+			SysDepartmentId3: departments[1],
+			SysDepartmentId4: departments[0],
+			PositionCode:     item.SECLEVEL,
+			IsEnabled:        true,
+		}
+		Employee = append(Employee, sysUser)
+	}
+	err = wx_crm.BatchInsertOrUpdateUser(Employee)
+	if err != nil {
+		global.FILE_LOG.Error("同步海通OA员工数据失败:", err.Error())
+		return
+	}
+}
+
+func GetEmployeeDepartmentList(departmentId int) (departmentIdList []int, err error) {
+	departmentList, err := wx_crm.GetDepartmentList()
+	if err != nil {
+		global.FILE_LOG.Error("获取部门信息失败", err.Error())
+		return
+	}
+	var currentDepartment wx_crm.SysDepartment
+	found := false
+	for _, item := range departmentList {
+		if item.OutId == departmentId {
+			currentDepartment = item
+			found = true
+			break
+		}
+	}
+	if found {
+		departmentIdList = append(departmentIdList, currentDepartment.OutId)
+		subList := TraceDepartmentList(currentDepartment.ParentId, departmentList, currentDepartment.Level-1)
+		departmentIdList = append(departmentIdList, subList...)
+	} else {
+		err = errors.New("当前部门id不存在")
+	}
+	return
+}
+
+func TraceDepartmentList(departmentId int, departmentList []wx_crm.SysDepartment, level int) (departmentIdList []int) {
+	if level == 0 || departmentId == 0 {
+		return
+	}
+	for _, item := range departmentList {
+		if item.OutId == departmentId {
+			if level > 1 && item.Type == wx_crm.SubCompany {
+				continue
+			}
+			if level == 1 && item.Type == wx_crm.Department {
+				continue
+			}
+			departmentIdList = append(departmentIdList, item.OutId)
+			subSubDepartments := TraceDepartmentList(item.ParentId, departmentList, item.Level-1)
+			departmentIdList = append(departmentIdList, subSubDepartments...)
+
+		}
+	}
+	return departmentIdList
+}

+ 80 - 0
utils/aes.go

@@ -0,0 +1,80 @@
+package utils
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"errors"
+	"io"
+)
+
+// GenerateAESKey 生成 AES 密钥
+func GenerateAESKey() ([]byte, error) {
+	key := make([]byte, 32)
+	_, err := io.ReadFull(rand.Reader, key)
+	if err != nil {
+		return nil, err
+	}
+	return key, nil
+}
+
+// EncryptWithAES 使用 AES 加密数据
+func EncryptWithAES(key []byte, plaintext []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
+	iv := ciphertext[:aes.BlockSize]
+	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+		return nil, err
+	}
+	stream := cipher.NewCFBEncrypter(block, iv)
+	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
+	return ciphertext, nil
+}
+
+// DecryptWithAES 使用 AES 解密数据
+func DecryptWithAES(key []byte, ciphertext []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	if len(ciphertext) < aes.BlockSize {
+		return nil, errors.New("ciphertext too short")
+	}
+	iv := ciphertext[:aes.BlockSize]
+	ciphertext = ciphertext[aes.BlockSize:]
+	stream := cipher.NewCFBDecrypter(block, iv)
+	stream.XORKeyStream(ciphertext, ciphertext)
+	// 去填充数据
+	unpadded, err := unpad(ciphertext)
+	if err != nil {
+		return nil, err
+	}
+	return unpadded, nil
+}
+func unpad(buf []byte) ([]byte, error) {
+	if len(buf) == 0 {
+		return nil, errors.New("输入缓冲区为空")
+	}
+
+	// 获取最后一个字节作为填充长度
+	padding := int(buf[len(buf)-1])
+
+	// 检查填充是否有效
+	if padding > len(buf) || padding == 0 {
+		return nil, errors.New("无效的填充")
+	}
+
+	// 验证填充是否一致
+	for i := len(buf) - padding; i < len(buf); i++ {
+		if buf[i] != byte(padding) {
+			return nil, errors.New("无效的填充")
+		}
+	}
+
+	// 返回未填充的数据
+	return buf[:len(buf)-padding], nil
+}

+ 24 - 1
utils/common.go

@@ -250,6 +250,29 @@ func FileIsExist(filePath string) bool {
 	_, err := os.Stat(filePath)
 	return err == nil || os.IsExist(err)
 }
+func ExistFiles(configPathMap map[string][]string) (FullFileName string, err error) {
+	for filePath, fileNames := range configPathMap {
+		if FullFileName != "" {
+			return
+		}
+		files, pathErr := os.ReadDir(filePath)
+		if pathErr != nil {
+			continue
+		}
+		for _, file := range files {
+			if file.IsDir() {
+				continue
+			}
+			for _, fileName := range fileNames {
+				if file.Name() == fileName {
+					FullFileName = fmt.Sprintf("%s/%s", filePath, file.Name())
+					break
+				}
+			}
+		}
+	}
+	return
+}
 
 // GetImgExt 获取图片扩展名
 func GetImgExt(file string) (ext string, err error) {
@@ -1090,4 +1113,4 @@ func InArrayByInt(idStrList []int, searchId int) (has bool) {
 		}
 	}
 	return
-}
+}

+ 2 - 2
utils/constants.go

@@ -98,5 +98,5 @@ const (
 	BusinessCodeRelease = "E2023080900" // 弘则ETA
 )
 
-const CACHE_MYSQL_MASTER_FILENAME = "eta:mysql:binlog:filename"
-const CACHE_MYSQL_MASTER_POSITION = "eta:mysql:binlog:position"
+const CACHE_MYSQL_MASTER_FILENAME = "wx_crm:mysql:binlog:filename"
+const CACHE_MYSQL_MASTER_POSITION = "wx_crm:mysql:binlog:position"

+ 66 - 0
utils/rsa.go

@@ -0,0 +1,66 @@
+package utils
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"os"
+)
+
+// EncryptWithRSA 使用 RSA 公钥加密数据
+func EncryptWithRSA(publicKey *rsa.PublicKey, data []byte) ([]byte, error) {
+	hash := sha256.Sum256(data)
+	encrypted, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, hash[:], nil)
+	if err != nil {
+		return nil, err
+	}
+	return encrypted, nil
+}
+
+// DecryptWithRSA 使用 RSA 私钥解密数据
+func DecryptWithRSA(privateKey *rsa.PrivateKey, encrypted []byte) ([]byte, error) {
+	hash, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, encrypted)
+	if err != nil {
+		return nil, err
+	}
+	return hash, nil
+}
+
+// 解析RSA公钥
+func ParsePrivateKeyFromPEM(path string) (privateKey *rsa.PrivateKey, err error) {
+	pemBlock, err := os.ReadFile(path + "rsa_private_key.pem")
+	block, _ := pem.Decode(pemBlock)
+	str := base64.StdEncoding.EncodeToString(pemBlock)
+	fmt.Printf(str)
+	if block == nil {
+		return nil, errors.New("私钥解析失败")
+	}
+	privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	return
+}
+
+// ParsePublicKeyFromPEM 解析RSA公钥
+func ParsePublicKeyFromPEM() (publicKey *rsa.PublicKey, err error) {
+	pemBlock, err := os.ReadFile("./config/rsa_public_key.pem")
+	if err != nil {
+		return nil, errors.New("公钥加载失败")
+	}
+	block, _ := pem.Decode(pemBlock)
+	if block == nil {
+		return nil, errors.New("公钥解析失败")
+	}
+	key, err := x509.ParsePKIXPublicKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	publicKey = key.(*rsa.PublicKey)
+	return
+}