70 lines
1.8 KiB
Go
70 lines
1.8 KiB
Go
package handlers
|
|
|
|
// presence.go — Heartbeat upsert and status query (v0.23.1)
|
|
//
|
|
// Clients POST /api/v1/presence/heartbeat every 30s while active.
|
|
// GET /api/v1/presence?users=id1,id2 returns current status.
|
|
// Online = last_seen within 90s.
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"git.gobha.me/xcaliber/chat-switchboard/database"
|
|
)
|
|
|
|
const presenceOnlineThreshold = 90 * time.Second
|
|
|
|
// PresenceHeartbeat upserts the calling user's last_seen timestamp.
|
|
func PresenceHeartbeat(c *gin.Context) {
|
|
userID := getUserID(c)
|
|
_, err := database.DB.ExecContext(c.Request.Context(), database.Q(`
|
|
INSERT INTO user_presence (user_id, last_seen, status)
|
|
VALUES ($1, NOW(), 'online')
|
|
ON CONFLICT (user_id) DO UPDATE
|
|
SET last_seen = NOW(), status = 'online'
|
|
`), userID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "presence update failed"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"ok": true})
|
|
}
|
|
|
|
// PresenceQuery returns online/offline status for a list of user IDs.
|
|
// Query param: ?users=uuid1,uuid2,...
|
|
func PresenceQuery(c *gin.Context) {
|
|
raw := c.Query("users")
|
|
if raw == "" {
|
|
c.JSON(http.StatusOK, gin.H{"presence": map[string]string{}})
|
|
return
|
|
}
|
|
ids := strings.Split(raw, ",")
|
|
if len(ids) > 100 {
|
|
ids = ids[:100]
|
|
}
|
|
|
|
threshold := time.Now().Add(-presenceOnlineThreshold)
|
|
|
|
result := make(map[string]string, len(ids))
|
|
for _, id := range ids {
|
|
id = strings.TrimSpace(id)
|
|
if id == "" {
|
|
continue
|
|
}
|
|
var lastSeen time.Time
|
|
err := database.DB.QueryRowContext(c.Request.Context(), database.Q(`
|
|
SELECT last_seen FROM user_presence WHERE user_id = $1
|
|
`), id).Scan(&lastSeen)
|
|
if err != nil || lastSeen.Before(threshold) {
|
|
result[id] = "offline"
|
|
} else {
|
|
result[id] = "online"
|
|
}
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"presence": result})
|
|
}
|