feat: sync deployed v1.0.0-rc.38-custom.42
Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
1 parent
aa6c3f50f4
commit
ceddfd3d6b
828 files changed
+122253
-13702
No files matched your search
@@ -372,11 +372,16 @@ func DoFormRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBod
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DoWssRequest dials the adaptor's upstream over WebSocket for the realtime
|
||||
// and Responses WebSocket relays. It honors the channel proxy, is bound to the
|
||||
// request context, and reports a rejected handshake as a *types.NewAPIError
|
||||
// carrying the upstream status code (types.NewError preserves it).
|
||||
func DoWssRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBody io.Reader) (*websocket.Conn, error) {
|
||||
fullRequestURL, err := a.GetRequestURL(info)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get request url failed: %w", err)
|
||||
}
|
||||
fullRequestURL = toWebSocketURL(fullRequestURL)
|
||||
targetHeader := http.Header{}
|
||||
err = a.SetupRequestHeader(c, &targetHeader, info)
|
||||
if err != nil {
|
||||
@@ -392,16 +397,41 @@ func DoWssRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBody
|
||||
targetHeader.Set(key, value)
|
||||
}
|
||||
targetHeader.Set("Content-Type", c.Request.Header.Get("Content-Type"))
|
||||
targetConn, _, err := websocket.DefaultDialer.Dial(fullRequestURL, targetHeader)
|
||||
dialer := *websocket.DefaultDialer
|
||||
if info.ChannelSetting.Proxy != "" {
|
||||
proxyURL, _, proxyErr := common2.ParseProxyURLRuntime(info.ChannelSetting.Proxy)
|
||||
if proxyErr != nil {
|
||||
return nil, proxyErr
|
||||
}
|
||||
dialer.Proxy = http.ProxyURL(proxyURL)
|
||||
}
|
||||
targetConn, resp, err := dialer.DialContext(c.Request.Context(), fullRequestURL, targetHeader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dial failed to %s: %w", common.SanitizeURLForLog(fullRequestURL), err)
|
||||
statusCode := http.StatusInternalServerError
|
||||
if resp != nil {
|
||||
statusCode = resp.StatusCode
|
||||
if resp.Body != nil {
|
||||
_ = resp.Body.Close()
|
||||
}
|
||||
}
|
||||
return nil, types.NewErrorWithStatusCode(fmt.Errorf("dial failed to %s: %w", common.SanitizeURLForLog(fullRequestURL), err), types.ErrorCodeDoRequestFailed, statusCode)
|
||||
}
|
||||
// send request body
|
||||
//all, err := io.ReadAll(requestBody)
|
||||
//err = service.WssString(c, targetConn, string(all))
|
||||
return targetConn, nil
|
||||
}
|
||||
|
||||
// toWebSocketURL maps an http(s) endpoint to ws(s). Realtime adaptors already
|
||||
// return ws(s) URLs, which pass through unchanged.
|
||||
func toWebSocketURL(raw string) string {
|
||||
switch {
|
||||
case strings.HasPrefix(raw, "https://"):
|
||||
return "wss://" + strings.TrimPrefix(raw, "https://")
|
||||
case strings.HasPrefix(raw, "http://"):
|
||||
return "ws://" + strings.TrimPrefix(raw, "http://")
|
||||
default:
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
func startPingKeepAlive(c *gin.Context, pingInterval time.Duration) (context.CancelFunc, <-chan struct{}) {
|
||||
pingerCtx, stopPinger := context.WithCancel(context.Background())
|
||||
done := make(chan struct{})
|
||||
@@ -488,6 +518,13 @@ func keepUpstreamRedirectResponse(_ *http.Request, _ []*http.Request) error {
|
||||
}
|
||||
|
||||
func doRequest(c *gin.Context, req *http.Request, info *common.RelayInfo) (*http.Response, error) {
|
||||
guardEnabled := info.ResponseGuard != nil && info.AstraAutoSwitch
|
||||
if guardEnabled && info.UpstreamRequests >= common.ResponseGuardMaxAttempts {
|
||||
return nil, types.NewErrorWithStatusCode(errors.New("response model attempt budget exhausted"), common.ResponseGuardErrorCode, http.StatusBadGateway, types.ErrOptionWithSkipRetry())
|
||||
}
|
||||
if guardEnabled && c.Request.Context().Err() != nil {
|
||||
return nil, types.NewErrorWithStatusCode(c.Request.Context().Err(), common.ResponseGuardErrorCode, http.StatusBadGateway, types.ErrOptionWithSkipRetry())
|
||||
}
|
||||
client, err := service.GetHttpClientWithProxySettings(info.ChannelSetting.Proxy, info.ChannelSetting)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("new proxy http client failed: %w", err)
|
||||
@@ -511,7 +548,7 @@ func doRequest(c *gin.Context, req *http.Request, info *common.RelayInfo) (*http
|
||||
|
||||
var stopPinger context.CancelFunc
|
||||
var pingerDone <-chan struct{}
|
||||
if info.IsStream {
|
||||
if info.IsStream && !guardEnabled {
|
||||
helper.SetEventStreamHeaders(c)
|
||||
// 处理流式请求的 ping 保活
|
||||
generalSettings := operation_setting.GetGeneralSetting()
|
||||
@@ -529,14 +566,55 @@ func doRequest(c *gin.Context, req *http.Request, info *common.RelayInfo) (*http
|
||||
}
|
||||
}
|
||||
|
||||
info.UpstreamRequests++
|
||||
var guard *common.ResponseGuardAttempt
|
||||
var guardUsage *service.GuardUsageCollector
|
||||
if guardEnabled {
|
||||
var upstream context.Context
|
||||
upstream, guard = info.ResponseGuard.Begin(c.Request.Context(), info.UpstreamRequests, info.ChannelId)
|
||||
if info.DurableAttemptID != 0 {
|
||||
guardUsage = service.NewGuardUsageCollector(c, info)
|
||||
guard.OnEvent = guardUsage.Observe
|
||||
guard.OnClose = func() { guardUsage.CheckpointFinal(guard.Reason) }
|
||||
}
|
||||
req = req.WithContext(upstream)
|
||||
}
|
||||
resp, err := relayClient.Do(req)
|
||||
if err != nil {
|
||||
if guard != nil {
|
||||
guard.Close()
|
||||
guard.Finish(false)
|
||||
if c.Request.Context().Err() != nil {
|
||||
guard.Reject("client_cancelled")
|
||||
return nil, guard.APIError()
|
||||
}
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
guard.Reject("confirmation_timeout")
|
||||
return nil, guard.APIError()
|
||||
}
|
||||
guard.Reason = "transport_error"
|
||||
}
|
||||
logger.LogError(c, "do request failed: "+err.Error())
|
||||
return nil, types.NewError(err, types.ErrorCodeDoRequestFailed, types.ErrOptionWithHideErrMsg("upstream error: do request failed"))
|
||||
}
|
||||
if resp == nil {
|
||||
if guard != nil {
|
||||
guard.Close()
|
||||
}
|
||||
return nil, errors.New("resp is nil")
|
||||
}
|
||||
if guard != nil {
|
||||
if err := guard.Confirm(resp, c.Request.Context()); err != nil {
|
||||
if guardUsage != nil && guardUsage.FinishRejected(info, guard, resp) {
|
||||
guard.Finish(false)
|
||||
return nil, guard.APIError()
|
||||
}
|
||||
guard.Close()
|
||||
_ = resp.Body.Close()
|
||||
guard.Finish(false)
|
||||
return nil, guard.APIError()
|
||||
}
|
||||
}
|
||||
if common2.DebugEnabled {
|
||||
policy := service.NormalizeHTTPTransportPolicy(info.ChannelSetting)
|
||||
logger.LogDebug(c, fmt.Sprintf(
|
||||
|
||||
Reference in new issue
Block a user