v0.0.17.3 Переработан websocket, добавлена обработка ping/pong
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
039c8447a7
commit
db667f224b
@ -159,17 +159,22 @@ func (r *mutationResolver) SendMessage(ctx context.Context, receiverID int, cont
|
|||||||
return nil, errors.New("не авторизован")
|
return nil, errors.New("не авторизован")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверяем, что не отправляем сообщение себе
|
|
||||||
if senderID == receiverID {
|
|
||||||
return nil, errors.New("cannot send message to yourself")
|
|
||||||
}
|
|
||||||
|
|
||||||
chat, err := r.Services.Chat.GetOrCreateChat(ctx, senderID, receiverID)
|
chat, err := r.Services.Chat.GetOrCreateChat(ctx, senderID, receiverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ошибка создания чата: %v", err)
|
return nil, fmt.Errorf("ошибка создания чата: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Services.Chat.SendMessage(ctx, senderID, chat.ID, content)
|
message, err := r.Services.Chat.SendMessage(ctx, senderID, chat.ID, content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Рассылаем сообщение через WebSocket
|
||||||
|
if r.Services.ChatHub != nil {
|
||||||
|
r.Services.ChatHub.Broadcast(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return message, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkAsRead - помечает сообщение как прочитанное
|
// MarkAsRead - помечает сообщение как прочитанное
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"tailly_back_v2/internal/service"
|
"tailly_back_v2/internal/service"
|
||||||
"tailly_back_v2/internal/ws"
|
"tailly_back_v2/internal/ws"
|
||||||
"tailly_back_v2/pkg/auth"
|
"tailly_back_v2/pkg/auth"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
@ -105,13 +106,17 @@ func (h *ChatHandler) HandleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ChatHandler) readPump(ctx context.Context, conn *websocket.Conn, client *ws.Client, userID int) {
|
func (h *ChatHandler) readPump(ctx context.Context, conn *websocket.Conn, client *ws.Client, userID int) {
|
||||||
defer func() {
|
ticker := time.NewTicker(30 * time.Second)
|
||||||
h.hub.UnregisterClient(client)
|
defer ticker.Stop()
|
||||||
conn.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
// Отправляем ping
|
||||||
|
if err := conn.WriteJSON(map[string]string{"type": "ping"}); err != nil {
|
||||||
|
log.Printf("Ping error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
@ -125,11 +130,15 @@ func (h *ChatHandler) readPump(ctx context.Context, conn *websocket.Conn, client
|
|||||||
|
|
||||||
if err := conn.ReadJSON(&msg); err != nil {
|
if err := conn.ReadJSON(&msg); err != nil {
|
||||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
||||||
log.Printf("WebSocket read error: %v", err)
|
log.Printf("WebSocket error: %v", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg.Type == "pong" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Обработка ping/pong
|
// Обработка ping/pong
|
||||||
if msg.Type == "ping" {
|
if msg.Type == "ping" {
|
||||||
conn.WriteJSON(map[string]string{"type": "pong"})
|
conn.WriteJSON(map[string]string{"type": "pong"})
|
||||||
|
|||||||
@ -39,30 +39,38 @@ func (s *chatService) SendMessage(ctx context.Context, senderID, chatID int, con
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверяем, что отправитель является участником чата
|
||||||
if senderID != chat.User1ID && senderID != chat.User2ID {
|
if senderID != chat.User1ID && senderID != chat.User2ID {
|
||||||
return nil, errors.New("user is not a participant of this chat")
|
return nil, errors.New("user is not a participant of this chat")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Определяем получателя
|
||||||
receiverID := chat.User1ID
|
receiverID := chat.User1ID
|
||||||
if senderID == chat.User1ID {
|
if senderID == chat.User1ID {
|
||||||
receiverID = chat.User2ID
|
receiverID = chat.User2ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Создаем сообщение
|
||||||
message := &domain.Message{
|
message := &domain.Message{
|
||||||
ChatID: chatID,
|
ChatID: chatID,
|
||||||
SenderID: senderID,
|
SenderID: senderID,
|
||||||
ReceiverID: receiverID,
|
ReceiverID: receiverID, // Гарантируем что receiverID всегда установлен
|
||||||
Content: content,
|
Content: content,
|
||||||
Status: "sent",
|
Status: "sent",
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Сохраняем в БД
|
||||||
if err := s.chatRepo.SaveMessage(ctx, message); err != nil {
|
if err := s.chatRepo.SaveMessage(ctx, message); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправляем сообщение через WebSocket
|
// Отправляем через WebSocket только один раз
|
||||||
if s.hub != nil {
|
if s.hub != nil {
|
||||||
|
// Добавляем проверку перед рассылкой
|
||||||
|
if message.ReceiverID == 0 {
|
||||||
|
return nil, errors.New("receiver ID is required")
|
||||||
|
}
|
||||||
s.hub.Broadcast(message)
|
s.hub.Broadcast(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package ws
|
package ws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"tailly_back_v2/internal/domain"
|
"tailly_back_v2/internal/domain"
|
||||||
)
|
)
|
||||||
@ -36,6 +37,16 @@ func (h *Hub) UnregisterClient(client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hub) Broadcast(message *domain.Message) {
|
func (h *Hub) Broadcast(message *domain.Message) {
|
||||||
|
if message == nil || message.SenderID == 0 {
|
||||||
|
log.Println("Attempt to broadcast invalid message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.ReceiverID == 0 {
|
||||||
|
log.Printf("Message %d has no receiver", message.ID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
h.broadcast <- message
|
h.broadcast <- message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user