Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(circuit): add circuit breaker #90

Merged
merged 3 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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