更新
This commit is contained in:
@@ -42,6 +42,7 @@ final class DifyRequiredAttachmentUpload
|
||||
array $options = []
|
||||
): array {
|
||||
$temporary = [];
|
||||
$multi = null;
|
||||
$skipped = [];
|
||||
$index = 0;
|
||||
$total = 0;
|
||||
@@ -78,6 +79,11 @@ final class DifyRequiredAttachmentUpload
|
||||
}
|
||||
}
|
||||
unset($item);
|
||||
// Keep libcurl's connection cache only for this preparation. Each
|
||||
// transfer still owns a fresh easy handle, so source downloads never
|
||||
// inherit the Dify upload headers or request body.
|
||||
$multi = curl_multi_init();
|
||||
if ($multi === false) self::fail('CURL_UNAVAILABLE');
|
||||
$prepared = [];
|
||||
$uploadedIndices = [];
|
||||
$cache = [];
|
||||
@@ -99,7 +105,7 @@ final class DifyRequiredAttachmentUpload
|
||||
if (isset($item['path'])) {
|
||||
self::copyLocal($item['path'], $path, $maxBytes, $deadline, $shouldAbort);
|
||||
} else {
|
||||
$exists = self::download($item['url'], $item['parts'], $path, $maxBytes, $deadline, $shouldAbort, $options);
|
||||
$exists = self::download($item['url'], $item['parts'], $path, $maxBytes, $deadline, $shouldAbort, $options, $multi);
|
||||
}
|
||||
self::check($deadline, $shouldAbort);
|
||||
if (!$exists) {
|
||||
@@ -113,7 +119,7 @@ final class DifyRequiredAttachmentUpload
|
||||
'audio/wav' => 'wav', 'audio/mpeg' => 'mp3', 'text/plain' => 'txt'][$mime] ?? 'bin';
|
||||
}
|
||||
$cache[$cacheKey] = self::upload($endpoint, $apiKey, $user, $path, $mime,
|
||||
'attachment-' . $index . '.' . $extension, $deadline, $shouldAbort, $options['ca_file']);
|
||||
'attachment-' . $index . '.' . $extension, $deadline, $shouldAbort, $options['ca_file'], $multi);
|
||||
}
|
||||
}
|
||||
if ($cache[$cacheKey] === null) {
|
||||
@@ -155,6 +161,7 @@ final class DifyRequiredAttachmentUpload
|
||||
'failed_index' => $index, 'attachment_count' => $total, 'skipped' => $skipped];
|
||||
} finally {
|
||||
foreach ($temporary as $path) if (is_file($path)) @unlink($path);
|
||||
if ($multi !== null && $multi !== false) curl_multi_close($multi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +347,7 @@ final class DifyRequiredAttachmentUpload
|
||||
}
|
||||
}
|
||||
|
||||
private static function download(string $url, array $parts, string $path, int $maxBytes, float $deadline, ?callable $shouldAbort, array $options): bool
|
||||
private static function download(string $url, array $parts, string $path, int $maxBytes, float $deadline, ?callable $shouldAbort, array $options, $multi): bool
|
||||
{
|
||||
self::check($deadline, $shouldAbort);
|
||||
$host = trim($parts['host'], '[]');
|
||||
@@ -391,7 +398,7 @@ final class DifyRequiredAttachmentUpload
|
||||
return $written;
|
||||
};
|
||||
if (!curl_setopt_array($ch, $curlOptions)) self::fail('REQUIRED_FILES_DOWNLOAD_FAILED');
|
||||
$result = self::execute($ch, $deadline, $shouldAbort);
|
||||
$result = self::execute($multi, $ch, $deadline, $shouldAbort);
|
||||
if ($writeError !== '') self::fail($writeError);
|
||||
if ($result['errno'] === CURLE_OPERATION_TIMEDOUT) self::fail('REQUIRED_FILES_TIMEOUT');
|
||||
if ($result['errno'] !== CURLE_OK) self::fail('REQUIRED_FILES_DOWNLOAD_FAILED');
|
||||
@@ -426,7 +433,7 @@ final class DifyRequiredAttachmentUpload
|
||||
&& ($remaining === 0 || (ord($packed[$bytes]) & (255 << (8 - $remaining))) === (ord($base[$bytes]) & (255 << (8 - $remaining))));
|
||||
}
|
||||
|
||||
private static function upload(string $endpoint, string $apiKey, string $user, string $path, string $mime, string $name, float $deadline, ?callable $shouldAbort, string $caFile): string
|
||||
private static function upload(string $endpoint, string $apiKey, string $user, string $path, string $mime, string $name, float $deadline, ?callable $shouldAbort, string $caFile, $multi): string
|
||||
{
|
||||
self::check($deadline, $shouldAbort);
|
||||
$ch = curl_init();
|
||||
@@ -444,7 +451,7 @@ final class DifyRequiredAttachmentUpload
|
||||
return strlen($chunk);
|
||||
};
|
||||
if (!curl_setopt_array($ch, $options)) self::fail('REQUIRED_FILES_UPLOAD_FAILED');
|
||||
$result = self::execute($ch, $deadline, $shouldAbort);
|
||||
$result = self::execute($multi, $ch, $deadline, $shouldAbort);
|
||||
if ($result['errno'] === CURLE_OPERATION_TIMEDOUT) self::fail('REQUIRED_FILES_TIMEOUT');
|
||||
if ($result['errno'] !== CURLE_OK || $tooLarge || !in_array($result['status'], [200, 201], true)) self::fail('REQUIRED_FILES_UPLOAD_FAILED');
|
||||
$decoded = json_decode($body, true);
|
||||
@@ -475,10 +482,9 @@ final class DifyRequiredAttachmentUpload
|
||||
return $options;
|
||||
}
|
||||
|
||||
/** curl_multi polling observes cancellation even while no headers/body arrive. */
|
||||
private static function execute($ch, float $deadline, ?callable $shouldAbort): array
|
||||
/** Request-local pool retains connections; polling also observes silent cancellation. */
|
||||
private static function execute($multi, $ch, float $deadline, ?callable $shouldAbort): array
|
||||
{
|
||||
$multi = curl_multi_init();
|
||||
$added = false;
|
||||
try {
|
||||
if (curl_multi_add_handle($multi, $ch) !== CURLM_OK) self::fail('REQUIRED_FILES_PREPARE_FAILED');
|
||||
@@ -495,7 +501,6 @@ final class DifyRequiredAttachmentUpload
|
||||
return ['errno' => $errno, 'status' => (int) curl_getinfo($ch, CURLINFO_HTTP_CODE)];
|
||||
} finally {
|
||||
if ($added) curl_multi_remove_handle($multi, $ch);
|
||||
curl_multi_close($multi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user