84 lines
2.2 KiB
Go
84 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// EngagementState tracks whether a user is in an active conversation.
|
|
type EngagementState int
|
|
|
|
const (
|
|
Sleeping EngagementState = 0
|
|
Active EngagementState = 1
|
|
)
|
|
|
|
// engagementSession tracks a single user's active conversation.
|
|
type engagementSession struct {
|
|
userID string
|
|
channelID string
|
|
state EngagementState
|
|
lastActive time.Time
|
|
}
|
|
|
|
// EngagementEngine manages active conversations per user+channel.
|
|
// When a user @mentions the bot, they enter an Active session.
|
|
// Their subsequent non-@mention messages in the same channel
|
|
// are treated as continuations until a stop word or timeout.
|
|
type EngagementEngine struct {
|
|
mu sync.Mutex
|
|
sessions map[string]*engagementSession
|
|
timeout time.Duration
|
|
}
|
|
|
|
// NewEngagementEngine creates a new engine with the given inactivity timeout.
|
|
func NewEngagementEngine() *EngagementEngine {
|
|
return &EngagementEngine{
|
|
sessions: make(map[string]*engagementSession),
|
|
timeout: 5 * time.Minute,
|
|
}
|
|
}
|
|
|
|
// sessionKey builds a unique key per user+channel.
|
|
func (e *EngagementEngine) sessionKey(userID, channelID string) string {
|
|
return userID + ":" + channelID
|
|
}
|
|
|
|
// Wake marks a user+channel as actively engaged with the bot.
|
|
func (e *EngagementEngine) Wake(userID, channelID string) {
|
|
e.mu.Lock()
|
|
defer e.mu.Unlock()
|
|
key := e.sessionKey(userID, channelID)
|
|
e.sessions[key] = &engagementSession{
|
|
userID: userID,
|
|
channelID: channelID,
|
|
state: Active,
|
|
lastActive: time.Now(),
|
|
}
|
|
}
|
|
|
|
// IsActive returns true if the user+channel is in an active conversation.
|
|
func (e *EngagementEngine) IsActive(userID, channelID string) bool {
|
|
e.mu.Lock()
|
|
defer e.mu.Unlock()
|
|
key := e.sessionKey(userID, channelID)
|
|
s, exists := e.sessions[key]
|
|
if !exists {
|
|
return false
|
|
}
|
|
if time.Since(s.lastActive) > e.timeout {
|
|
delete(e.sessions, key)
|
|
return false
|
|
}
|
|
s.lastActive = time.Now()
|
|
return true
|
|
}
|
|
|
|
// Sleep ends the active conversation for a user+channel.
|
|
func (e *EngagementEngine) Sleep(userID, channelID string) {
|
|
e.mu.Lock()
|
|
defer e.mu.Unlock()
|
|
key := e.sessionKey(userID, channelID)
|
|
delete(e.sessions, key)
|
|
}
|