mirror of
https://github.com/abhinavxd/libredesk.git
synced 2026-09-22 02:23:32 +00:00
13db8d2843
Improve sidebar navigation to retain open conversation Fix notification when disabled app still tries sending emails.
168 lines
6.0 KiB
Go
168 lines
6.0 KiB
Go
package conversation
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
|
|
cmodels "github.com/abhinavxd/libredesk/internal/conversation/models"
|
|
"github.com/abhinavxd/libredesk/internal/inbox"
|
|
"github.com/abhinavxd/libredesk/internal/inbox/channel/livechat"
|
|
wsmodels "github.com/abhinavxd/libredesk/internal/ws/models"
|
|
)
|
|
|
|
// BroadcastNewMessage broadcasts a new message to all users.
|
|
// lastMessage is the computed preview text (e.g., "Image" for media-only messages).
|
|
func (m *Manager) BroadcastNewMessage(message *cmodels.Message, lastMessage string) {
|
|
data := map[string]any{
|
|
"conversation_uuid": message.ConversationUUID,
|
|
"content": "",
|
|
"created_at": message.CreatedAt.Format(time.RFC3339),
|
|
"uuid": message.UUID,
|
|
"private": message.Private,
|
|
"type": message.Type,
|
|
"sender_type": message.SenderType,
|
|
}
|
|
|
|
// Include echo_id from meta so clients can match WS events to pending messages.
|
|
var meta map[string]any
|
|
if len(message.Meta) > 0 {
|
|
if err := json.Unmarshal(message.Meta, &meta); err == nil {
|
|
if echoID, ok := meta["echo_id"].(string); ok && echoID != "" {
|
|
data["echo_id"] = echoID
|
|
}
|
|
}
|
|
}
|
|
|
|
m.broadcastToUsers([]int{}, wsmodels.Message{
|
|
Type: wsmodels.MessageTypeNewMessage,
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
// BroadcastMessageUpdate broadcasts a partial message update to all users.
|
|
func (m *Manager) BroadcastMessageUpdate(conversationUUID, messageUUID string, data map[string]any) {
|
|
data["conversation_uuid"] = conversationUUID
|
|
data["uuid"] = messageUUID
|
|
m.broadcastToUsers([]int{}, wsmodels.Message{
|
|
Type: wsmodels.MessageTypeMessageUpdate,
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
// BroadcastConversationUpdate broadcasts a partial conversation update to all agent clients.
|
|
func (m *Manager) BroadcastConversationUpdate(conversationUUID string, data map[string]any) {
|
|
data["uuid"] = conversationUUID
|
|
m.broadcastToUsers([]int{}, wsmodels.Message{
|
|
Type: wsmodels.MessageTypeConversationUpdate,
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
// BroadcastContactUpdate broadcasts a contact update to all agent clients.
|
|
func (m *Manager) BroadcastContactUpdate(contactID int, data map[string]any) {
|
|
data["contact_id"] = contactID
|
|
m.broadcastToUsers([]int{}, wsmodels.Message{
|
|
Type: "contact_update",
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
// BroadcastTypingToConversation broadcasts typing status to all subscribers of a conversation.
|
|
// Set broadcastToWidgets to false when the typing event originates from a widget client to avoid echo.
|
|
func (m *Manager) BroadcastTypingToConversation(conversationUUID string, isTyping bool, broadcastToWidgets bool) {
|
|
message := wsmodels.Message{
|
|
Type: wsmodels.MessageTypeTyping,
|
|
Data: map[string]any{
|
|
"conversation_uuid": conversationUUID,
|
|
"is_typing": isTyping,
|
|
},
|
|
}
|
|
|
|
messageBytes, err := json.Marshal(message)
|
|
if err != nil {
|
|
m.lo.Error("error marshalling typing WS message", "error", err)
|
|
return
|
|
}
|
|
|
|
// Always broadcast to agent clients (main app WebSocket clients)
|
|
m.wsHub.BroadcastTypingToAllConversationClients(conversationUUID, messageBytes)
|
|
|
|
// Broadcast to widget clients (customers) only if this typing event comes from agents
|
|
if broadcastToWidgets {
|
|
m.broadcastTypingToWidgetClients(conversationUUID, isTyping)
|
|
}
|
|
}
|
|
|
|
// BroadcastTypingToWidgetClientsOnly broadcasts typing status only to widget clients.
|
|
func (m *Manager) BroadcastTypingToWidgetClientsOnly(conversationUUID string, isTyping bool) {
|
|
m.broadcastTypingToWidgetClients(conversationUUID, isTyping)
|
|
}
|
|
|
|
// broadcastToUsers broadcasts a message to a list of users, if the list is empty it broadcasts to all users.
|
|
func (m *Manager) broadcastToUsers(userIDs []int, message wsmodels.Message) {
|
|
messageBytes, err := json.Marshal(message)
|
|
if err != nil {
|
|
m.lo.Error("error marshalling WS message", "error", err)
|
|
return
|
|
}
|
|
m.wsHub.BroadcastMessage(wsmodels.BroadcastMessage{
|
|
Data: messageBytes,
|
|
Users: userIDs,
|
|
})
|
|
}
|
|
|
|
// broadcastTypingToWidgetClients broadcasts typing status to widget clients (customers) for a conversation.
|
|
func (m *Manager) broadcastTypingToWidgetClients(conversationUUID string, isTyping bool) {
|
|
conversation, err := m.GetConversation(0, conversationUUID, "")
|
|
if err != nil {
|
|
m.lo.Error("error getting conversation for widget typing broadcast", "error", err, "conversation_uuid", conversationUUID)
|
|
return
|
|
}
|
|
|
|
inboxInstance, err := m.inboxStore.Get(conversation.InboxID)
|
|
if err != nil {
|
|
m.lo.Error("error getting inbox for widget typing broadcast", "error", err, "inbox_id", conversation.InboxID)
|
|
return
|
|
}
|
|
|
|
if liveChatInbox, ok := inboxInstance.(*livechat.LiveChat); ok {
|
|
liveChatInbox.BroadcastTypingToClients(conversationUUID, conversation.ContactID, isTyping)
|
|
}
|
|
}
|
|
|
|
// BroadcastAgentStatusToWidget sends a lightweight assignee availability update
|
|
// to widget clients for all active livechat conversations assigned to the given agent.
|
|
func (m *Manager) BroadcastAgentStatusToWidget(agentID int, status string) {
|
|
var conversations []struct {
|
|
UUID string `db:"uuid"`
|
|
ContactID int `db:"contact_id"`
|
|
InboxID int `db:"inbox_id"`
|
|
}
|
|
if err := m.q.GetActiveLivechatConversationsByAgent.Select(&conversations, agentID); err != nil {
|
|
m.lo.Error("error fetching active livechat conversations for agent", "error", err, "agent_id", agentID)
|
|
return
|
|
}
|
|
for _, conv := range conversations {
|
|
m.BroadcastConversationToWidget(conv.UUID, conv.ContactID, conv.InboxID, map[string]any{
|
|
"assignee": map[string]any{"availability_status": status},
|
|
})
|
|
}
|
|
}
|
|
|
|
// BroadcastConversationToWidget broadcasts a partial conversation update to widget clients.
|
|
func (m *Manager) BroadcastConversationToWidget(conversationUUID string, contactID, inboxID int, data map[string]any) {
|
|
inboxInstance, err := m.inboxStore.Get(inboxID)
|
|
if err != nil {
|
|
if err == inbox.ErrInboxNotFound {
|
|
return
|
|
}
|
|
m.lo.Error("error getting inbox for widget conversation broadcast", "error", err, "inbox_id", inboxID)
|
|
return
|
|
}
|
|
|
|
if liveChatInbox, ok := inboxInstance.(*livechat.LiveChat); ok {
|
|
data["uuid"] = conversationUUID
|
|
liveChatInbox.BroadcastConversationToClients(conversationUUID, contactID, data)
|
|
}
|
|
}
|