mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-05 00:45:29 +08:00
feat: centralize DeepSeek SSE parsing, improve account identifier resolution, and simplify CORS configuration.
This commit is contained in:
@@ -154,20 +154,9 @@ func (h *Handler) testAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Concurrent testing with a semaphore to limit parallelism.
|
||||
const maxConcurrency = 5
|
||||
sem := make(chan struct{}, maxConcurrency)
|
||||
results := make([]map[string]any, len(accounts))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i, acc := range accounts {
|
||||
wg.Add(1)
|
||||
go func(idx int, account config.Account) {
|
||||
defer wg.Done()
|
||||
sem <- struct{}{} // acquire
|
||||
defer func() { <-sem }() // release
|
||||
results[idx] = h.testAccount(r.Context(), account, model, "")
|
||||
}(i, acc)
|
||||
}
|
||||
wg.Wait()
|
||||
results := runAccountTestsConcurrently(accounts, maxConcurrency, func(_ int, account config.Account) map[string]any {
|
||||
return h.testAccount(r.Context(), account, model, "")
|
||||
})
|
||||
|
||||
success := 0
|
||||
for _, res := range results {
|
||||
@@ -178,6 +167,26 @@ func (h *Handler) testAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"total": len(accounts), "success": success, "failed": len(accounts) - success, "results": results})
|
||||
}
|
||||
|
||||
func runAccountTestsConcurrently(accounts []config.Account, maxConcurrency int, testFn func(int, config.Account) map[string]any) []map[string]any {
|
||||
if maxConcurrency <= 0 {
|
||||
maxConcurrency = 1
|
||||
}
|
||||
sem := make(chan struct{}, maxConcurrency)
|
||||
results := make([]map[string]any, len(accounts))
|
||||
var wg sync.WaitGroup
|
||||
for i, acc := range accounts {
|
||||
wg.Add(1)
|
||||
go func(idx int, account config.Account) {
|
||||
defer wg.Done()
|
||||
sem <- struct{}{} // acquire
|
||||
defer func() { <-sem }() // release
|
||||
results[idx] = testFn(idx, account)
|
||||
}(i, acc)
|
||||
}
|
||||
wg.Wait()
|
||||
return results
|
||||
}
|
||||
|
||||
func (h *Handler) testAccount(ctx context.Context, acc config.Account, model, message string) map[string]any {
|
||||
start := time.Now()
|
||||
result := map[string]any{"account": acc.Identifier(), "success": false, "response_time": 0, "message": "", "model": model}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package admin
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"ds2api/internal/config"
|
||||
)
|
||||
|
||||
func TestToAccountMissingFieldsRemainEmpty(t *testing.T) {
|
||||
acc := toAccount(map[string]any{
|
||||
@@ -26,3 +32,62 @@ func TestFieldStringNilToEmpty(t *testing.T) {
|
||||
t.Fatalf("expected empty string for missing field, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunAccountTestsConcurrentlyKeepsInputOrder(t *testing.T) {
|
||||
accounts := []config.Account{
|
||||
{Email: "a@example.com"},
|
||||
{Email: "b@example.com"},
|
||||
{Email: "c@example.com"},
|
||||
}
|
||||
results := runAccountTestsConcurrently(accounts, 2, func(idx int, acc config.Account) map[string]any {
|
||||
return map[string]any{
|
||||
"idx": idx,
|
||||
"account": acc.Identifier(),
|
||||
}
|
||||
})
|
||||
if len(results) != len(accounts) {
|
||||
t.Fatalf("unexpected result length: got %d want %d", len(results), len(accounts))
|
||||
}
|
||||
for i := range accounts {
|
||||
gotIdx, _ := results[i]["idx"].(int)
|
||||
if gotIdx != i {
|
||||
t.Fatalf("result index mismatch at %d: got %d", i, gotIdx)
|
||||
}
|
||||
gotID, _ := results[i]["account"].(string)
|
||||
if gotID != accounts[i].Identifier() {
|
||||
t.Fatalf("result order mismatch at %d: got %q want %q", i, gotID, accounts[i].Identifier())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunAccountTestsConcurrentlyRespectsLimit(t *testing.T) {
|
||||
const limit = 3
|
||||
accounts := []config.Account{
|
||||
{Email: "1@example.com"},
|
||||
{Email: "2@example.com"},
|
||||
{Email: "3@example.com"},
|
||||
{Email: "4@example.com"},
|
||||
{Email: "5@example.com"},
|
||||
{Email: "6@example.com"},
|
||||
}
|
||||
var current int32
|
||||
var maxSeen int32
|
||||
_ = runAccountTestsConcurrently(accounts, limit, func(_ int, _ config.Account) map[string]any {
|
||||
c := atomic.AddInt32(¤t, 1)
|
||||
for {
|
||||
m := atomic.LoadInt32(&maxSeen)
|
||||
if c <= m || atomic.CompareAndSwapInt32(&maxSeen, m, c) {
|
||||
break
|
||||
}
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
atomic.AddInt32(¤t, -1)
|
||||
return map[string]any{"success": true}
|
||||
})
|
||||
if maxSeen > limit {
|
||||
t.Fatalf("concurrency exceeded limit: got %d > %d", maxSeen, limit)
|
||||
}
|
||||
if maxSeen < 2 {
|
||||
t.Fatalf("expected concurrent execution, max seen %d", maxSeen)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user