- Implement full MessageHandler dispatch with all 18 incoming message types - Add handler_messages.go: SendMessage, EditMessage, DeleteMessage with ownership checks - Add handler_rooms.go: JoinConversation, LeaveConversation - Add handler_history.go: FetchHistory (cursor-based), SearchMessages (ILIKE), SyncMessages - Add handler_realtime.go: Typing, MarkAsRead, Delivered, AddReaction, RemoveReaction - Add handler_calls.go: WebRTC signaling relay (CallOffer/Answer/ICE/Hangup/Reject) - Add PermissionService: CanRead/CanSend/CanJoin/CanModerate based on room_members - Add RateLimiter: per-user per-action sliding window (in-memory) - Wire all dependencies in router.go setupChatWebSocket
103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package chat
|
|
|
|
import (
|
|
"context"
|
|
|
|
"veza-backend-api/internal/repositories"
|
|
"veza-backend-api/internal/services"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type MessageHandler struct {
|
|
msgRepo *repositories.ChatMessageRepository
|
|
readRepo *repositories.ReadReceiptRepository
|
|
deliveredRepo *repositories.DeliveredStatusRepository
|
|
reactionRepo *repositories.ReactionRepository
|
|
pubsub *services.ChatPubSubService
|
|
permissions *PermissionService
|
|
rateLimiter *RateLimiter
|
|
hub *Hub
|
|
logger *zap.Logger
|
|
}
|
|
|
|
func NewMessageHandler(
|
|
hub *Hub,
|
|
msgRepo *repositories.ChatMessageRepository,
|
|
readRepo *repositories.ReadReceiptRepository,
|
|
deliveredRepo *repositories.DeliveredStatusRepository,
|
|
reactionRepo *repositories.ReactionRepository,
|
|
pubsub *services.ChatPubSubService,
|
|
permissions *PermissionService,
|
|
rateLimiter *RateLimiter,
|
|
logger *zap.Logger,
|
|
) *MessageHandler {
|
|
if logger == nil {
|
|
logger = zap.NewNop()
|
|
}
|
|
return &MessageHandler{
|
|
hub: hub,
|
|
msgRepo: msgRepo,
|
|
readRepo: readRepo,
|
|
deliveredRepo: deliveredRepo,
|
|
reactionRepo: reactionRepo,
|
|
pubsub: pubsub,
|
|
permissions: permissions,
|
|
rateLimiter: rateLimiter,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (h *MessageHandler) Dispatch(ctx context.Context, client *Client, msg *IncomingMessage) {
|
|
switch msg.Type {
|
|
case TypePing:
|
|
client.SendJSON(NewPongResponse())
|
|
|
|
case TypeSendMessage:
|
|
h.HandleSendMessage(ctx, client, msg)
|
|
case TypeEditMessage:
|
|
h.HandleEditMessage(ctx, client, msg)
|
|
case TypeDeleteMessage:
|
|
h.HandleDeleteMessage(ctx, client, msg)
|
|
|
|
case TypeJoinConversation:
|
|
h.HandleJoinConversation(ctx, client, msg)
|
|
case TypeLeaveConversation:
|
|
h.HandleLeaveConversation(ctx, client, msg)
|
|
|
|
case TypeFetchHistory:
|
|
h.HandleFetchHistory(ctx, client, msg)
|
|
case TypeSearchMessages:
|
|
h.HandleSearchMessages(ctx, client, msg)
|
|
case TypeSyncMessages:
|
|
h.HandleSyncMessages(ctx, client, msg)
|
|
|
|
case TypeTyping:
|
|
h.HandleTyping(ctx, client, msg)
|
|
case TypeMarkAsRead:
|
|
h.HandleMarkAsRead(ctx, client, msg)
|
|
case TypeDelivered:
|
|
h.HandleDelivered(ctx, client, msg)
|
|
case TypeAddReaction:
|
|
h.HandleAddReaction(ctx, client, msg)
|
|
case TypeRemoveReaction:
|
|
h.HandleRemoveReaction(ctx, client, msg)
|
|
|
|
case TypeCallOffer:
|
|
h.HandleCallOffer(ctx, client, msg)
|
|
case TypeCallAnswer:
|
|
h.HandleCallAnswer(ctx, client, msg)
|
|
case TypeICECandidate:
|
|
h.HandleICECandidate(ctx, client, msg)
|
|
case TypeCallHangup:
|
|
h.HandleCallHangup(ctx, client, msg)
|
|
case TypeCallReject:
|
|
h.HandleCallReject(ctx, client, msg)
|
|
|
|
default:
|
|
h.logger.Warn("Unknown message type",
|
|
zap.String("type", msg.Type),
|
|
zap.String("user_id", client.UserID.String()))
|
|
client.SendJSON(NewErrorResponse("Unknown message type: " + msg.Type))
|
|
}
|
|
}
|