Refactor server: extract shared helpers, fix tool-call ordering and finish_reason mapping

- Extract callUpstream helper to deduplicate ~30 lines between chatCompletions and responses
- Move HTML templates to internal/server/templates/ via go:embed (server.go 1749→1192 lines)
- Consolidate 4 copies of firstNonEmpty into util.FirstNonEmpty
- Extract chatStreamChunk named type shared by aggregateStream and aggregateResponsesStream
- Fix tool-call ordering: iterate sorted map keys instead of sequential 0..N
- Map upstream finish_reason to Responses API status (length/content_filter → incomplete)
- Surface /v1/models errors as 401/502 instead of silently returning empty 200
- Add Secure cookie flag via isTLSRequest helper
- forEachSSEChunk: use sseDataPayload parser, drop redundant json.Valid, distinguish bufio.ErrTooLong
- Fix StreamIdleTimout typo → StreamIdleTimeout
- sso.go: single Read → io.ReadAll(io.LimitReader), explicit unknown error fallback
This commit is contained in:
2026-08-20 15:46:47 +08:00
parent 2517b4f730
commit 9aba511abe
10 changed files with 824 additions and 765 deletions
+13 -14
View File
@@ -5,9 +5,12 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"time"
"git.misaka.ren/M1saka/zhanlu_proxy/internal/util"
)
// ExchangeCode exchanges an SSO auth code for a user profile via the Zhanlu
@@ -39,9 +42,8 @@ func ExchangeCode(client *http.Client, endpoint string, code string, decryptKey
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
b := make([]byte, 1024)
n, _ := resp.Body.Read(b)
return Profile{}, fmt.Errorf("exchange returned %d: %s", resp.StatusCode, strings.TrimSpace(string(b[:n])))
b, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
return Profile{}, fmt.Errorf("exchange returned %d: %s", resp.StatusCode, strings.TrimSpace(string(b)))
}
var exchange ExchangeResponse
@@ -49,11 +51,17 @@ func ExchangeCode(client *http.Client, endpoint string, code string, decryptKey
return Profile{}, err
}
if exchange.ErrorCode != "" && exchange.ErrorCode != "Success" {
msg := firstNonEmpty(exchange.ErrorMsg, exchange.Message, exchange.ErrorCode)
msg := util.FirstNonEmpty(exchange.ErrorMsg, exchange.Message, exchange.ErrorCode)
if msg == "" {
msg = "unknown error"
}
return Profile{}, fmt.Errorf("exchange failed: %s", msg)
}
if exchange.State != "" && exchange.State != "OK" {
msg := firstNonEmpty(exchange.ErrorMsg, exchange.Message, exchange.State)
msg := util.FirstNonEmpty(exchange.ErrorMsg, exchange.Message, exchange.State)
if msg == "" {
msg = "unknown error"
}
return Profile{}, fmt.Errorf("exchange failed: %s", msg)
}
@@ -95,12 +103,3 @@ type ExchangeResponse struct {
Result map[string]any `json:"result"`
Data map[string]any `json:"data"`
}
func firstNonEmpty(values ...string) string {
for _, v := range values {
if strings.TrimSpace(v) != "" {
return v
}
}
return "unknown error"
}