mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-17 20:00:52 +08:00
Break out config diffing, hashing, and OpenAI compatibility utilities into a dedicated diff package, update watcher to consume them, and add comprehensive tests for diff logic and watcher behavior.
125 lines
3.6 KiB
Go
125 lines
3.6 KiB
Go
package diff
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
)
|
|
|
|
// DiffOpenAICompatibility produces human-readable change descriptions.
|
|
func DiffOpenAICompatibility(oldList, newList []config.OpenAICompatibility) []string {
|
|
changes := make([]string, 0)
|
|
oldMap := make(map[string]config.OpenAICompatibility, len(oldList))
|
|
oldLabels := make(map[string]string, len(oldList))
|
|
for idx, entry := range oldList {
|
|
key, label := openAICompatKey(entry, idx)
|
|
oldMap[key] = entry
|
|
oldLabels[key] = label
|
|
}
|
|
newMap := make(map[string]config.OpenAICompatibility, len(newList))
|
|
newLabels := make(map[string]string, len(newList))
|
|
for idx, entry := range newList {
|
|
key, label := openAICompatKey(entry, idx)
|
|
newMap[key] = entry
|
|
newLabels[key] = label
|
|
}
|
|
keySet := make(map[string]struct{}, len(oldMap)+len(newMap))
|
|
for key := range oldMap {
|
|
keySet[key] = struct{}{}
|
|
}
|
|
for key := range newMap {
|
|
keySet[key] = struct{}{}
|
|
}
|
|
orderedKeys := make([]string, 0, len(keySet))
|
|
for key := range keySet {
|
|
orderedKeys = append(orderedKeys, key)
|
|
}
|
|
sort.Strings(orderedKeys)
|
|
for _, key := range orderedKeys {
|
|
oldEntry, oldOk := oldMap[key]
|
|
newEntry, newOk := newMap[key]
|
|
label := oldLabels[key]
|
|
if label == "" {
|
|
label = newLabels[key]
|
|
}
|
|
switch {
|
|
case !oldOk:
|
|
changes = append(changes, fmt.Sprintf("provider added: %s (api-keys=%d, models=%d)", label, countAPIKeys(newEntry), countOpenAIModels(newEntry.Models)))
|
|
case !newOk:
|
|
changes = append(changes, fmt.Sprintf("provider removed: %s (api-keys=%d, models=%d)", label, countAPIKeys(oldEntry), countOpenAIModels(oldEntry.Models)))
|
|
default:
|
|
if detail := describeOpenAICompatibilityUpdate(oldEntry, newEntry); detail != "" {
|
|
changes = append(changes, fmt.Sprintf("provider updated: %s %s", label, detail))
|
|
}
|
|
}
|
|
}
|
|
return changes
|
|
}
|
|
|
|
func describeOpenAICompatibilityUpdate(oldEntry, newEntry config.OpenAICompatibility) string {
|
|
oldKeyCount := countAPIKeys(oldEntry)
|
|
newKeyCount := countAPIKeys(newEntry)
|
|
oldModelCount := countOpenAIModels(oldEntry.Models)
|
|
newModelCount := countOpenAIModels(newEntry.Models)
|
|
details := make([]string, 0, 3)
|
|
if oldKeyCount != newKeyCount {
|
|
details = append(details, fmt.Sprintf("api-keys %d -> %d", oldKeyCount, newKeyCount))
|
|
}
|
|
if oldModelCount != newModelCount {
|
|
details = append(details, fmt.Sprintf("models %d -> %d", oldModelCount, newModelCount))
|
|
}
|
|
if !equalStringMap(oldEntry.Headers, newEntry.Headers) {
|
|
details = append(details, "headers updated")
|
|
}
|
|
if len(details) == 0 {
|
|
return ""
|
|
}
|
|
return "(" + strings.Join(details, ", ") + ")"
|
|
}
|
|
|
|
func countAPIKeys(entry config.OpenAICompatibility) int {
|
|
count := 0
|
|
for _, keyEntry := range entry.APIKeyEntries {
|
|
if strings.TrimSpace(keyEntry.APIKey) != "" {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func countOpenAIModels(models []config.OpenAICompatibilityModel) int {
|
|
count := 0
|
|
for _, model := range models {
|
|
name := strings.TrimSpace(model.Name)
|
|
alias := strings.TrimSpace(model.Alias)
|
|
if name == "" && alias == "" {
|
|
continue
|
|
}
|
|
count++
|
|
}
|
|
return count
|
|
}
|
|
|
|
func openAICompatKey(entry config.OpenAICompatibility, index int) (string, string) {
|
|
name := strings.TrimSpace(entry.Name)
|
|
if name != "" {
|
|
return "name:" + name, name
|
|
}
|
|
base := strings.TrimSpace(entry.BaseURL)
|
|
if base != "" {
|
|
return "base:" + base, base
|
|
}
|
|
for _, model := range entry.Models {
|
|
alias := strings.TrimSpace(model.Alias)
|
|
if alias == "" {
|
|
alias = strings.TrimSpace(model.Name)
|
|
}
|
|
if alias != "" {
|
|
return "alias:" + alias, alias
|
|
}
|
|
}
|
|
return fmt.Sprintf("index:%d", index), fmt.Sprintf("entry-%d", index+1)
|
|
}
|