66 lines
1.9 KiB
Go
66 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
sessionSnapshotItems = 24
|
|
sessionSnapshotBytes = 8 << 20
|
|
)
|
|
|
|
type sessionSnapshot struct {
|
|
SessionID string `json:"session_id"`
|
|
Messages []json.RawMessage `json:"messages"`
|
|
TotalMessages int `json:"total_messages"`
|
|
}
|
|
|
|
// boundSessionSnapshot caps only the continuity fallback response. Native
|
|
// WebUI requests remain untouched, including when an older backend ignores
|
|
// its optional `limit` query parameter.
|
|
func boundSessionSnapshot(response *http.Response) error {
|
|
request := response.Request
|
|
if request == nil || response.StatusCode != http.StatusOK ||
|
|
request.URL.Query().Get("hermes_fallback") != "1" ||
|
|
!strings.HasPrefix(request.URL.Path, "/api/sessions/") ||
|
|
!strings.HasSuffix(request.URL.Path, "/messages") {
|
|
return nil
|
|
}
|
|
body, err := io.ReadAll(io.LimitReader(response.Body, sessionSnapshotBytes+1))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = response.Body.Close()
|
|
if len(body) > sessionSnapshotBytes {
|
|
return errors.New("session snapshot exceeds safe response limit")
|
|
}
|
|
var payload sessionSnapshot
|
|
if err := json.Unmarshal(body, &payload); err != nil || payload.Messages == nil {
|
|
return errors.New("session snapshot is malformed")
|
|
}
|
|
total := len(payload.Messages)
|
|
if payload.TotalMessages > total {
|
|
total = payload.TotalMessages
|
|
}
|
|
if len(payload.Messages) > sessionSnapshotItems {
|
|
payload.Messages = payload.Messages[len(payload.Messages)-sessionSnapshotItems:]
|
|
}
|
|
payload.TotalMessages = total
|
|
body, err = json.Marshal(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
response.Body = io.NopCloser(strings.NewReader(string(body)))
|
|
response.ContentLength = int64(len(body))
|
|
response.Header.Set("Content-Length", strconv.Itoa(len(body)))
|
|
response.Header.Set("Content-Type", "application/json; charset=utf-8")
|
|
response.Header.Set("Cache-Control", "no-store")
|
|
response.Header.Del("ETag")
|
|
return nil
|
|
}
|