feat(providers): route only the generate submit through the proxy
Extends the adobe split to leonardo, krea, imagine, runway (image+video) and chatgpt: reference-image upload, polling and result download egress on the local IP; only the generate/task-create submit uses proxy.url. chatgpt keeps its anti-bot-guarded submit+upload phase on the proxy and moves only the existing second (poll/resolve/download) session to local. custom is already direct. Build+vet pass; adobe verified live, the other providers are code-complete but not yet live-tested (no dev accounts).
This commit is contained in:
@@ -248,10 +248,15 @@ func (c *Client) FetchCreditsBalance(ctx context.Context, cookie string) (map[st
|
||||
}, nil
|
||||
}
|
||||
|
||||
// graphql POSTs a GraphQL body to the Leonardo API with the bearer + schema header,
|
||||
// returning the raw response body and status.
|
||||
// graphql runs a GraphQL call through the proxy. graphqlP lets callers pick the
|
||||
// egress: only the generate submit uses the proxy; reference-image upload and
|
||||
// polling run direct (local IP).
|
||||
func (c *Client) graphql(ctx context.Context, accessToken string, payload []byte) ([]byte, int, error) {
|
||||
client, err := c.newTLSClient()
|
||||
return c.graphqlP(ctx, accessToken, payload, true)
|
||||
}
|
||||
|
||||
func (c *Client) graphqlP(ctx context.Context, accessToken string, payload []byte, useProxy bool) ([]byte, int, error) {
|
||||
client, err := c.newTLSClientP(useProxy)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@@ -300,7 +305,13 @@ func unknownBalance(reason string) map[string]any {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) newTLSClient() (tlsclient.HttpClient, error) {
|
||||
func (c *Client) newTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(true) }
|
||||
|
||||
// newDirectTLSClient egresses on the local IP (never the proxy). Used for
|
||||
// reference-image upload, polling and result download.
|
||||
func (c *Client) newDirectTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(false) }
|
||||
|
||||
func (c *Client) newTLSClientP(useProxy bool) (tlsclient.HttpClient, error) {
|
||||
// Match the fingerprint proven to work against Leonardo's Cloudflare edge:
|
||||
// Chrome_120, fixed extension order. A randomized JA3 (Chrome_133 +
|
||||
// WithRandomTLSExtensionOrder) gets flagged and 429'd at get-session.
|
||||
@@ -308,7 +319,7 @@ func (c *Client) newTLSClient() (tlsclient.HttpClient, error) {
|
||||
tlsclient.WithTimeoutSeconds(60),
|
||||
tlsclient.WithClientProfile(profiles.Chrome_120),
|
||||
}
|
||||
if c.proxy != "" {
|
||||
if useProxy && c.proxy != "" {
|
||||
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
||||
}
|
||||
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
||||
@@ -319,7 +330,7 @@ func (c *Client) downloadImage(ctx context.Context, imageURL string) ([]byte, er
|
||||
if _, err := url.Parse(imageURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := c.newTLSClient()
|
||||
client, err := c.newDirectTLSClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func (c *Client) uploadInitImage(ctx context.Context, accessToken string, img []
|
||||
"query": mUploadImage,
|
||||
"variables": map[string]any{"uploadImageInput": map[string]any{"uploadType": "INIT", "extension": "png"}},
|
||||
})
|
||||
body, status, err := c.graphql(ctx, accessToken, payload)
|
||||
body, status, err := c.graphqlP(ctx, accessToken, payload, false)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: upload-init: %s", ErrTemporaryUpstream, err.Error())
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func (c *Client) uploadInitImage(ctx context.Context, accessToken string, img []
|
||||
}
|
||||
_ = w.Close()
|
||||
|
||||
client, err := c.newTLSClient()
|
||||
client, err := c.newDirectTLSClient()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -256,7 +256,7 @@ func (c *Client) pollImage(ctx context.Context, accessToken, genID string) (stri
|
||||
deadline := time.Now().Add(5 * time.Minute)
|
||||
|
||||
for {
|
||||
body, status, err := c.graphql(ctx, accessToken, payload)
|
||||
body, status, err := c.graphqlP(ctx, accessToken, payload, false)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: poll: %s", ErrTemporaryUpstream, err.Error())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user