package web_hook import ( "eta/eta_mini_ht_api/common/component/cache" logger "eta/eta_mini_ht_api/common/component/log" "eta/eta_mini_ht_api/common/exception" "eta/eta_mini_ht_api/controllers" userService "eta/eta_mini_ht_api/domian/user" accountService "eta/eta_mini_ht_api/service/user" "fmt" "golang.org/x/time/rate" "net/http" "strings" "sync" "time" ) var ( // 初始化限流器 accountRateLimiter = NewThirdRateLimiter(rate.Every(1*time.Second), 1) rdServer = cache.GetInstance() ) type ThirdRateLimiter struct { limiters sync.Map // 存储每个用户的限流器 defaultLimiter *rate.Limiter // 默认限流器 } func NewThirdRateLimiter(limit rate.Limit, burst int) *ThirdRateLimiter { return &ThirdRateLimiter{ defaultLimiter: rate.NewLimiter(limit, burst), } } func (url *ThirdRateLimiter) Allow(idNo string) bool { if limiter, ok := url.limiters.Load(idNo); ok { return limiter.(*rate.Limiter).Allow() } // 创建新的限流器并存储 newLimiter := rate.NewLimiter(url.defaultLimiter.Limit(), url.defaultLimiter.Burst()) url.limiters.Store(idNo, newLimiter) return newLimiter.Allow() } // ThirdRateLimitFilter 回调接口限流 func ThirdRateLimitFilter(idNo string) (code int) { if idNo == "" { code = http.StatusBadRequest return } if !accountRateLimiter.Allow(idNo) { code = http.StatusTooManyRequests return } code = http.StatusOK return } type HTFuturesAccountController struct { controllers.WebHookController } // // SyncCustomerRiskLevel 风险测评同步接口 // // @Summary 风险测评同步接口 // // @Description 风险测评同步接口 // // @Success 200 {object} controllers.BaseResponse // // @router /riskLevel [post] // // func (h *UserController) SyncCustomerRiskLevel() { // controllers.Wrap(&h.BaseController, func() (result *controllers.WrapData, err error) { // result = h.InitWrapData("同步风险等级") // htConfig := config.GetConfig(contants.HT).(*config.HTBizConfig) // webhookRequest := new(WebhookRequest) // h.GetPostParams(webhookRequest) // privateKey, err := authUtils.ParsePrivateKey(htConfig.GetWebhookPrivateKey()) // if err != nil { // err = exception.NewWithException(exception.SysError, err.Error()) // logger.Error("解析私钥失败: %v", err) // h.FailedResult("解析私钥失败", result) // return // } // decodeData, err := authUtils.DecryptWithRSA(privateKey, webhookRequest.Data) // if err != nil { // err = exception.NewWithException(exception.SysError, err.Error()) // logger.Error("解密请求体失败: %v", err) // h.FailedResult("解密请求体失败", result) // return // } // syncCustomerRiskLevelReq := new(SyncCustomerRiskLevelReq) // err = json.Unmarshal(decodeData, syncCustomerRiskLevelReq) // if err != nil { // err = exception.NewWithException(exception.SyncRiskError, err.Error()) // logger.Error("解析请求体失败: %v", err) // h.FailedResult("解析请求体失败", result) // return // } // custInfo := syncCustomerRiskLevelReq.CustInfo // riskInfo := syncCustomerRiskLevelReq.RiskInfo // if custInfo.ClientName == "" { // err = exception.New(exception.SyncRiskError) // h.FailedResult("用户名字不能为空", result) // return // } // if custInfo.MobileTel == "" { // err = exception.New(exception.SyncRiskError) // h.FailedResult("手机号码不能为空", result) // return // } // if custInfo.IdNo == "" { // err = exception.New(exception.SyncRiskError) // h.FailedResult("身份证号不能为空", result) // return // } // //if !utils.IsValidIDCard(custInfo.IdNo) && !utils.IsValidOldIDCard(custInfo.IdNo) { // // err = exception.New(exception.SyncRiskError) // // h.FailedResult("身份证号不合法", result) // // return // //} // if riskInfo.CorpRiskLevel == "" { // err = exception.New(exception.SyncRiskError) // h.FailedResult("风险等级不能为空", result) // return // } // if riskInfo.CorpEndDate == "" { // err = exception.New(exception.SyncRiskError) // h.FailedResult("风险测评有效结束日期不能为空", result) // return // } // err = userService.UpdateRiskLevelInfo(userService.RiskLevelInfoDTO{ // Name: custInfo.ClientName, // PhoneNumber: custInfo.MobileTel, // RiskLevel: riskInfo.CorpRiskLevel, // RiskValidEndDate: riskInfo.CorpEndDate, // }) // if err != nil { // logger.ErrorWithTraceId(h.Ctx, err.Error()) // h.FailedResult(err.Error(), result) // err = exception.New(exception.SyncRiskError) // return // } // logger.InfoWithTraceId(h.Ctx, err.Error()) // result = h.InitWrapData("同步风险等级成功") // h.SuccessResult("success", syncCustomerRiskLevelReq, result) // return // }) // } var ( riskMappingMap = map[string]string{ "0": "C1", "1": "C1", "2": "C2", "3": "C3", "4": "C4", "5": "C5", } ) // SyncCustomerRiskLevel 风险测评同步接口 // @Summary 风险测评同步接口 // @Description 风险测评同步接口 // @Success 200 {object} controllers.BaseResponse // @router /v1/syncRiskLevel/ [post] func (h *HTFuturesAccountController) SyncCustomerRiskLevel() { controllers.WrapWebhook(&h.WebHookController, func() (result *controllers.WrapData, err error) { result = h.InitWrapData("同步风险等级") syncCustomerRiskLevelReq := new(SyncCustomerRiskLevelReq) h.GetPostParams(syncCustomerRiskLevelReq) custInfo := syncCustomerRiskLevelReq.CustInfo riskInfo := syncCustomerRiskLevelReq.RiskInfo if custInfo.ClientName == "" { err = exception.New(exception.SyncRiskError) h.FailedResult("用户名字不能为空", result) return } if custInfo.DealMobileTel == "" { err = exception.New(exception.SyncRiskError) h.FailedResult("手机号码不能为空", result) return } if custInfo.IdNo == "" { err = exception.New(exception.SyncRiskError) h.FailedResult("身份证号不能为空", result) return } if custInfo.MobileTel != "" && custInfo.DealMobileTel != custInfo.MobileTel { err = exception.New(exception.SyncRiskError) h.FailedResult(fmt.Sprintf("柜台预留手机号码不一致,测评手机:%s,柜台预留手机:%s", custInfo.DealMobileTel, custInfo.MobileTel), result) return } if riskInfo.CorpRiskLevel == "" { err = exception.New(exception.SyncRiskError) h.FailedResult("风险等级不能为空", result) return } if riskInfo.CorpEndDate == "" { err = exception.New(exception.SyncRiskError) h.FailedResult("风险测评有效结束日期不能为空", result) return } riskEndDate, parseErr := time.Parse("20060102", riskInfo.CorpEndDate) if parseErr != nil { err = exception.New(exception.SyncRiskError) h.FailedResult("风险测评有效结束日期不合法["+riskInfo.CorpEndDate+"]", result) return } if risk, ok := riskMappingMap[riskInfo.CorpRiskLevel]; ok { riskInfo.CorpRiskLevel = risk } else { err = exception.New(exception.SyncRiskError) h.FailedResult(fmt.Sprintf("风险等级不合法,应答结果:%s", riskInfo.CorpRiskLevel), result) return } err = userService.UpdateRiskLevelInfo(userService.RiskLevelInfoDTO{ Name: custInfo.ClientName, PhoneNumber: custInfo.DealMobileTel, RiskLevel: riskInfo.CorpRiskLevel, RiskValidEndDate: riskEndDate.Format(time.DateOnly), }) if err != nil { logger.ErrorWithTraceId(h.Ctx, err.Error()) h.FailedResult(err.Error(), result) err = exception.New(exception.SyncRiskError) return } result = h.InitWrapData("同步风险等级成功") h.SuccessResult("success", syncCustomerRiskLevelReq, result) return }) } // SyncCustomerAccountInfo 开户信息同步接口 // @Summary 开户信息同步接口 // @Description 开户信息同步接口 // @Success 200 {object} controllers.BaseResponse // @router /v1/syncAccountInfo/ [post] func (h *HTFuturesAccountController) SyncCustomerAccountInfo() { controllers.WrapWebhook(&h.WebHookController, func() (result *controllers.WrapData, err error) { result = h.InitWrapData("同步开户信息") syncCustomerRiskLevelReq := new(AccountOpenInfoReq) h.GetPostParams(syncCustomerRiskLevelReq) if ThirdRateLimitFilter(syncCustomerRiskLevelReq.IdNo) != 200 { err = exception.New(exception.TooManyRequest) h.FailedResult("接口请求太频繁,请稍后重试", result) return } //if syncCustomerRiskLevelReq.MobileTel != "" && syncCustomerRiskLevelReq.DealMobileTel != syncCustomerRiskLevelReq.MobileTel { // err = exception.New(exception.SyncRiskError) // h.FailedResult(fmt.Sprintf("柜台预留手机号码不一致,测评手机:%s,柜台预留手机:%s", syncCustomerRiskLevelReq.DealMobileTel, syncCustomerRiskLevelReq.MobileTel), result) // return //} if syncCustomerRiskLevelReq.ClientName == "" { err = exception.New(exception.SyncAccountStatusError) h.FailedResult("用户名字不能为空", result) return } if syncCustomerRiskLevelReq.MobileTel == "" { err = exception.New(exception.SyncAccountStatusError) h.FailedResult("手机号码不能为空", result) return } if _, ok := idKindMap[syncCustomerRiskLevelReq.IdKind]; !ok { err = exception.New(exception.SyncAccountStatusError) validIdKind := make([]string, 0) for _, v := range idKindMap { validIdKind = append(validIdKind, string(v)) } h.FailedResult(fmt.Sprintf("证件类型不合法,当前只支持[%s]", strings.Join(validIdKind, ",")), result) return } if syncCustomerRiskLevelReq.IdNo == "" { err = exception.New(exception.SyncAccountStatusError) h.FailedResult("证号号码不能为空", result) return } idBeginDate, parseErr := time.Parse(time.DateOnly, syncCustomerRiskLevelReq.IdBeginDate) if parseErr != nil { err = exception.New(exception.SyncAccountStatusError) h.FailedResult("身份证有效开始时间不合法["+syncCustomerRiskLevelReq.IdBeginDate+"]", result) return } idEndDate, parseErr := time.Parse(time.DateOnly, syncCustomerRiskLevelReq.IdEndDate) if parseErr != nil { err = exception.New(exception.SyncAccountStatusError) h.FailedResult("身份证有效结束时间不合法["+syncCustomerRiskLevelReq.IdEndDate+"]", result) return } if idEndDate.Before(idBeginDate) { err = exception.New(exception.SyncAccountStatusError) h.FailedResult("身份证有效结束时间不合法,开始日期不能大于结束日期", result) return } err = accountService.UpdateUserAccountOpenStatus(accountService.AccountStatusDTO{ MobileTel: syncCustomerRiskLevelReq.MobileTel, ClientName: syncCustomerRiskLevelReq.ClientName, IdKind: syncCustomerRiskLevelReq.IdKind, IdNo: syncCustomerRiskLevelReq.IdNo, IdBeginDate: idBeginDate, IdEndDate: idEndDate, AccountStatus: string(syncCustomerRiskLevelReq.AccountStatus), ErrorMessage: syncCustomerRiskLevelReq.ErrorMessage, }) if err != nil { logger.ErrorWithTraceId(h.Ctx, err.Error()) h.FailedResult(err.Error(), result) err = exception.New(exception.SyncAccountStatusError) return } result = h.InitWrapData("同步开户信息成功") h.SuccessResult("success", syncCustomerRiskLevelReq, result) return }) } type SyncCustomerRiskLevelReq struct { CustInfo CustInfo `json:"custInfo"` RiskInfo RiskInfo `json:"riskInfo"` } type CustInfo struct { MobileTel string `json:"mobile_tel"` DealMobileTel string `json:"deal_mobile_tel"` ClientName string `json:"client_name"` IdKind string `json:"id_kind"` IdNo string `json:"id_no"` } type RiskInfo struct { CorpBeginDate string `json:"corp_begin_date"` CorpEndDate string `json:"corp_end_date"` UserInvestTerm string `json:"user_invest_term"` UserInvestKind string `json:"user_invest_kind"` CorpRiskLevel string `json:"corp_risk_level"` } type SyncCustomerAccountInfoReq struct { CustInfo CustInfo `json:"custInfo"` RiskInfo RiskInfo `json:"riskInfo"` } type AccountStatus string type IdKind string var ( accountStatusMap = map[string]AccountStatus{ "success": AccountStatusOpenSuccess, "failed": AccountStatusOpenFailed, } idKindMap = map[int]IdKind{ 1: Id, } ) const ( AccountStatusOpenSuccess AccountStatus = "success" AccountStatusOpenFailed AccountStatus = "failed" Id IdKind = "身份证" ) type AccountOpenInfoReq struct { MobileTel string `json:"mobile_tel"` //DealMobileTel string `json:"deal_mobile_tel"` ClientName string `json:"client_name"` IdKind int `json:"id_kind"` IdNo string `json:"id_no"` AccountStatus AccountStatus `json:"account_status"` //ErrorCode int `json:"error_code"` IdBeginDate string `json:"id_begin_date"` IdEndDate string `json:"id_end_date"` ErrorMessage string `json:"error_message"` Timestamp int64 `json:"timestamp"` }