灵仙gateway
This commit is contained in:
parent
3e2719f682
commit
1d2bc6eafd
@ -88,6 +88,16 @@ func (g *Gateways) GetUserProfile(ctx context.Context, userID int64) (UserProfil
|
||||
return g.Profile.GetUserProfile(ctx, userID)
|
||||
}
|
||||
|
||||
// GetUserProfileByAccount 透传到资料网关。
|
||||
func (g *Gateways) GetUserProfileByAccount(ctx context.Context, sysOrigin, account string) (UserProfile, error) {
|
||||
return g.Profile.GetUserProfileByAccount(ctx, sysOrigin, account)
|
||||
}
|
||||
|
||||
// GetUserProfileByAccountOne 透传到资料网关。
|
||||
func (g *Gateways) GetUserProfileByAccountOne(ctx context.Context, account string) (UserProfile, error) {
|
||||
return g.Profile.GetUserProfileByAccountOne(ctx, account)
|
||||
}
|
||||
|
||||
// GetUserLanguage 透传到资料网关。
|
||||
func (g *Gateways) GetUserLanguage(ctx context.Context, userID int64) (string, error) {
|
||||
return g.Profile.GetUserLanguage(ctx, userID)
|
||||
@ -198,6 +208,16 @@ func (g *ProfileGateway) GetUserProfile(ctx context.Context, userID int64) (User
|
||||
return g.client.GetUserProfile(ctx, userID)
|
||||
}
|
||||
|
||||
// GetUserProfileByAccount 根据账号查询用户资料。
|
||||
func (g *ProfileGateway) GetUserProfileByAccount(ctx context.Context, sysOrigin, account string) (UserProfile, error) {
|
||||
return g.client.GetUserProfileByAccount(ctx, sysOrigin, account)
|
||||
}
|
||||
|
||||
// GetUserProfileByAccountOne 根据账号查询单个用户资料。
|
||||
func (g *ProfileGateway) GetUserProfileByAccountOne(ctx context.Context, account string) (UserProfile, error) {
|
||||
return g.client.GetUserProfileByAccountOne(ctx, account)
|
||||
}
|
||||
|
||||
// GetUserLanguage 查询用户语言。
|
||||
func (g *ProfileGateway) GetUserLanguage(ctx context.Context, userID int64) (string, error) {
|
||||
return g.client.GetUserLanguage(ctx, userID)
|
||||
|
||||
@ -38,6 +38,7 @@ type ConsoleAccount struct {
|
||||
|
||||
type UserProfile struct {
|
||||
ID Int64Value `json:"id"`
|
||||
Account string `json:"account"`
|
||||
UserAvatar string `json:"userAvatar"`
|
||||
UserNickname string `json:"userNickname"`
|
||||
}
|
||||
@ -349,6 +350,32 @@ func (c *Client) GetUserProfile(ctx context.Context, userID int64) (UserProfile,
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetUserProfileByAccount(ctx context.Context, sysOrigin, account string) (UserProfile, error) {
|
||||
endpoint := c.cfg.Java.OtherBaseURL + "/user-profile/client/getByAccount?sysOrigin=" +
|
||||
url.QueryEscape(strings.TrimSpace(sysOrigin)) + "&account=" + url.QueryEscape(strings.TrimSpace(account))
|
||||
var resp resultResponse[UserProfile]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return UserProfile{}, err
|
||||
}
|
||||
if int64(resp.Body.ID) == 0 {
|
||||
return UserProfile{}, fmt.Errorf("empty user profile response")
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetUserProfileByAccountOne(ctx context.Context, account string) (UserProfile, error) {
|
||||
endpoint := c.cfg.Java.OtherBaseURL + "/user-profile/client/getByAccountOne?account=" +
|
||||
url.QueryEscape(strings.TrimSpace(account))
|
||||
var resp resultResponse[UserProfile]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return UserProfile{}, err
|
||||
}
|
||||
if int64(resp.Body.ID) == 0 {
|
||||
return UserProfile{}, fmt.Errorf("empty user profile response")
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
func (c *Client) rewardBridgeBaseURL() string {
|
||||
if baseURL := strings.TrimRight(strings.TrimSpace(c.cfg.Java.ConsoleBaseURL), "/"); baseURL != "" {
|
||||
return baseURL
|
||||
|
||||
@ -31,14 +31,19 @@ func (s *GameOpenService) HandleQueryUser(ctx context.Context, req QueryUserRequ
|
||||
s.saveCallbackLog(ctx, "query-user", rawJSON, resp, "", req, nil, gameOpenLogStatusFailed)
|
||||
return resp
|
||||
}
|
||||
userID := int64(credential.UserID)
|
||||
if req.UID != strconv.FormatInt(userID, 10) {
|
||||
resolved, err := s.resolveUserWithToken(ctx, credential, req.UID)
|
||||
if err != nil {
|
||||
resp := failResponse(gameOpenCodeTokenInvalid, "uid token mismatch")
|
||||
userID := int64(credential.UserID)
|
||||
s.saveCallbackLog(ctx, "query-user", rawJSON, resp, credential.SysOrigin, req, &userID, gameOpenLogStatusFailed)
|
||||
return resp
|
||||
}
|
||||
userID := resolved.userID
|
||||
|
||||
profile, err := s.java.GetUserProfile(ctx, userID)
|
||||
profile := resolved.profile
|
||||
if int64(profile.ID) == 0 {
|
||||
profile, err = s.java.GetUserProfile(ctx, userID)
|
||||
}
|
||||
if err != nil {
|
||||
resp := failResponse(gameOpenCodeServerError, "profile load failed")
|
||||
s.saveCallbackLog(ctx, "query-user", rawJSON, resp, credential.SysOrigin, req, &userID, gameOpenLogStatusFailed)
|
||||
@ -80,12 +85,14 @@ func (s *GameOpenService) HandleUpdateCoin(ctx context.Context, req UpdateCoinRe
|
||||
s.saveCallbackLog(ctx, "update-coin", rawJSON, resp, "", req, nil, gameOpenLogStatusFailed)
|
||||
return resp
|
||||
}
|
||||
userID := int64(credential.UserID)
|
||||
if req.UID != strconv.FormatInt(userID, 10) {
|
||||
resolved, err := s.resolveUserWithToken(ctx, credential, req.UID)
|
||||
if err != nil {
|
||||
resp := failResponse(gameOpenCodeTokenInvalid, "uid token mismatch")
|
||||
userID := int64(credential.UserID)
|
||||
s.saveCallbackLog(ctx, "update-coin", rawJSON, resp, credential.SysOrigin, req, &userID, gameOpenLogStatusFailed)
|
||||
return resp
|
||||
}
|
||||
userID := resolved.userID
|
||||
|
||||
eventID := "GAME_OPEN:" + strings.TrimSpace(req.OrderID)
|
||||
exists, err := s.java.ExistsGoldEvent(ctx, eventID)
|
||||
@ -138,7 +145,12 @@ func (s *GameOpenService) HandleSupplement(ctx context.Context, req SupplementRe
|
||||
return resp
|
||||
}
|
||||
|
||||
userID := parseInt64Default(req.UID)
|
||||
userID, err := s.resolveUserID(ctx, req.UID)
|
||||
if err != nil {
|
||||
resp := failResponse(gameOpenCodeTokenInvalid, "uid invalid")
|
||||
s.saveCallbackLog(ctx, "supplement", rawJSON, resp, "", req, nil, gameOpenLogStatusFailed)
|
||||
return resp
|
||||
}
|
||||
balance, err := s.readUserBalance(ctx, userID)
|
||||
if err != nil {
|
||||
resp := failResponse(gameOpenCodeServerError, "balance load failed")
|
||||
@ -187,6 +199,49 @@ func (s *GameOpenService) readUserBalance(ctx context.Context, userID int64) (in
|
||||
return balances[userID], nil
|
||||
}
|
||||
|
||||
type resolvedGameOpenUser struct {
|
||||
userID int64
|
||||
profile integration.UserProfile
|
||||
}
|
||||
|
||||
func (s *GameOpenService) resolveUserWithToken(ctx context.Context, credential integration.UserCredential, uid string) (resolvedGameOpenUser, error) {
|
||||
userID := int64(credential.UserID)
|
||||
uid = strings.TrimSpace(uid)
|
||||
if uid == strconv.FormatInt(userID, 10) {
|
||||
return resolvedGameOpenUser{userID: userID}, nil
|
||||
}
|
||||
|
||||
profile, err := s.java.GetUserProfileByAccount(ctx, credential.SysOrigin, uid)
|
||||
if err == nil {
|
||||
if int64(profile.ID) == userID {
|
||||
return resolvedGameOpenUser{userID: userID, profile: profile}, nil
|
||||
}
|
||||
return resolvedGameOpenUser{}, fmt.Errorf("uid token mismatch")
|
||||
}
|
||||
|
||||
profile, err = s.java.GetUserProfile(ctx, userID)
|
||||
if err != nil {
|
||||
return resolvedGameOpenUser{}, err
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(profile.Account), uid) {
|
||||
return resolvedGameOpenUser{userID: userID, profile: profile}, nil
|
||||
}
|
||||
return resolvedGameOpenUser{}, fmt.Errorf("uid token mismatch")
|
||||
}
|
||||
|
||||
func (s *GameOpenService) resolveUserID(ctx context.Context, uid string) (int64, error) {
|
||||
uid = strings.TrimSpace(uid)
|
||||
profile, err := s.java.GetUserProfileByAccountOne(ctx, uid)
|
||||
if err == nil && int64(profile.ID) > 0 {
|
||||
return int64(profile.ID), nil
|
||||
}
|
||||
|
||||
if userID := parseInt64Default(uid); userID > 0 {
|
||||
return userID, nil
|
||||
}
|
||||
return 0, fmt.Errorf("uid invalid")
|
||||
}
|
||||
|
||||
func (s *GameOpenService) saveCallbackLog(ctx context.Context, requestType, rawJSON string, resp CallbackResponse, sysOrigin string, req any, userID *int64, status string) {
|
||||
if s == nil || s.repo.DB == nil {
|
||||
return
|
||||
|
||||
@ -11,6 +11,7 @@ type stubGateway struct {
|
||||
credential integration.UserCredential
|
||||
token string
|
||||
profile integration.UserProfile
|
||||
accountMap map[string]integration.UserProfile
|
||||
balance int64
|
||||
exists bool
|
||||
cmd integration.GoldReceiptCommand
|
||||
@ -28,8 +29,34 @@ func (s *stubGateway) GetUserProfile(context.Context, int64) (integration.UserPr
|
||||
return s.profile, nil
|
||||
}
|
||||
|
||||
func (s *stubGateway) GetUserProfileByAccount(_ context.Context, _ string, account string) (integration.UserProfile, error) {
|
||||
if profile, ok := s.accountMap[account]; ok {
|
||||
return profile, nil
|
||||
}
|
||||
return integration.UserProfile{}, context.Canceled
|
||||
}
|
||||
|
||||
func (s *stubGateway) GetUserProfileByAccountOne(_ context.Context, account string) (integration.UserProfile, error) {
|
||||
if profile, ok := s.accountMap[account]; ok {
|
||||
return profile, nil
|
||||
}
|
||||
return integration.UserProfile{}, context.Canceled
|
||||
}
|
||||
|
||||
func (s *stubGateway) MapGoldBalance(context.Context, []int64) (map[int64]int64, error) {
|
||||
return map[int64]int64{int64(s.credential.UserID): s.balance}, nil
|
||||
result := map[int64]int64{}
|
||||
if int64(s.credential.UserID) > 0 {
|
||||
result[int64(s.credential.UserID)] = s.balance
|
||||
}
|
||||
if int64(s.profile.ID) > 0 {
|
||||
result[int64(s.profile.ID)] = s.balance
|
||||
}
|
||||
for _, profile := range s.accountMap {
|
||||
if int64(profile.ID) > 0 {
|
||||
result[int64(profile.ID)] = s.balance
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *stubGateway) ExistsGoldEvent(context.Context, string) (bool, error) {
|
||||
@ -46,6 +73,7 @@ func TestHandleQueryUser(t *testing.T) {
|
||||
credential: integration.UserCredential{UserID: 1234567, SysOrigin: "LIKEI"},
|
||||
profile: integration.UserProfile{
|
||||
ID: 1234567,
|
||||
Account: "1234567",
|
||||
UserNickname: "tester",
|
||||
UserAvatar: "https://example.com/avatar.png",
|
||||
},
|
||||
@ -78,7 +106,11 @@ func TestHandleQueryUser(t *testing.T) {
|
||||
func TestHandleUpdateCoin(t *testing.T) {
|
||||
gateway := &stubGateway{
|
||||
credential: integration.UserCredential{UserID: 1234567, SysOrigin: "LIKEI"},
|
||||
balance: 99,
|
||||
profile: integration.UserProfile{
|
||||
ID: 1234567,
|
||||
Account: "1234567",
|
||||
},
|
||||
balance: 99,
|
||||
}
|
||||
service := NewGameOpenService(config.Config{
|
||||
GameOpen: config.GameOpenConfig{AppKey: "game-open-test-key"},
|
||||
@ -109,6 +141,114 @@ func TestHandleUpdateCoin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleQueryUserAcceptsAccountUID(t *testing.T) {
|
||||
gateway := &stubGateway{
|
||||
credential: integration.UserCredential{UserID: 4569421795454615552, SysOrigin: "LIKEI"},
|
||||
profile: integration.UserProfile{
|
||||
ID: 4569421795454615552,
|
||||
Account: "1234567",
|
||||
UserNickname: "tester",
|
||||
UserAvatar: "https://example.com/avatar.png",
|
||||
},
|
||||
accountMap: map[string]integration.UserProfile{
|
||||
"1234567": {
|
||||
ID: 4569421795454615552,
|
||||
Account: "1234567",
|
||||
UserNickname: "tester",
|
||||
UserAvatar: "https://example.com/avatar.png",
|
||||
},
|
||||
},
|
||||
balance: 88,
|
||||
}
|
||||
service := NewGameOpenService(config.Config{
|
||||
GameOpen: config.GameOpenConfig{AppKey: "game-open-test-key"},
|
||||
}, nil, gateway)
|
||||
req := QueryUserRequest{
|
||||
GameID: "101",
|
||||
UID: "1234567",
|
||||
Token: "token",
|
||||
RoomID: "room-1",
|
||||
}
|
||||
req.Sign = buildQueryUserSign(req, "game-open-test-key")
|
||||
|
||||
resp := service.HandleQueryUser(context.Background(), req, "{}")
|
||||
if resp.ErrorCode != 0 {
|
||||
t.Fatalf("HandleQueryUser() error = %+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleUpdateCoinAcceptsAccountUID(t *testing.T) {
|
||||
gateway := &stubGateway{
|
||||
credential: integration.UserCredential{UserID: 4569421795454615552, SysOrigin: "LIKEI"},
|
||||
accountMap: map[string]integration.UserProfile{
|
||||
"1234567": {
|
||||
ID: 4569421795454615552,
|
||||
Account: "1234567",
|
||||
},
|
||||
},
|
||||
balance: 99,
|
||||
}
|
||||
service := NewGameOpenService(config.Config{
|
||||
GameOpen: config.GameOpenConfig{AppKey: "game-open-test-key"},
|
||||
}, nil, gateway)
|
||||
req := UpdateCoinRequest{
|
||||
OrderID: "order-1",
|
||||
GameID: "101",
|
||||
RoundID: "round-1",
|
||||
UID: "1234567",
|
||||
Coin: 15,
|
||||
Type: 2,
|
||||
RewardType: 2,
|
||||
Token: "token",
|
||||
WinID: "win-1",
|
||||
RoomID: "room-1",
|
||||
}
|
||||
req.Sign = buildUpdateCoinSign(req, "game-open-test-key")
|
||||
|
||||
resp := service.HandleUpdateCoin(context.Background(), req, "{}")
|
||||
if resp.ErrorCode != 0 {
|
||||
t.Fatalf("HandleUpdateCoin() error = %+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleSupplementAcceptsAccountUID(t *testing.T) {
|
||||
gateway := &stubGateway{
|
||||
accountMap: map[string]integration.UserProfile{
|
||||
"1234567": {
|
||||
ID: 4569421795454615552,
|
||||
Account: "1234567",
|
||||
},
|
||||
},
|
||||
balance: 66,
|
||||
}
|
||||
service := NewGameOpenService(config.Config{
|
||||
GameOpen: config.GameOpenConfig{AppKey: "game-open-test-key"},
|
||||
}, nil, gateway)
|
||||
req := SupplementRequest{
|
||||
OrderID: "order-1",
|
||||
GameID: "101",
|
||||
RoundID: "round-1",
|
||||
UID: "1234567",
|
||||
Coin: 1,
|
||||
RewardType: 1,
|
||||
WinID: "win-1",
|
||||
RoomID: "room-1",
|
||||
}
|
||||
req.Sign = buildSupplementSign(req, "game-open-test-key")
|
||||
|
||||
resp := service.HandleSupplement(context.Background(), req, "{}")
|
||||
if resp.ErrorCode != 0 {
|
||||
t.Fatalf("HandleSupplement() error = %+v", resp)
|
||||
}
|
||||
data, ok := resp.Data.(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("HandleSupplement() data type = %T", resp.Data)
|
||||
}
|
||||
if got := data["coin"]; got != int64(66) {
|
||||
t.Fatalf("HandleSupplement() coin = %v, want 66", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIntegrationInfo(t *testing.T) {
|
||||
gateway := &stubGateway{token: "token-123"}
|
||||
service := NewGameOpenService(config.Config{
|
||||
|
||||
@ -29,6 +29,8 @@ type gameOpenGateway interface {
|
||||
AuthenticateToken(ctx context.Context, token string) (integration.UserCredential, error)
|
||||
CreateIfAbsentUserCredentialToken(ctx context.Context, userID int64) (string, error)
|
||||
GetUserProfile(ctx context.Context, userID int64) (integration.UserProfile, error)
|
||||
GetUserProfileByAccount(ctx context.Context, sysOrigin, account string) (integration.UserProfile, error)
|
||||
GetUserProfileByAccountOne(ctx context.Context, account string) (integration.UserProfile, error)
|
||||
MapGoldBalance(ctx context.Context, userIDs []int64) (map[int64]int64, error)
|
||||
ExistsGoldEvent(ctx context.Context, eventID string) (bool, error)
|
||||
ChangeGoldBalance(ctx context.Context, cmd integration.GoldReceiptCommand) error
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user