Skip to content

Commit

Permalink
Merge pull request #90 from cbluebird/zf-circuit
Browse files Browse the repository at this point in the history
feat(circuit): add circuit breaker
  • Loading branch information
XiMo-210 authored Jan 29, 2025
2 parents 10365d1 + 426b685 commit dda2336
Show file tree
Hide file tree
Showing 18 changed files with 542 additions and 108 deletions.
1 change: 1 addition & 0 deletions app/apiException/apiException.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var (
SendVerificationCodeLimit = NewError(http.StatusInternalServerError, 200524, "短信发送超限,请1分钟后再试")
CampusMismatch = NewError(http.StatusInternalServerError, 200525, "暂无该校区绑定信息")
OAuthNotUpdate = NewError(http.StatusInternalServerError, 200526, "统一身份认证密码未更新")
NoApiAvailable = NewError(http.StatusInternalServerError, 200527, "正方相关服务暂不可用")
NotInit = NewError(http.StatusNotFound, 200404, http.StatusText(http.StatusNotFound))
NotFound = NewError(http.StatusNotFound, 200404, http.StatusText(http.StatusNotFound))
Unknown = NewError(http.StatusInternalServerError, 300500, "系统异常,请稍后重试!")
Expand Down
56 changes: 16 additions & 40 deletions app/controllers/funcControllers/zfController/zfController.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"math/rand"
"time"
"wejh-go/app/apiException"
"wejh-go/app/models"
"wejh-go/app/services/funnelServices"
"wejh-go/app/services/sessionServices"
"wejh-go/app/services/userServices"
"wejh-go/app/utils"
"wejh-go/app/utils/circuitBreaker"
"wejh-go/config/redis"
)

Expand All @@ -34,15 +33,15 @@ func GetClassTable(c *gin.Context) {
return
}

loginType, err := genLoginType(user)
api, loginType, err := circuitBreaker.CB.GetApi(user.ZFPassword != "", user.OauthPassword != "")
if err != nil {
_ = c.AbortWithError(200, err)
return
}

result, err := funnelServices.GetClassTable(user, postForm.Year, postForm.Term, loginType)
result, err := funnelServices.GetClassTable(user, postForm.Year, postForm.Term, api, loginType)
if err != nil {
userServices.DelPassword(err, user, loginType)
userServices.DelPassword(err, user, string(loginType))
_ = c.AbortWithError(200, err)
return
}
Expand All @@ -63,15 +62,15 @@ func GetScore(c *gin.Context) {
return
}

loginType, err := genLoginType(user)
api, loginType, err := circuitBreaker.CB.GetApi(user.ZFPassword != "", user.OauthPassword != "")
if err != nil {
_ = c.AbortWithError(200, err)
return
}

result, err := funnelServices.GetScore(user, postForm.Year, postForm.Term, loginType)
result, err := funnelServices.GetScore(user, postForm.Year, postForm.Term, api, loginType)
if err != nil {
userServices.DelPassword(err, user, loginType)
userServices.DelPassword(err, user, string(loginType))
_ = c.AbortWithError(200, err)
return
}
Expand All @@ -92,15 +91,15 @@ func GetMidTermScore(c *gin.Context) {
return
}

loginType, err := genLoginType(user)
api, loginType, err := circuitBreaker.CB.GetApi(user.ZFPassword != "", user.OauthPassword != "")
if err != nil {
_ = c.AbortWithError(200, err)
return
}

result, err := funnelServices.GetMidTermScore(user, postForm.Year, postForm.Term, loginType)
result, err := funnelServices.GetMidTermScore(user, postForm.Year, postForm.Term, api, loginType)
if err != nil {
userServices.DelPassword(err, user, loginType)
userServices.DelPassword(err, user, string(loginType))
_ = c.AbortWithError(200, err)
return
}
Expand All @@ -121,15 +120,15 @@ func GetExam(c *gin.Context) {
return
}

loginType, err := genLoginType(user)
api, loginType, err := circuitBreaker.CB.GetApi(user.ZFPassword != "", user.OauthPassword != "")
if err != nil {
_ = c.AbortWithError(200, err)
return
}

result, err := funnelServices.GetExam(user, postForm.Year, postForm.Term, loginType)
result, err := funnelServices.GetExam(user, postForm.Year, postForm.Term, api, loginType)
if err != nil {
userServices.DelPassword(err, user, loginType)
userServices.DelPassword(err, user, string(loginType))
_ = c.AbortWithError(200, err)
return
}
Expand Down Expand Up @@ -159,7 +158,7 @@ func GetRoom(c *gin.Context) {
return
}

loginType, err := genLoginType(user)
api, loginType, err := circuitBreaker.CB.GetApi(user.ZFPassword != "", user.OauthPassword != "")
if err != nil {
_ = c.AbortWithError(200, err)
return
Expand All @@ -181,9 +180,9 @@ func GetRoom(c *gin.Context) {
}
}

