@@ -28,7 +28,11 @@ import (
2828 "io"
2929 "net/http"
3030 "net/url"
31+ "strconv"
3132 "strings"
33+
34+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35+
3236 "time"
3337
3438 "github.com/kubernetes-sigs/headlamp/backend/pkg/cache"
@@ -38,9 +42,20 @@ import (
3842// CachedResponseData stores information such as StatusCode, Headers, and Body.
3943// It helps cache responses efficiently and serve them from the cache.
4044type CachedResponseData struct {
41- StatusCode int `json:"statusCode"`
42- Headers http.Header `json:"headers"`
43- Body string `json:"body"`
45+ StatusCode int `json:"statusCode"`
46+ Headers http.Header `json:"headers"`
47+ Body ResourceResponse `json:"body"`
48+ }
49+
50+ type Item struct {
51+ Metadata metav1.ObjectMeta `json:"metadata"`
52+ }
53+
54+ type ResourceResponse struct {
55+ Kind string `json:"kind"`
56+ Version string `json:"apiVersion"`
57+ Metadata metav1.ListMeta `json:"metadata"`
58+ Items []Item `json:"items"`
4459}
4560
4661// GetResponseBody decompresses a gzip-encoded response body and returns it as a string.
@@ -172,6 +187,32 @@ func FilterHeaderForCache(responseHeaders http.Header, encoding string) http.Hea
172187 return cacheHeader
173188}
174189
190+ func sliceTheResponse (page int , pageSize int , sizeOfResponse int ) (int , int ) {
191+ start := (page - 1 ) * pageSize
192+ if start >= sizeOfResponse {
193+ return sizeOfResponse , sizeOfResponse // slice empty if page out of range
194+ }
195+ end := start + pageSize
196+ if end > sizeOfResponse {
197+ end = sizeOfResponse
198+ }
199+ return start , end
200+ }
201+
202+ func ReturnResponseToClient (rcw * ResponseCapture , v any , w http.ResponseWriter ) error {
203+ var err error
204+ if rcw .Header ().Get ("Content-Encoding" ) == "gzip" {
205+ w .Header ().Set ("Content-Encoding" , "gzip" )
206+ gz := gzip .NewWriter (w )
207+ defer gz .Close ()
208+ err = json .NewEncoder (gz ).Encode (v )
209+ } else {
210+ err = json .NewEncoder (w ).Encode (v )
211+ }
212+
213+ return err
214+ }
215+
175216// LoadFromCache checks if a cached resource exists and the user has permission to view it.
176217// If found, it writes the cached data to the ResponseWriter and returns (true, nil).
177218// If not found or on error, it returns (false, error).
@@ -186,14 +227,30 @@ func LoadFromCache(k8scache cache.Cache[string], isAllowed bool,
186227 }
187228
188229 SetHeader (cachedData , w )
189- _ , writeErr := w .Write ([]byte (cachedData .Body ))
230+ w .Header ().Set ("Content-Type" , "application/json" )
231+
232+ // // 🔹 Always paginate, even for first request
233+ pageNo := r .URL .Query ().Get ("p" )
234+ limit := 10
190235
191- if writeErr != nil {
192- return false , writeErr
236+ page , _ := strconv .Atoi (pageNo )
237+
238+ if page > 1 {
239+ start , end := sliceTheResponse (page , limit , len (cachedData .Body .Items ))
240+ cachedData .Body .Items = cachedData .Body .Items [start :end ]
241+ }
242+
243+ bodyBytes , err := json .Marshal (cachedData .Body )
244+ if err != nil {
245+ return false , err
193246 }
194247
195- logger .Log (logger .LevelInfo , nil , nil , "serving from the cache with key " + key )
248+ if _ , err := w .Write (bodyBytes ); err != nil {
249+ // fmt.Println("since : ", time.Since(startNow))
250+ return false , err
251+ }
196252
253+ logger .Log (logger .LevelInfo , nil , nil , "serving from cache with key " + key )
197254 return true , nil
198255 }
199256
@@ -219,11 +276,18 @@ func StoreK8sResponseInCache(k8scache cache.Cache[string],
219276 }
220277
221278 headersToCache := FilterHeaderForCache (capturedHeaders , encoding )
279+
280+ var resourceBody ResourceResponse
281+ if err := json .Unmarshal ([]byte (dcmpBody ), & resourceBody ); err != nil {
282+ logger .Log (logger .LevelError , nil , err , "failed to unmarshal resource response body" )
283+ return err
284+ }
285+
222286 if ! strings .Contains (url .Path , "selfsubjectrulesreviews" ) {
223287 cachedData := CachedResponseData {
224288 StatusCode : rcw .StatusCode ,
225289 Headers : headersToCache ,
226- Body : dcmpBody ,
290+ Body : resourceBody ,
227291 }
228292
229293 jsonBytes , err := json .Marshal (cachedData )
@@ -239,6 +303,5 @@ func StoreK8sResponseInCache(k8scache cache.Cache[string],
239303 logger .Log (logger .LevelInfo , nil , nil , "k8s resource was stored with the key " + key )
240304 }
241305 }
242-
243306 return nil
244307}
0 commit comments