provider: a held All gives each caller its own providers, Keys and Headers included — 463462cd held All for a request and gave callers a slices.Clone of it, which shares each provider's slices and maps: SetKeyOn, RemoveKey and RenameKey change p.Keys[i] of what Find returns, so a key switched while a GUI GET or Codex's /models held the list changed every other caller's copy before it was saved. All now clones each provider (Was, Keys, Fallback, Models, Headers, AccountProxies, AccountModels, AccountCaps, Contexts, MaxConcurrency, ZhipuTeam; Account, the sign-in's runtime, stays shared). TestHeldAllUnshared.
This commit is contained in:
1 parent
cb7f442785
commit
cb2e3bcca4
2 files changed
+55
-1
No files matched your search
@@ -0,0 +1,20 @@
|
||||
package provider
|
||||
|
||||
import "testing"
|
||||
|
||||
// A held list is shared by the request's callers: one that changes a key
|
||||
// of its copy (SetKeyOn through Find) leaves the others' as they were.
|
||||
func TestHeldAllUnshared(t *testing.T) {
|
||||
n := 3
|
||||
p := Provider{ID: "a", Keys: []KeyAccount{{Name: "k"}}, Headers: map[string]string{"h": "1"},
|
||||
Models: []string{"m"}, AccountModels: map[string][]string{"x": {"m"}}, MaxConcurrency: &n}
|
||||
q := p.clone()
|
||||
q.Keys[0].Name = "changed"
|
||||
q.Headers["h"] = "2"
|
||||
q.Models[0] = "n"
|
||||
q.AccountModels["x"][0] = "n"
|
||||
*q.MaxConcurrency = 9
|
||||
if p.Keys[0].Name != "k" || p.Headers["h"] != "1" || p.Models[0] != "m" || p.AccountModels["x"][0] != "m" || n != 3 {
|
||||
t.Fatalf("clone shares with the original: %+v", p)
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -317,7 +318,40 @@ func store(f file) error {
|
||||
// item or a CLI's among them, and Codex's /models asked for it seven times
|
||||
// over, past the 5 s Codex waits for the list (#746).
|
||||
func All() []Provider {
|
||||
return slices.Clone(heldOf("all", allProviders)) // callers change theirs
|
||||
held := heldOf("all", allProviders)
|
||||
out := make([]Provider, len(held))
|
||||
for i, p := range held {
|
||||
out[i] = p.clone() // callers change theirs, Keys[i] and Headers included
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// clone is p with its settings unshared: slices, maps and pointers copied.
|
||||
func (p Provider) clone() Provider {
|
||||
p.Was = slices.Clone(p.Was)
|
||||
p.Keys = slices.Clone(p.Keys)
|
||||
p.Fallback = slices.Clone(p.Fallback)
|
||||
p.Models = slices.Clone(p.Models)
|
||||
p.Headers = maps.Clone(p.Headers)
|
||||
p.AccountProxies = maps.Clone(p.AccountProxies)
|
||||
p.AccountCaps = maps.Clone(p.AccountCaps)
|
||||
p.Contexts = maps.Clone(p.Contexts)
|
||||
if p.AccountModels != nil {
|
||||
m := make(map[string][]string, len(p.AccountModels))
|
||||
for k, v := range p.AccountModels {
|
||||
m[k] = slices.Clone(v)
|
||||
}
|
||||
p.AccountModels = m
|
||||
}
|
||||
if p.MaxConcurrency != nil {
|
||||
v := *p.MaxConcurrency
|
||||
p.MaxConcurrency = &v
|
||||
}
|
||||
if p.ZhipuTeam != nil {
|
||||
v := *p.ZhipuTeam
|
||||
p.ZhipuTeam = &v
|
||||
}
|
||||
return p // Account, the sign-in's runtime, stays shared
|
||||
}
|
||||
|
||||
// AllBuilt counts the times All built the list anew, for tests.
|
||||
|
||||
Reference in new issue
Block a user