feat: RHS panel initial fetch, floating widget, session cleanup (#5)
Phase 1: Fix RHS panel to fetch existing sessions on mount - Add initial API fetch in useAllStatusUpdates() hook - Allow GET /sessions endpoint without shared secret auth - RHS panel now shows sessions after page refresh Phase 2: Floating widget component (registerRootComponent) - New floating_widget.tsx with auto-show/hide behavior - Draggable, collapsible to pulsing dot with session count - Shows last 5 lines of most recent active session - Position persisted to localStorage - CSS styles using Mattermost theme variables Phase 3: Session cleanup and KV optimization - Add LastUpdateMs field to SessionData for staleness tracking - Set LastUpdateMs on session create and update - Add periodic cleanup goroutine (every 5 min) - Stale active sessions (>30 min no update) marked interrupted - Expired non-active sessions (>1 hr) deleted from KV - Add ListAllSessions and keep ListActiveSessions as helper - Add debug logging to daemon file polling Closes #5
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/plugin"
|
||||
)
|
||||
@@ -22,8 +23,9 @@ type SessionData struct {
|
||||
Lines []string `json:"lines"`
|
||||
ElapsedMs int64 `json:"elapsed_ms"`
|
||||
TokenCount int `json:"token_count"`
|
||||
Children []SessionData `json:"children,omitempty"`
|
||||
StartTimeMs int64 `json:"start_time_ms"`
|
||||
Children []SessionData `json:"children,omitempty"`
|
||||
StartTimeMs int64 `json:"start_time_ms"`
|
||||
LastUpdateMs int64 `json:"last_update_ms"`
|
||||
}
|
||||
|
||||
// Store wraps Mattermost KV store operations for session persistence.
|
||||
@@ -79,8 +81,8 @@ func (s *Store) DeleteSession(sessionKey string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListActiveSessions returns all active sessions from the KV store.
|
||||
func (s *Store) ListActiveSessions() ([]SessionData, error) {
|
||||
// ListAllSessions returns all sessions from the KV store (active and non-active).
|
||||
func (s *Store) ListAllSessions() ([]SessionData, error) {
|
||||
var sessions []SessionData
|
||||
page := 0
|
||||
perPage := 100
|
||||
@@ -106,12 +108,59 @@ func (s *Store) ListActiveSessions() ([]SessionData, error) {
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
continue
|
||||
}
|
||||
if data.Status == "active" {
|
||||
sessions = append(sessions, data)
|
||||
}
|
||||
sessions = append(sessions, data)
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
return sessions, nil
|
||||
}
|
||||
|
||||
// ListActiveSessions returns only active sessions from the KV store.
|
||||
func (s *Store) ListActiveSessions() ([]SessionData, error) {
|
||||
all, err := s.ListAllSessions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var active []SessionData
|
||||
for _, sess := range all {
|
||||
if sess.Status == "active" {
|
||||
active = append(active, sess)
|
||||
}
|
||||
}
|
||||
return active, nil
|
||||
}
|
||||
|
||||
// CleanStaleSessions marks stale active sessions as interrupted and deletes expired completed sessions.
|
||||
// staleThresholdMs: active sessions with no update for this long are marked interrupted.
|
||||
// expireThresholdMs: non-active sessions older than this are deleted from KV.
|
||||
func (s *Store) CleanStaleSessions(staleThresholdMs, expireThresholdMs int64) (cleaned int, expired int, err error) {
|
||||
now := time.Now().UnixMilli()
|
||||
all, err := s.ListAllSessions()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
for _, session := range all {
|
||||
lastUpdate := session.LastUpdateMs
|
||||
if lastUpdate == 0 {
|
||||
lastUpdate = session.StartTimeMs
|
||||
}
|
||||
if lastUpdate == 0 {
|
||||
continue
|
||||
}
|
||||
age := now - lastUpdate
|
||||
|
||||
if session.Status == "active" && age > staleThresholdMs {
|
||||
// Mark stale sessions as interrupted
|
||||
session.Status = "interrupted"
|
||||
session.LastUpdateMs = now
|
||||
_ = s.SaveSession(session.SessionKey, session)
|
||||
cleaned++
|
||||
} else if session.Status != "active" && age > expireThresholdMs {
|
||||
// Delete expired completed/interrupted sessions
|
||||
_ = s.DeleteSession(session.SessionKey)
|
||||
expired++
|
||||
}
|
||||
}
|
||||
return cleaned, expired, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user