118 lines
3.4 KiB
Go
118 lines
3.4 KiB
Go
package service
|
|
|
|
import "github.com/Wei-Shaw/sub2api/internal/config"
|
|
|
|
// OpenAIUpstreamTransport 表示 OpenAI 上游传输协议。
|
|
type OpenAIUpstreamTransport string
|
|
|
|
const (
|
|
OpenAIUpstreamTransportAny OpenAIUpstreamTransport = ""
|
|
OpenAIUpstreamTransportHTTPSSE OpenAIUpstreamTransport = "http_sse"
|
|
OpenAIUpstreamTransportResponsesWebsocket OpenAIUpstreamTransport = "responses_websockets"
|
|
OpenAIUpstreamTransportResponsesWebsocketV2 OpenAIUpstreamTransport = "responses_websockets_v2"
|
|
)
|
|
|
|
// OpenAIWSProtocolDecision 表示协议决策结果。
|
|
type OpenAIWSProtocolDecision struct {
|
|
Transport OpenAIUpstreamTransport
|
|
Reason string
|
|
}
|
|
|
|
// OpenAIWSProtocolResolver 定义 OpenAI 上游协议决策。
|
|
type OpenAIWSProtocolResolver interface {
|
|
Resolve(account *Account) OpenAIWSProtocolDecision
|
|
}
|
|
|
|
type defaultOpenAIWSProtocolResolver struct {
|
|
cfg *config.Config
|
|
}
|
|
|
|
// NewOpenAIWSProtocolResolver 创建默认协议决策器。
|
|
func NewOpenAIWSProtocolResolver(cfg *config.Config) OpenAIWSProtocolResolver {
|
|
return &defaultOpenAIWSProtocolResolver{cfg: cfg}
|
|
}
|
|
|
|
func (r *defaultOpenAIWSProtocolResolver) Resolve(account *Account) OpenAIWSProtocolDecision {
|
|
if account == nil {
|
|
return openAIWSHTTPDecision("account_missing")
|
|
}
|
|
if !account.IsOpenAI() {
|
|
return openAIWSHTTPDecision("platform_not_openai")
|
|
}
|
|
if account.IsOpenAIWSForceHTTPEnabled() {
|
|
return openAIWSHTTPDecision("account_force_http")
|
|
}
|
|
if r == nil || r.cfg == nil {
|
|
return openAIWSHTTPDecision("config_missing")
|
|
}
|
|
|
|
wsCfg := r.cfg.Gateway.OpenAIWS
|
|
if wsCfg.ForceHTTP {
|
|
return openAIWSHTTPDecision("global_force_http")
|
|
}
|
|
if !wsCfg.Enabled {
|
|
return openAIWSHTTPDecision("global_disabled")
|
|
}
|
|
if account.IsOpenAIOAuth() {
|
|
if !wsCfg.OAuthEnabled {
|
|
return openAIWSHTTPDecision("oauth_disabled")
|
|
}
|
|
} else if account.IsOpenAIApiKey() {
|
|
if !wsCfg.APIKeyEnabled {
|
|
return openAIWSHTTPDecision("apikey_disabled")
|
|
}
|
|
} else {
|
|
return openAIWSHTTPDecision("unknown_auth_type")
|
|
}
|
|
if wsCfg.ModeRouterV2Enabled {
|
|
mode := account.ResolveOpenAIResponsesWebSocketV2Mode(wsCfg.IngressModeDefault)
|
|
switch mode {
|
|
case OpenAIWSIngressModeOff:
|
|
return openAIWSHTTPDecision("account_mode_off")
|
|
case OpenAIWSIngressModeShared, OpenAIWSIngressModeDedicated:
|
|
// continue
|
|
default:
|
|
return openAIWSHTTPDecision("account_mode_off")
|
|
}
|
|
if account.Concurrency <= 0 {
|
|
return openAIWSHTTPDecision("account_concurrency_invalid")
|
|
}
|
|
if wsCfg.ResponsesWebsocketsV2 {
|
|
return OpenAIWSProtocolDecision{
|
|
Transport: OpenAIUpstreamTransportResponsesWebsocketV2,
|
|
Reason: "ws_v2_mode_" + mode,
|
|
}
|
|
}
|
|
if wsCfg.ResponsesWebsockets {
|
|
return OpenAIWSProtocolDecision{
|
|
Transport: OpenAIUpstreamTransportResponsesWebsocket,
|
|
Reason: "ws_v1_mode_" + mode,
|
|
}
|
|
}
|
|
return openAIWSHTTPDecision("feature_disabled")
|
|
}
|
|
if !account.IsOpenAIResponsesWebSocketV2Enabled() {
|
|
return openAIWSHTTPDecision("account_disabled")
|
|
}
|
|
if wsCfg.ResponsesWebsocketsV2 {
|
|
return OpenAIWSProtocolDecision{
|
|
Transport: OpenAIUpstreamTransportResponsesWebsocketV2,
|
|
Reason: "ws_v2_enabled",
|
|
}
|
|
}
|
|
if wsCfg.ResponsesWebsockets {
|
|
return OpenAIWSProtocolDecision{
|
|
Transport: OpenAIUpstreamTransportResponsesWebsocket,
|
|
Reason: "ws_v1_enabled",
|
|
}
|
|
}
|
|
return openAIWSHTTPDecision("feature_disabled")
|
|
}
|
|
|
|
func openAIWSHTTPDecision(reason string) OpenAIWSProtocolDecision {
|
|
return OpenAIWSProtocolDecision{
|
|
Transport: OpenAIUpstreamTransportHTTPSSE,
|
|
Reason: reason,
|
|
}
|
|
}
|