package roomclient import ( "context" "fmt" "strings" "time" "hyapp-admin-server/internal/appctx" roomv1 "hyapp.local/api/proto/room/v1" "google.golang.org/grpc" ) type Client interface { CloseRoom(ctx context.Context, req CloseRoomRequest) (*CloseRoomResult, error) ReopenRoom(ctx context.Context, req ReopenRoomRequest) (*CloseRoomResult, error) } type CloseRoomRequest struct { RequestID string RoomID string ActorUserID int64 Reason string } type CloseRoomResult struct { Applied bool RoomVersion int64 ServerTimeMs int64 RoomStatus string OnlineUserNum int } type ReopenRoomRequest struct { RequestID string RoomID string ActorUserID int64 } type GRPCClient struct { client roomv1.RoomCommandServiceClient } func NewGRPC(conn grpc.ClientConnInterface) *GRPCClient { return &GRPCClient{client: roomv1.NewRoomCommandServiceClient(conn)} } func (c *GRPCClient) CloseRoom(ctx context.Context, req CloseRoomRequest) (*CloseRoomResult, error) { return c.setRoomLifecycle(ctx, req.RequestID, req.RoomID, req.ActorUserID, firstNonEmpty(req.Reason, "admin_closed")) } func (c *GRPCClient) ReopenRoom(ctx context.Context, req ReopenRoomRequest) (*CloseRoomResult, error) { return c.setRoomLifecycle(ctx, req.RequestID, req.RoomID, req.ActorUserID, "admin_reopen") } func (c *GRPCClient) setRoomLifecycle(ctx context.Context, rawRequestID string, rawRoomID string, actorUserID int64, rawReason string) (*CloseRoomResult, error) { if c == nil || c.client == nil { return nil, fmt.Errorf("room service client is not configured") } roomID := strings.TrimSpace(rawRoomID) reason := strings.TrimSpace(rawReason) if roomID == "" || actorUserID <= 0 || reason == "" { return nil, fmt.Errorf("room lifecycle request is incomplete") } requestID := strings.TrimSpace(rawRequestID) if requestID == "" { requestID = fmt.Sprintf("admin-room-lifecycle-%s-%d", roomID, time.Now().UnixMilli()) } resp, err := c.client.CloseRoom(ctx, &roomv1.CloseRoomRequest{ Meta: &roomv1.RequestMeta{ RequestId: requestID, CommandId: commandID(requestID, reason, roomID), ActorUserId: actorUserID, RoomId: roomID, AppCode: appctx.FromContext(ctx), SentAtMs: time.Now().UnixMilli(), }, Reason: reason, }) if err != nil { return nil, err } result := resp.GetResult() room := resp.GetRoom() return &CloseRoomResult{ Applied: result.GetApplied(), RoomVersion: result.GetRoomVersion(), ServerTimeMs: result.GetServerTimeMs(), RoomStatus: room.GetStatus(), OnlineUserNum: len(room.GetOnlineUsers()), }, nil } func commandID(requestID string, reason string, roomID string) string { base := strings.TrimSpace(requestID) if base == "" { base = fmt.Sprintf("admin-room-lifecycle-%d", time.Now().UnixMilli()) } value := base + ":" + strings.TrimSpace(reason) + ":" + strings.TrimSpace(roomID) if len(value) <= 128 { return value } return value[:128] } func firstNonEmpty(values ...string) string { for _, value := range values { if strings.TrimSpace(value) != "" { return value } } return "" }