⛏️ index : haiku.git

/*
 * Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
 * All rights reserved. Distributed under the terms of the MIT License.
 */


#include "AbstractSingleFileServerProcess.h"

#include <AutoLocker.h>
#include <StopWatch.h>

#include "HaikuDepotConstants.h"
#include "Logger.h"
#include "ServerHelper.h"
#include "ServerSettings.h"
#include "StorageUtils.h"


AbstractSingleFileServerProcess::AbstractSingleFileServerProcess(uint32 options)
	:
	AbstractServerProcess(options),
	fDownloadDurationSeconds(0.0),
	fProcessLocalDataDurationSeconds(0.0)
{
}


AbstractSingleFileServerProcess::~AbstractSingleFileServerProcess()
{
}


status_t
AbstractSingleFileServerProcess::RunInternal()
{
	HDINFO("[%s] will fetch data", Name());
	BPath localPath;
	status_t result = GetLocalPath(localPath);

	if (result != B_OK)
		return result;

	BString urlPathComponent = UrlPathComponent();

	if (IsSuccess(result) && HasOption(SERVER_PROCESS_DROP_CACHE))
		result = DeleteLocalFile(localPath);

	bool hasData = false;
	off_t size;

	if (IsSuccess(result))
		result = StorageUtils::ExistsObject(localPath, &hasData, NULL, &size);

	hasData = hasData && size > 0;

	if (IsSuccess(result) && ShouldAttemptNetworkDownload(hasData)) {
		BStopWatch stopWatch("download", true);
		result = DownloadToLocalFileAtomically(localPath,
			ServerSettings::CreateFullUrl(urlPathComponent));
		fDownloadDurationSeconds = ((double)stopWatch.ElapsedTime() / 1000000.0);

		if (!IsSuccess(result)) {
			if (hasData) {
				HDINFO("[%s] failed to update data, but have old data anyway so carry on with that",
					Name());
				result = B_OK;
			} else {
				HDERROR("[%s] failed to obtain data", Name());
			}
		} else {
			HDINFO("[%s] did fetch data", Name());
		}
	}

	if (IsSuccess(result)) {
		status_t hasDataResult = StorageUtils::ExistsObject(localPath, &hasData, NULL, &size);

		hasData = hasData && size > 0;

		if (hasDataResult == B_OK && !hasData) {
			HDINFO("[%s] there is no data to process", Name());
			result = HD_ERR_NO_DATA;
		}
	}

	if (IsSuccess(result)) {
		HDINFO("[%s] will process data", Name());

		BStopWatch stopWatch("process local data", true);
		result = ProcessLocalData();
		fProcessLocalDataDurationSeconds = ((double)stopWatch.ElapsedTime() / 1000000.0);

		switch (result) {
			case B_OK:
				HDINFO("[%s] did process data", Name());
				break;
			default:
				HDERROR("[%s] failed processing data", Name());
				MoveDamagedFileAside(localPath);
				break;
		}
	}

	return result;
}


status_t
AbstractSingleFileServerProcess::GetStandardMetaDataPath(BPath& path) const
{
	return GetLocalPath(path);
}


BString
AbstractSingleFileServerProcess::LogReport()
{
	BString result;
	result.Append(AbstractProcess::LogReport());

	AutoLocker<BLocker> locker(&fLock);

	if (ProcessState() == PROCESS_COMPLETE) {
		BString downloadLogLine;
		BString localDataLogLine;
		downloadLogLine.SetToFormat("\n - download %6.3f", fDownloadDurationSeconds);
		localDataLogLine.SetToFormat("\n - process local data %6.3f",
			fProcessLocalDataDurationSeconds);
		result.Append(downloadLogLine);
		result.Append(localDataLogLine);
	}

	return result;
}