mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-07 18:05:30 +08:00
feat: add ETag cache optimization, code-split WebUI, and refactor XML tool scanner
- Chat history: early 304 via Revision()/DetailRevision() to avoid full snapshot reads - WebUI: lazy-load tab containers with Suspense fallback - Toolstream: split tool_sieve_xml.go into tags.go and scan.go - CI: trigger on main branch, guard cross-build to dev/main pushes only - Docs: add DEVELOPER.md developer quick reference Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,24 @@ func (h *Handler) getChatHistory(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusServiceUnavailable, map[string]any{"detail": "chat history store is not configured"})
|
||||
return
|
||||
}
|
||||
ifNoneMatch := strings.TrimSpace(r.Header.Get("If-None-Match"))
|
||||
if ifNoneMatch != "" {
|
||||
revision, err := store.Revision()
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusServiceUnavailable, map[string]any{
|
||||
"detail": err.Error(),
|
||||
"path": store.Path(),
|
||||
})
|
||||
return
|
||||
}
|
||||
etag := chathistory.ListETag(revision)
|
||||
w.Header().Set("ETag", etag)
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
if ifNoneMatch == etag {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
snapshot, err := store.Snapshot()
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusServiceUnavailable, map[string]any{
|
||||
@@ -27,7 +45,7 @@ func (h *Handler) getChatHistory(w http.ResponseWriter, r *http.Request) {
|
||||
etag := chathistory.ListETag(snapshot.Revision)
|
||||
w.Header().Set("ETag", etag)
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
if strings.TrimSpace(r.Header.Get("If-None-Match")) == etag {
|
||||
if ifNoneMatch == etag {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
@@ -51,6 +69,25 @@ func (h *Handler) getChatHistoryItem(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": "history id is required"})
|
||||
return
|
||||
}
|
||||
ifNoneMatch := strings.TrimSpace(r.Header.Get("If-None-Match"))
|
||||
if ifNoneMatch != "" {
|
||||
revision, err := store.DetailRevision(id)
|
||||
if err != nil {
|
||||
status := http.StatusInternalServerError
|
||||
if strings.Contains(strings.ToLower(err.Error()), "not found") {
|
||||
status = http.StatusNotFound
|
||||
}
|
||||
writeJSON(w, status, map[string]any{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
etag := chathistory.DetailETag(id, revision)
|
||||
w.Header().Set("ETag", etag)
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
if ifNoneMatch == etag {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
item, err := store.Get(id)
|
||||
if err != nil {
|
||||
status := http.StatusInternalServerError
|
||||
@@ -63,7 +100,7 @@ func (h *Handler) getChatHistoryItem(w http.ResponseWriter, r *http.Request) {
|
||||
etag := chathistory.DetailETag(item.ID, item.Revision)
|
||||
w.Header().Set("ETag", etag)
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
if strings.TrimSpace(r.Header.Get("If-None-Match")) == etag {
|
||||
if ifNoneMatch == etag {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -95,6 +95,15 @@ func TestGetChatHistoryAndUpdateSettings(t *testing.T) {
|
||||
t.Fatalf("expected detail etag header")
|
||||
}
|
||||
|
||||
notModifiedItemReq := httptest.NewRequest(http.MethodGet, "/chat-history/"+entry.ID, nil)
|
||||
notModifiedItemReq.Header.Set("Authorization", "Bearer admin")
|
||||
notModifiedItemReq.Header.Set("If-None-Match", itemRec.Header().Get("ETag"))
|
||||
notModifiedItemRec := httptest.NewRecorder()
|
||||
r.ServeHTTP(notModifiedItemRec, notModifiedItemReq)
|
||||
if notModifiedItemRec.Code != http.StatusNotModified {
|
||||
t.Fatalf("expected detail 304, got %d body=%s", notModifiedItemRec.Code, notModifiedItemRec.Body.String())
|
||||
}
|
||||
|
||||
updateReq := httptest.NewRequest(http.MethodPut, "/chat-history/settings", bytes.NewReader([]byte(`{"limit":10}`)))
|
||||
updateReq.Header.Set("Authorization", "Bearer admin")
|
||||
updateRec := httptest.NewRecorder()
|
||||
|
||||
Reference in New Issue
Block a user