xworkmate-bridge/internal/acp/config.go
2026-05-26 14:11:01 +08:00

162 lines
3.9 KiB
Go

package acp
import (
"os"
"strings"
"gopkg.in/yaml.v3"
"xworkmate-bridge/internal/shared"
)
type syncedProvider struct {
ProviderID string
Label string
Endpoint string
AuthorizationHeader string
Enabled bool
}
type BridgeConfig struct {
Upstream struct {
GatewayURL string `yaml:"gateway_url"`
CodexURL string `yaml:"codex_url"`
OpenCodeURL string `yaml:"opencode_url"`
GeminiURL string `yaml:"gemini_url"`
HermesURL string `yaml:"hermes_url"`
} `yaml:"upstream"`
Distributed DistributedConfig `yaml:"distributed"`
OpenClawGateway OpenClawGatewayConfig `yaml:"openclaw_gateway"`
}
type DistributedConfig struct {
TaskForwardEndpoint string `yaml:"task_forward_endpoint"`
TaskForwardToken string `yaml:"task_forward_token"`
}
type OpenClawGatewayConfig struct {
MaxActive *int `yaml:"max_active"`
MaxQueued *int `yaml:"max_queued"`
QueueTimeout string `yaml:"queue_timeout"`
}
func loadBridgeConfig() *BridgeConfig {
config := &BridgeConfig{}
configPath := shared.EnvOrDefault("BRIDGE_CONFIG_PATH", "/app/config.yaml")
if _, err := os.Stat(configPath); err == nil {
data, err := os.ReadFile(configPath)
if err == nil {
_ = yaml.Unmarshal(data, config)
}
}
return config
}
func resolveURL(yamlVal string, envKeys ...string) string {
val := strings.TrimSpace(yamlVal)
if val != "" {
return val
}
for _, key := range envKeys {
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
return v
}
}
return ""
}
func bridgeUpstreamAuthorizationHeader() string {
token := bridgeSharedAuthToken()
if token != "" && !strings.HasPrefix(strings.ToLower(token), "bearer ") {
return "Bearer " + token
}
return token
}
func bridgeSharedAuthToken() string {
return strings.TrimSpace(shared.EnvOrDefault("BRIDGE_AUTH_TOKEN", ""))
}
func resolveDistributedTaskForwardEndpoint(config *BridgeConfig) string {
yamlVal := ""
if config != nil {
yamlVal = config.Distributed.TaskForwardEndpoint
}
return resolveURL(yamlVal, "XWORKMATE_BRIDGE_TASK_FORWARD_ENDPOINT", "BRIDGE_TASK_FORWARD_ENDPOINT")
}
func resolveDistributedTaskForwardToken(config *BridgeConfig) string {
if token := strings.TrimSpace(os.Getenv("XWORKMATE_BRIDGE_TASK_FORWARD_TOKEN")); token != "" {
return token
}
if token := strings.TrimSpace(os.Getenv("BRIDGE_TASK_FORWARD_TOKEN")); token != "" {
return token
}
if config != nil {
if token := strings.TrimSpace(config.Distributed.TaskForwardToken); token != "" {
return token
}
}
return bridgeSharedAuthToken()
}
func newProductionProviderCatalog() (*BridgeConfig, map[string]syncedProvider, []string) {
return newProductionProviderCatalogFromConfig(loadBridgeConfig())
}
func newProductionProviderCatalogFromConfig(config *BridgeConfig) (*BridgeConfig, map[string]syncedProvider, []string) {
if config == nil {
config = &BridgeConfig{}
}
authorizationHeader := bridgeUpstreamAuthorizationHeader()
providers := []struct {
id string
label string
yaml string
envKeys []string
}{
{
id: "codex",
label: "Codex",
yaml: config.Upstream.CodexURL,
envKeys: []string{"CODEX_RPC_URL"},
},
{
id: "opencode",
label: "OpenCode",
yaml: config.Upstream.OpenCodeURL,
envKeys: []string{"OPENCODE_RPC_URL"},
},
{
id: "gemini",
label: "Gemini",
yaml: config.Upstream.GeminiURL,
envKeys: []string{"GEMINI_RPC_URL"},
},
{
id: "hermes",
label: "Hermes",
yaml: config.Upstream.HermesURL,
envKeys: []string{"HERMES_RPC_URL"},
},
}
catalog := make(map[string]syncedProvider)
var order []string
for _, p := range providers {
endpoint := resolveURL(p.yaml, p.envKeys...)
catalog[p.id] = syncedProvider{
ProviderID: p.id,
Label: p.label,
Endpoint: endpoint,
AuthorizationHeader: authorizationHeader,
Enabled: endpoint != "",
}
order = append(order, p.id)
}
return config, catalog, order
}