136 lines
4.1 KiB
Go
136 lines
4.1 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"tailly_back_v2/internal/domain"
|
|
"tailly_back_v2/internal/repository"
|
|
"tailly_back_v2/internal/ws"
|
|
"time"
|
|
)
|
|
|
|
type ChatService interface {
|
|
SendMessage(ctx context.Context, senderID, chatID int, content string) (*domain.Message, error)
|
|
GetChatMessages(ctx context.Context, chatID, userID int, limit, offset int) ([]*domain.Message, error)
|
|
MarkAsRead(ctx context.Context, messageID int) error
|
|
DeleteMessage(ctx context.Context, messageID, userID int) error
|
|
GetUserChats(ctx context.Context, userID int) ([]*domain.Chat, error)
|
|
GetOrCreateChat(ctx context.Context, user1ID, user2ID int) (*domain.Chat, error)
|
|
GetUnreadCount(ctx context.Context, chatID, userID int) (int, error)
|
|
GetChatByID(ctx context.Context, id int) (*domain.Chat, error)
|
|
}
|
|
|
|
type chatService struct {
|
|
chatRepo repository.ChatRepository
|
|
userRepo repository.UserRepository
|
|
hub *ws.Hub
|
|
}
|
|
|
|
func NewChatService(chatRepo repository.ChatRepository, userRepo repository.UserRepository, hub *ws.Hub) ChatService {
|
|
return &chatService{
|
|
chatRepo: chatRepo,
|
|
userRepo: userRepo,
|
|
hub: hub,
|
|
}
|
|
}
|
|
|
|
func (s *chatService) SendMessage(ctx context.Context, senderID, chatID int, content string) (*domain.Message, error) {
|
|
chat, err := s.chatRepo.GetChatByID(ctx, chatID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Проверяем, что отправитель является участником чата
|
|
if senderID != chat.User1ID && senderID != chat.User2ID {
|
|
return nil, errors.New("user is not a participant of this chat")
|
|
}
|
|
|
|
// Определяем получателя
|
|
receiverID := chat.User1ID
|
|
if senderID == chat.User1ID {
|
|
receiverID = chat.User2ID
|
|
}
|
|
|
|
// Создаем сообщение
|
|
message := &domain.Message{
|
|
ChatID: chatID,
|
|
SenderID: senderID,
|
|
ReceiverID: receiverID, // Гарантируем что receiverID всегда установлен
|
|
Content: content,
|
|
Status: "sent",
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
// Сохраняем в БД
|
|
if err := s.chatRepo.SaveMessage(ctx, message); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Отправляем через WebSocket только один раз
|
|
if s.hub != nil {
|
|
// Добавляем проверку перед рассылкой
|
|
if message.ReceiverID == 0 {
|
|
return nil, errors.New("receiver ID is required")
|
|
}
|
|
s.hub.Broadcast(message)
|
|
}
|
|
|
|
return message, nil
|
|
}
|
|
|
|
func (s *chatService) GetChatMessages(ctx context.Context, chatID, userID int, limit, offset int) ([]*domain.Message, error) {
|
|
// Проверяем доступ пользователя к чату
|
|
chat, err := s.chatRepo.GetChatByID(ctx, chatID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if userID != chat.User1ID && userID != chat.User2ID {
|
|
return nil, errors.New("access denied")
|
|
}
|
|
|
|
return s.chatRepo.GetMessagesByChat(ctx, chatID, limit, offset)
|
|
}
|
|
|
|
func (s *chatService) MarkAsRead(ctx context.Context, messageID int) error {
|
|
return s.chatRepo.UpdateMessageStatus(ctx, messageID, "read")
|
|
}
|
|
|
|
func (s *chatService) DeleteMessage(ctx context.Context, messageID, userID int) error {
|
|
message, err := s.chatRepo.GetMessageByID(ctx, messageID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if message.SenderID != userID {
|
|
return errors.New("only sender can delete the message")
|
|
}
|
|
|
|
return s.chatRepo.DeleteMessage(ctx, messageID)
|
|
}
|
|
|
|
func (s *chatService) GetUserChats(ctx context.Context, userID int) ([]*domain.Chat, error) {
|
|
return s.chatRepo.GetUserChats(ctx, userID)
|
|
}
|
|
|
|
func (s *chatService) GetOrCreateChat(ctx context.Context, user1ID, user2ID int) (*domain.Chat, error) {
|
|
// Проверяем существование чата
|
|
chat, err := s.chatRepo.GetChatByParticipants(ctx, user1ID, user2ID)
|
|
if err == nil {
|
|
return chat, nil
|
|
}
|
|
|
|
if !errors.Is(err, repository.ErrChatNotFound) {
|
|
return nil, err
|
|
}
|
|
|
|
// Создаем новый чат
|
|
return s.chatRepo.CreateChat(ctx, user1ID, user2ID)
|
|
}
|
|
func (s *chatService) GetUnreadCount(ctx context.Context, chatID, userID int) (int, error) {
|
|
return s.chatRepo.GetUnreadCount(ctx, chatID, userID)
|
|
}
|
|
func (s *chatService) GetChatByID(ctx context.Context, id int) (*domain.Chat, error) {
|
|
return s.chatRepo.GetChatByID(ctx, id)
|
|
}
|