mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
91 lines
3.4 KiB
Go
91 lines
3.4 KiB
Go
//go:build !slim
|
|
|
|
package cli
|
|
|
|
import (
|
|
"context"
|
|
"net/url"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/aibridge"
|
|
"github.com/coder/coder/v2/aibridge/intercept/apidump"
|
|
"github.com/coder/coder/v2/enterprise/aibridgeproxyd"
|
|
"github.com/coder/coder/v2/enterprise/coderd"
|
|
)
|
|
|
|
func newAIBridgeProxyDaemon(coderAPI *coderd.API, providers []aibridge.Provider) (*aibridgeproxyd.Server, error) {
|
|
ctx := context.Background()
|
|
coderAPI.Logger.Debug(ctx, "starting in-memory aibridgeproxy daemon")
|
|
|
|
logger := coderAPI.Logger.Named("aibridgeproxyd")
|
|
|
|
domains, providerFromHost := domainsFromProviders(providers)
|
|
|
|
reg := prometheus.WrapRegistererWithPrefix("coder_aibridgeproxyd_", coderAPI.PrometheusRegistry)
|
|
metrics := aibridgeproxyd.NewMetrics(reg)
|
|
|
|
var newDumper func(provider, requestID string) aibridgeproxyd.RoundTripDumper
|
|
if dumpDir := coderAPI.DeploymentValues.AI.BridgeProxyConfig.APIDumpDir.String(); dumpDir != "" {
|
|
newDumper = func(provider, requestID string) aibridgeproxyd.RoundTripDumper {
|
|
return apidump.NewDumper(filepath.Join(dumpDir, provider, requestID), logger)
|
|
}
|
|
}
|
|
|
|
srv, err := aibridgeproxyd.New(ctx, logger, aibridgeproxyd.Options{
|
|
ListenAddr: coderAPI.DeploymentValues.AI.BridgeProxyConfig.ListenAddr.String(),
|
|
TLSCertFile: coderAPI.DeploymentValues.AI.BridgeProxyConfig.TLSCertFile.String(),
|
|
TLSKeyFile: coderAPI.DeploymentValues.AI.BridgeProxyConfig.TLSKeyFile.String(),
|
|
CoderAccessURL: coderAPI.AccessURL.String(),
|
|
MITMCertFile: coderAPI.DeploymentValues.AI.BridgeProxyConfig.MITMCertFile.String(),
|
|
MITMKeyFile: coderAPI.DeploymentValues.AI.BridgeProxyConfig.MITMKeyFile.String(),
|
|
DomainAllowlist: domains,
|
|
AIBridgeProviderFromHost: providerFromHost,
|
|
UpstreamProxy: coderAPI.DeploymentValues.AI.BridgeProxyConfig.UpstreamProxy.String(),
|
|
UpstreamProxyCA: coderAPI.DeploymentValues.AI.BridgeProxyConfig.UpstreamProxyCA.String(),
|
|
AllowedPrivateCIDRs: coderAPI.DeploymentValues.AI.BridgeProxyConfig.AllowedPrivateCIDRs.Value(),
|
|
NewDumper: newDumper,
|
|
Metrics: metrics,
|
|
})
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to start in-memory aibridgeproxy daemon: %w", err)
|
|
}
|
|
|
|
return srv, nil
|
|
}
|
|
|
|
// domainsFromProviders extracts distinct hostnames from providers' base
|
|
// URLs and builds a host-to-provider-name mapping function. The returned
|
|
// domain list is suitable for use as DomainAllowlist and the mapping
|
|
// function is suitable for use as AIBridgeProviderFromHost.
|
|
func domainsFromProviders(providers []aibridge.Provider) ([]string, func(string) string) {
|
|
hostToProvider := make(map[string]string, len(providers))
|
|
var domains []string
|
|
for _, p := range providers {
|
|
raw := p.BaseURL()
|
|
if raw == "" {
|
|
continue
|
|
}
|
|
u, err := url.Parse(raw)
|
|
if err != nil || u.Hostname() == "" {
|
|
continue
|
|
}
|
|
host := strings.ToLower(u.Hostname())
|
|
if _, exists := hostToProvider[host]; exists {
|
|
// First provider wins; duplicates are expected when
|
|
// multiple providers share a base URL host (e.g. two
|
|
// OpenAI providers using the same proxy).
|
|
continue
|
|
}
|
|
hostToProvider[host] = p.Name()
|
|
domains = append(domains, host)
|
|
}
|
|
|
|
return domains, func(host string) string {
|
|
return hostToProvider[strings.ToLower(host)]
|
|
}
|
|
}
|