修复上麦失败问题

This commit is contained in:
zhx 2026-07-03 22:55:56 +08:00
parent 026a354b04
commit b83c3f38d4
2 changed files with 55 additions and 3 deletions

View File

@ -38,9 +38,16 @@ func (s *Service) MicUp(ctx context.Context, req *roomv1.MicUpRequest) (*roomv1.
return mutationResult{}, nil, xerr.New(xerr.NotFound, "user not in room")
}
if _, exists := current.SeatByUser(cmd.ActorUserID()); exists {
// 一个用户同一时间只能占一个麦位。
return mutationResult{}, nil, xerr.New(xerr.Conflict, "user already on seat")
if seat, exists := current.SeatByUser(cmd.ActorUserID()); exists {
// MicUp 是客户端“确保自己在麦上”的入口;重复点击或网络重试如果换了 command_id
// 当前业务目标已经满足,直接返回现有麦位会话,避免把首次成功覆盖成用户可见失败。
// 真正换麦必须继续走 ChangeMicSeat不能让重复 MicUp 隐式迁移麦位。
return mutationResult{
snapshot: current.ToProto(),
seatNo: seat.SeatNo,
micSessionID: seat.MicSessionID,
publishDeadlineMS: seat.PublishDeadlineMS,
}, nil, nil
}
index := current.SeatIndex(cmd.SeatNo)

View File

@ -9,6 +9,51 @@ import (
"hyapp/services/room-service/internal/testutil/mysqltest"
)
func TestMicUpReturnsExistingSeatForDuplicateUserCommand(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
now := &fixedRoomRocketClock{now: time.Date(2026, 6, 4, 8, 0, 0, 0, time.UTC)}
svc := newRocketTestService(t, repository, &rocketTestWallet{}, now)
roomID := "room-mic-up-duplicate-user"
ownerID := int64(8501)
speakerID := int64(8502)
createRocketRoom(t, ctx, svc, roomID, ownerID, 9101)
joinRocketRoom(t, ctx, svc, roomID, speakerID)
upResp, err := svc.MicUp(ctx, &roomv1.MicUpRequest{
Meta: rocketMeta(roomID, speakerID, "mic-up-duplicate-user-first"),
SeatNo: 2,
})
if err != nil {
t.Fatalf("first mic up failed: %v", err)
}
duplicateResp, err := svc.MicUp(ctx, &roomv1.MicUpRequest{
Meta: rocketMeta(roomID, speakerID, "mic-up-duplicate-user-second"),
SeatNo: 3,
})
if err != nil {
t.Fatalf("duplicate mic up must return current session instead of conflict: %v", err)
}
if duplicateResp.GetResult().GetApplied() {
t.Fatalf("duplicate mic up must be a no-op mutation: %+v", duplicateResp.GetResult())
}
if duplicateResp.GetRoom().GetVersion() != upResp.GetRoom().GetVersion() {
t.Fatalf("duplicate mic up must not advance room version: got=%d want=%d", duplicateResp.GetRoom().GetVersion(), upResp.GetRoom().GetVersion())
}
if duplicateResp.GetSeatNo() != 2 || duplicateResp.GetMicSessionId() != upResp.GetMicSessionId() || duplicateResp.GetPublishDeadlineMs() != upResp.GetPublishDeadlineMs() {
t.Fatalf("duplicate mic up must return original mic session: duplicate=%+v first=%+v", duplicateResp, upResp)
}
if originalSeat := seatByNo(duplicateResp.GetRoom(), 2); originalSeat == nil || originalSeat.GetUserId() != speakerID || originalSeat.GetMicSessionId() != upResp.GetMicSessionId() {
t.Fatalf("original seat must remain occupied by speaker: %+v", originalSeat)
}
if requestedSeat := seatByNo(duplicateResp.GetRoom(), 3); requestedSeat == nil || requestedSeat.GetUserId() != 0 {
// 重复 MicUp 只能表达“我已经在麦上”的幂等结果;换到 seat 3 必须走 ChangeMicSeat。
t.Fatalf("duplicate mic up must not move user to requested seat: %+v", requestedSeat)
}
}
func TestMicHeartbeatRefreshesPublishingSessionAndPresence(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)