• Модуль: clouds
  • Путь к файлу: ~/bitrix/modules/clouds/classes/general/failover.php
  • Класс: CCloudFailover
  • Вызов: CCloudFailover::executeCopyTask
static function executeCopyTask($copyTask, $overwrite)
{
	//Check if failover condition is active
	$testBucket = new CCloudStorageBucket($copyTask["SOURCE_BUCKET_ID"]);
	if (
		($testBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
		&& ($testBucket->FAILOVER_ACTIVE === "Y")
	)
	{
		return CCloudFailover::ST_FAILOVER;
	}

	$testBucket = new CCloudStorageBucket($copyTask["TARGET_BUCKET_ID"]);
	if (
		($testBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
		&& ($testBucket->FAILOVER_ACTIVE === "Y")
	)
	{
		return CCloudFailover::ST_FAILOVER;
	}

	//Initialize storages
	$sourceBucket = new CCloudStorageBucket($copyTask["SOURCE_BUCKET_ID"], false);
	if (!$sourceBucket->Init())
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
			"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
			"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): failed to init source bucket."
		));
		return CCloudFailover::ST_ERROR;
	}

	$targetBucket = new CCloudStorageBucket($copyTask["TARGET_BUCKET_ID"], false);
	if (!$targetBucket->Init())
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
			"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
			"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): failed to init target bucket."
		));
		return CCloudFailover::ST_ERROR;
	}

	//Check if source file is exists
	if (!$sourceBucket->FileExists($copyTask["SOURCE_FILE_PATH"]))
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
			"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
			"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): source file does not exists."
		));
		return CCloudFailover::ST_ERROR;
	}

	$CONTENT_TYPE = $sourceBucket->GetService()->GetLastRequestHeader('Content-Type');
	$CONTENT_LENGTH = $sourceBucket->GetService()->GetLastRequestHeader('Content-Length');

	if ($copyTask["FILE_SIZE"] == -1)
	{
		if ($CONTENT_LENGTH)
		{
			$copyTask["FILE_SIZE"] = intval($CONTENT_LENGTH);
		}
		else
		{
			$copyTask["FILE_SIZE"] = $sourceBucket->GetFileSize($copyTask["SOURCE_FILE_PATH"]);
		}
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FILE_SIZE" => $copyTask["FILE_SIZE"],
		));
	}
	//AddMessage2Log($copyTask);
	$targetBucket->setQueueFlag(false);
	$tempPath = $copyTask["TARGET_FILE_PATH"].".fail-over-copy-part";

	$CLOchunkSize = $targetBucket->GetService()->GetMinUploadPartSize();
	if ($copyTask["FILE_SIZE"] <= $CLOchunkSize)
	{
		$http = new BitrixMainWebHttpClient(array(
			"streamTimeout" => 0,
		));
		$arFile = array(
			"type" => $CONTENT_TYPE,
			"content" => false,
		);
		$arFile["content"] = $http->get($sourceBucket->GetFileSRC($copyTask["SOURCE_FILE_PATH"]));
		if ($arFile["content"] === false)
		{
			BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
				"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
				"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
				"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): failed to download."
			));
			return CCloudFailover::ST_ERROR;
		}

		if (!$overwrite && $targetBucket->FileExists($copyTask["TARGET_FILE_PATH"]))
		{
			BitrixCloudsCopyQueueTable::delete($copyTask["ID"]);
			return CCloudFailover::ST_CONTINUE;
		}

		$res = $targetBucket->SaveFile($copyTask["TARGET_FILE_PATH"], $arFile);
		if ($res)
		{
			BitrixCloudsCopyQueueTable::delete($copyTask["ID"]);
			return CCloudFailover::ST_CONTINUE;
		}
		else
		{
			BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
				"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
				"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
				"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): failed to upload file."
			));
			return CCloudFailover::ST_ERROR;
		}
	}

	$upload = new CCloudStorageUpload($tempPath);
	if ($copyTask["FILE_POS"] == 0)
	{
		if (!$overwrite && $targetBucket->FileExists($copyTask["TARGET_FILE_PATH"]))
		{
			BitrixCloudsCopyQueueTable::delete($copyTask["ID"]);
			return CCloudFailover::ST_CONTINUE;
		}

		if (!$upload->isStarted())
		{
			if (!$upload->Start($targetBucket, $copyTask["FILE_SIZE"], $CONTENT_TYPE))
			{
				BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
					"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
					"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
					"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): failed to start upload."
				));
				return CCloudFailover::ST_ERROR;
			}
		}
	}

	//Download part

	$http = new BitrixMainWebHttpClient();
	$rangeStart = $copyTask["FILE_POS"];
	$rangeEnd = min($copyTask["FILE_POS"] + $targetBucket->getService()->GetMinUploadPartSize(), $copyTask["FILE_SIZE"]) - 1;
	$http->setHeader("Range", "bytes=".$rangeStart."-".$rangeEnd);
	$data = $http->get($sourceBucket->GetFileSRC($copyTask["SOURCE_FILE_PATH"]));

	$uploadResult = false;
	while ($upload->hasRetries())
	{
		if ($upload->Next($data, $targetBucket))
		{
			$uploadResult = true;
			break;
		}
	}

	if (!$uploadResult)
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
			"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
			"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): upload part failed."
		));
		return CCloudFailover::ST_ERROR;
	}

	$filePos = $upload->getPos();

	//Continue next time
	if ($filePos < $copyTask["FILE_SIZE"])
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FILE_POS" => $filePos,
		));
		return CCloudFailover::ST_CONTINUE;
	}

	if (!$upload->Finish($targetBucket))
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
			"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
			"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): finish has failed."
		));
		return CCloudFailover::ST_ERROR;
	}

	if (!CCloudTempFile::IsTempFile($copyTask["TARGET_FILE_PATH"]))
	{
		$targetBucket->IncFileCounter($copyTask["FILE_SIZE"]);
	}

	if ($overwrite && $targetBucket->FileExists($copyTask["TARGET_FILE_PATH"]))
	{
		$fileSize = $targetBucket->GetFileSize($copyTask["TARGET_FILE_PATH"]);
		if ($targetBucket->DeleteFile($copyTask["TARGET_FILE_PATH"]))
		{
			if (!CCloudTempFile::IsTempFile($copyTask["TARGET_FILE_PATH"]))
			{
				$targetBucket->DecFileCounter($fileSize);
			}
		}
	}

	if (!$targetBucket->FileRename($tempPath, $copyTask["TARGET_FILE_PATH"]))
	{
		BitrixCloudsCopyQueueTable::update($copyTask["ID"], array(
			"FAIL_COUNTER" => $copyTask["FAIL_COUNTER"] + 1,
			"STATUS" => $copyTask["FAIL_COUNTER"] >= COption::GetOptionInt("clouds", "max_copy_fail_count")? "F": $copyTask["STATUS"],
			"ERROR_MESSAGE" => "CCloudFailover::executeCopyQueue(".$copyTask["ID"]."): rename failed."
		));
		return CCloudFailover::ST_ERROR;
	}

	BitrixCloudsCopyQueueTable::delete($copyTask["ID"]);
	return CCloudFailover::ST_CONTINUE;
}