result, err := funnelServices.GetRoom(user, postForm.Year, postForm.Term, postForm.Campus, postForm.Weekday, postForm.Week, postForm.Sections, loginType)
result, err := funnelServices.GetRoom(user, postForm.Year, postForm.Term, postForm.Campus, postForm.Weekday, postForm.Week, postForm.Sections, api, loginType)
if err != nil {
userServices.DelPassword(err, user, loginType)
userServices.DelPassword(err, user, string(loginType))
_ = c.AbortWithError(200, err)
return
}
Expand All @@ -198,26 +197,3 @@ func GetRoom(c *gin.Context) {
}
utils.JsonSuccessResponse(c, result)
}

func genLoginType(u *models.User) (string, error) {
var loginType string
rand.Seed(time.Now().UnixNano())
oauthVal := rand.Intn(40)
zfVal := rand.Intn(60)

if u.OauthPassword != "" && u.ZFPassword != "" {
if oauthVal > zfVal {
loginType = "OAUTH"
} else {
loginType = "ZF"
}
} else if u.OauthPassword != "" {
loginType = "OAUTH"
} else if u.ZFPassword != "" {
loginType = "ZF"
} else {
return "", apiException.NoThatPasswordOrWrong
}

return loginType, nil
}
15 changes: 13 additions & 2 deletions app/controllers/userController/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"wejh-go/app/services/userServices"
"wejh-go/app/services/yxyServices"
"wejh-go/app/utils"
"wejh-go/app/utils/circuitBreaker"

