package services import ( "agent-desk/internal/models" "agent-desk/internal/pkg/constants" "agent-desk/internal/pkg/enums" "agent-desk/internal/repositories" "github.com/mlogclub/simple/sqls" "log/slog" "slices" "time" ) const agentPresenceLeaseTTL = 90 * time.Second const agentPresenceDisconnectGrace = 15 * time.Second const agentPresenceRenewInterval = 15 * time.Second func (s *wsService) renewAgentPresence(session *ClientSession) { if session == nil || session.Closed.Load() || session.Principal == nil || (session.Role != realtimeRoleAdmin && session.Role != realtimeRoleNotification) { return } session.presenceMu.Lock() dispatchPending := false defer func() { session.presenceMu.Unlock() // Finish the presence write before dispatching, and keep ownership in // this call rather than launching an untracked database goroutine. if dispatchPending { _, _ = ConversationDispatchService.DispatchPendingConversations(0) } }() if session.PresenceEnded { return } principal := session.Principal if principal.UserType != enums.UserTypeEmployee || !slices.Contains(principal.Permissions, constants.PermissionConversationView.Code) { return } now := time.Now() last := session.PresenceRenewedAt.Load() if now.Unix()-last < int64(agentPresenceRenewInterval/time.Second) { return } if !session.PresenceRenewedAt.CompareAndSwap(last, now.Unix()) { return } // The internal ID is generated independently per connection, across processes. expires := now.Add(agentPresenceLeaseTTL) if principal.ExpiresAt.Before(expires) { expires = principal.ExpiresAt } lease := models.AgentPresenceLease{ID: session.PresenceLeaseID, UserID: principal.UserID, LoginSessionID: principal.LoginSessionID, ExpiresAt: expires} if lease.ID == "" { return } if err := repositories.SupportAvailabilityRepository.RenewPresence(sqls.DB(), &lease); err != nil { slog.Warn("support presence renewal failed") return } if last == 0 { dispatchPending = true } } func (s *wsService) endAgentPresence(session *ClientSession) { if session == nil { return } session.presenceMu.Lock() defer session.presenceMu.Unlock() session.PresenceEnded = true if session.PresenceLeaseID == "" || session.PresenceRenewedAt.Load() == 0 { return } if err := repositories.SupportAvailabilityRepository.EndPresence(sqls.DB(), session.PresenceLeaseID, time.Now().Add(agentPresenceDisconnectGrace)); err != nil { slog.Warn("support presence disconnect update failed") } }