openai_ws_protocol_resolver.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package service
  2. import "github.com/Wei-Shaw/sub2api/internal/config"
  3. // OpenAIUpstreamTransport 表示 OpenAI 上游传输协议。
  4. type OpenAIUpstreamTransport string
  5. const (
  6. OpenAIUpstreamTransportAny OpenAIUpstreamTransport = ""
  7. OpenAIUpstreamTransportHTTPSSE OpenAIUpstreamTransport = "http_sse"
  8. OpenAIUpstreamTransportResponsesWebsocket OpenAIUpstreamTransport = "responses_websockets"
  9. OpenAIUpstreamTransportResponsesWebsocketV2 OpenAIUpstreamTransport = "responses_websockets_v2"
  10. // OpenAIUpstreamTransportResponsesWebsocketV2Ingress 用于 WS ingress 入口选账号:
  11. // mode_router_v2 开启时允许 ctx_pool/passthrough/http_bridge,拒绝 off。
  12. OpenAIUpstreamTransportResponsesWebsocketV2Ingress OpenAIUpstreamTransport = "responses_websockets_v2_ingress"
  13. )
  14. // OpenAIWSProtocolDecision 表示协议决策结果。
  15. type OpenAIWSProtocolDecision struct {
  16. Transport OpenAIUpstreamTransport
  17. Reason string
  18. }
  19. // OpenAIWSProtocolResolver 定义 OpenAI 上游协议决策。
  20. type OpenAIWSProtocolResolver interface {
  21. Resolve(account *Account) OpenAIWSProtocolDecision
  22. }
  23. type defaultOpenAIWSProtocolResolver struct {
  24. cfg *config.Config
  25. }
  26. // NewOpenAIWSProtocolResolver 创建默认协议决策器。
  27. func NewOpenAIWSProtocolResolver(cfg *config.Config) OpenAIWSProtocolResolver {
  28. return &defaultOpenAIWSProtocolResolver{cfg: cfg}
  29. }
  30. func (r *defaultOpenAIWSProtocolResolver) Resolve(account *Account) OpenAIWSProtocolDecision {
  31. if account == nil {
  32. return openAIWSHTTPDecision("account_missing")
  33. }
  34. if !account.IsOpenAI() {
  35. return openAIWSHTTPDecision("platform_not_openai")
  36. }
  37. if account.IsOpenAIWSForceHTTPEnabled() {
  38. return openAIWSHTTPDecision("account_force_http")
  39. }
  40. if r == nil || r.cfg == nil {
  41. return openAIWSHTTPDecision("config_missing")
  42. }
  43. wsCfg := r.cfg.Gateway.OpenAIWS
  44. if wsCfg.ForceHTTP {
  45. return openAIWSHTTPDecision("global_force_http")
  46. }
  47. if !wsCfg.Enabled {
  48. return openAIWSHTTPDecision("global_disabled")
  49. }
  50. if account.IsOpenAIOAuthLike() {
  51. if !wsCfg.OAuthEnabled {
  52. return openAIWSHTTPDecision("oauth_disabled")
  53. }
  54. } else if account.IsOpenAIApiKey() {
  55. if !wsCfg.APIKeyEnabled {
  56. return openAIWSHTTPDecision("apikey_disabled")
  57. }
  58. } else {
  59. return openAIWSHTTPDecision("unknown_auth_type")
  60. }
  61. if wsCfg.ModeRouterV2Enabled {
  62. mode := account.ResolveOpenAIResponsesWebSocketV2Mode(wsCfg.IngressModeDefault)
  63. switch mode {
  64. case OpenAIWSIngressModeOff:
  65. return openAIWSHTTPDecision("account_mode_off")
  66. case OpenAIWSIngressModeCtxPool, OpenAIWSIngressModePassthrough:
  67. // continue
  68. case OpenAIWSIngressModeHTTPBridge:
  69. return openAIWSHTTPDecision("ws_v2_mode_http_bridge")
  70. case OpenAIWSIngressModeShared, OpenAIWSIngressModeDedicated:
  71. // 历史值兼容:按 ctx_pool 处理。
  72. mode = OpenAIWSIngressModeCtxPool
  73. default:
  74. return openAIWSHTTPDecision("account_mode_off")
  75. }
  76. if account.Concurrency <= 0 {
  77. return openAIWSHTTPDecision("account_concurrency_invalid")
  78. }
  79. if wsCfg.ResponsesWebsocketsV2 {
  80. return OpenAIWSProtocolDecision{
  81. Transport: OpenAIUpstreamTransportResponsesWebsocketV2,
  82. Reason: "ws_v2_mode_" + mode,
  83. }
  84. }
  85. if wsCfg.ResponsesWebsockets {
  86. return OpenAIWSProtocolDecision{
  87. Transport: OpenAIUpstreamTransportResponsesWebsocket,
  88. Reason: "ws_v1_mode_" + mode,
  89. }
  90. }
  91. return openAIWSHTTPDecision("feature_disabled")
  92. }
  93. if !account.IsOpenAIResponsesWebSocketV2Enabled() {
  94. return openAIWSHTTPDecision("account_disabled")
  95. }
  96. if wsCfg.ResponsesWebsocketsV2 {
  97. return OpenAIWSProtocolDecision{
  98. Transport: OpenAIUpstreamTransportResponsesWebsocketV2,
  99. Reason: "ws_v2_enabled",
  100. }
  101. }
  102. if wsCfg.ResponsesWebsockets {
  103. return OpenAIWSProtocolDecision{
  104. Transport: OpenAIUpstreamTransportResponsesWebsocket,
  105. Reason: "ws_v1_enabled",
  106. }
  107. }
  108. return openAIWSHTTPDecision("feature_disabled")
  109. }
  110. func openAIWSHTTPDecision(reason string) OpenAIWSProtocolDecision {
  111. return OpenAIWSProtocolDecision{
  112. Transport: OpenAIUpstreamTransportHTTPSSE,
  113. Reason: reason,
  114. }
  115. }