"github.com/gin-gonic/gin"
"github.com/google/uuid"
Expand Down Expand Up @@ -36,7 +37,12 @@ func BindZFPassword(c *gin.Context) {
_ = c.AbortWithError(200, apiException.NotLogin)
return
}
err = userServices.SetZFPassword(user, postForm.PassWord)
api, _, err := circuitBreaker.CB.GetApi(true, false)
if err != nil {
_ = c.AbortWithError(200, err)
return
}
err = userServices.SetZFPassword(user, postForm.PassWord, api)
if err != nil {
_ = c.AbortWithError(200, err)
return
Expand All @@ -56,7 +62,12 @@ func BindOauthPassword(c *gin.Context) {
_ = c.AbortWithError(200, apiException.NotLogin)
return
}
err = userServices.SetOauthPassword(user, postForm.PassWord)
api, _, err := circuitBreaker.CB.GetApi(false, true)
if err != nil {
_ = c.AbortWithError(200, err)
return
}
err = userServices.SetOauthPassword(user, postForm.PassWord, api)
if err != nil {
_ = c.AbortWithError(200, err)
return
Expand Down
83 changes: 43 additions & 40 deletions app/services/funnelServices/funnelServices.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package funnelServices
import (
"encoding/json"
"net/url"
"strings"
"wejh-go/app/apiException"
"wejh-go/app/utils/circuitBreaker"
"wejh-go/app/utils/fetch"
"wejh-go/config/api/funnelApi"
)
Expand All @@ -14,54 +16,55 @@ type FunnelResponse struct {
Data interface{} `json:"data"`
}

func FetchHandleOfPost(form url.Values, url funnelApi.FunnelApi) (interface{}, error) {
func FetchHandleOfPost(form url.Values, host string, url funnelApi.FunnelApi) (interface{}, error) {
f := fetch.Fetch{}
f.Init()
res, err := f.PostForm(funnelApi.FunnelHost+string(url), form)
if err != nil {
return nil, apiException.RequestError
}
rc := FunnelResponse{}
err = json.Unmarshal(res, &rc)
if err != nil {
return nil, apiException.RequestError
}
i := 0
for rc.Code == 413 && i < 5 {
i++
res, err = f.PostForm(funnelApi.FunnelHost+string(url), form)

var rc FunnelResponse
var res []byte
var err error
for i := 0; i < 5; i++ {
res, err = f.PostForm(host+string(url), form)
if err != nil {
return nil, apiException.RequestError
err = apiException.RequestError
break
}
rc = FunnelResponse{}
err = json.Unmarshal(res, &rc)
if err != nil {
return nil, apiException.RequestError
if err = json.Unmarshal(res, &rc); err != nil {
err = apiException.RequestError
break
}
if rc.Code != 413 {
break
}
}

if rc.Code == 413 {
return rc.Data, apiException.ServerError
}
if rc.Code == 412 {
return rc.Data, apiException.NoThatPasswordOrWrong
}
if rc.Code == 416 {
return rc.Data, apiException.OAuthNotUpdate
}
return rc.Data, nil
}
func FetchHandleOfGet(url funnelApi.FunnelApi) (interface{}, error) {
f := fetch.Fetch{}
f.Init()
res, err := f.Get(funnelApi.FunnelHost + string(url))
loginType := funnelApi.LoginType(form.Get("type"))
zfFlag := strings.Contains(string(url), "zf")
if err != nil {
return nil, apiException.RequestError
if zfFlag {
circuitBreaker.CB.Fail(host, loginType)
}
return nil, apiException.ServerError
}
rc := FunnelResponse{}
err = json.Unmarshal(res, &rc)
if err != nil {
return nil, apiException.RequestError

if zfFlag {
if rc.Code == 200 || rc.Code == 412 || rc.Code == 416 {
circuitBreaker.CB.Success(host, loginType)
} else {
circuitBreaker.CB.Fail(host, loginType)
}
}

switch rc.Code {
case 200:
return rc.Data, nil
case 413:
return nil, apiException.ServerError
case 412:
return nil, apiException.NoThatPasswordOrWrong
case 416:
return nil, apiException.OAuthNotUpdate
default:
return nil, apiException.ServerError
}
return rc.Data, nil
}
4 changes: 2 additions & 2 deletions app/services/funnelServices/libraryService.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func GetCurrentBorrow(u *models.User) (interface{}, error) {
form := url.Values{}
form.Add("username", u.StudentID)
form.Add("password", u.OauthPassword)
return FetchHandleOfPost(form, funnelApi.LibraryCurrent)
return FetchHandleOfPost(form, funnelApi.FunnelHost, funnelApi.LibraryCurrent)
}

func GetHistoryBorrow(u *models.User) (interface{}, error) {
Expand All @@ -25,5 +25,5 @@ func GetHistoryBorrow(u *models.User) (interface{}, error) {
form.Add("username", u.StudentID)
form.Add("password", u.OauthPassword)

return FetchHandleOfPost(form, funnelApi.LibraryHistory)
return FetchHandleOfPost(form, funnelApi.FunnelHost, funnelApi.LibraryHistory)
}
32 changes: 16 additions & 16 deletions app/services/funnelServices/zfService.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"wejh-go/config/api/funnelApi"
)

func genTermForm(u *models.User, year, term, loginType string) url.Values {
func genTermForm(u *models.User, year, term string, loginType funnelApi.LoginType) url.Values {
var password string

if loginType == "OAUTH" {
if loginType == funnelApi.Oauth {
password = u.OauthPassword
} else {
password = u.ZFPassword
Expand All @@ -18,42 +18,42 @@ func genTermForm(u *models.User, year, term, loginType string) url.Values {
form := url.Values{}
form.Add("username", u.StudentID)
form.Add("password", password)
form.Add("type", loginType)
form.Add("type", string(loginType))
form.Add("year", year)
form.Add("term", term)
return form
}

func GetClassTable(u *models.User, year, term, loginType string) (interface{}, error) {
func GetClassTable(u *models.User, year, term, host string, loginType funnelApi.LoginType) (interface{}, error) {
form := genTermForm(u, year, term, loginType)
return FetchHandleOfPost(form, funnelApi.ZFClassTable)
return FetchHandleOfPost(form, host, funnelApi.ZFClassTable)
}

func GetScore(u *models.User, year, term, loginType string) (interface{}, error) {
func GetScore(u *models.User, year, term, host string, loginType funnelApi.LoginType) (interface{}, error) {
form := genTermForm(u, year, term, loginType)
return FetchHandleOfPost(form, funnelApi.ZFScore)
return FetchHandleOfPost(form, host, funnelApi.ZFScore)
}

func GetMidTermScore(u *models.User, year, term, loginType string) (interface{}, error) {
func GetMidTermScore(u *models.User, year, term, host string, loginType funnelApi.LoginType) (interface{}, error) {
form := genTermForm(u, year, term, loginType)
return FetchHandleOfPost(form, funnelApi.ZFMidTermScore)
return FetchHandleOfPost(form, host, funnelApi.ZFMidTermScore)
}

func GetExam(u *models.User, year, term, loginType string) (interface{}, error) {
func GetExam(u *models.User, year, term, host string, loginType funnelApi.LoginType) (interface{}, error) {
form := genTermForm(u, year, term, loginType)
return FetchHandleOfPost(form, funnelApi.ZFExam)
return FetchHandleOfPost(form, host, funnelApi.ZFExam)
}

func GetRoom(u *models.User, year, term, campus, weekday, week, sections, loginType string) (interface{}, error) {
func GetRoom(u *models.User, year, term, campus, weekday, week, sections, host string, loginType funnelApi.LoginType) (interface{}, error) {
form := genTermForm(u, year, term, loginType)
form.Add("campus", campus)
form.Add("weekday", weekday)
form.Add("week", week)
form.Add("sections", sections)
return FetchHandleOfPost(form, funnelApi.ZFRoom)
return FetchHandleOfPost(form, host, funnelApi.ZFRoom)
}

func BindPassword(u *models.User, year, term, loginType string) (interface{}, error) {
func BindPassword(u *models.User, year, term, host string, loginType funnelApi.LoginType) (interface{}, error) {
var password string
if loginType == "ZF" {
password = u.ZFPassword
Expand All @@ -63,8 +63,8 @@ func BindPassword(u *models.User, year, term, loginType string) (interface{}, er
form := url.Values{}
form.Add("username", u.StudentID)
form.Add("password", password)
form.Add("type", loginType)
form.Add("type", string(loginType))
form.Add("year", year)
form.Add("term", term)
return FetchHandleOfPost(form, funnelApi.ZFExam)
return FetchHandleOfPost(form, host, funnelApi.ZFExam)
}
Loading

0 comments on commit dda2336

Please sign in to comment.