wsd: refactor the download logic in DocumentBroker

Change-Id: Ic916a8373664f2b4de8d8649bf160effb1fe3dfa
Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
This commit is contained in:
Ashod Nakashian 2024-03-31 08:33:05 -04:00 committed by Michael Meeks
parent b2c980a91a
commit 72c368ea0e
2 changed files with 102 additions and 135 deletions

View file

@ -32,6 +32,7 @@
#include <Poco/URI.h>
#include "Admin.hpp"
#include "Authorization.hpp"
#include "ClientSession.hpp"
#include "Exceptions.hpp"
#include "COOLWSD.hpp"
@ -881,70 +882,13 @@ bool DocumentBroker::downloadAdvance(const std::string& jailId, const Poco::URI&
std::chrono::milliseconds getFileCallDurationMs = std::chrono::milliseconds::zero();
if (!_storage->isDownloaded())
{
LOG_DBG("Download file for docKey [" << _docKey << ']');
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
std::string localPath = _storage->downloadStorageFileToLocal(
Authorization::create(uriPublic), *_lockCtx, templateSource);
if (localPath.empty())
const Authorization auth = Authorization::create(uriPublic);
if (!doDownloadDocument(/*session=*/nullptr, auth, templateSource, fileInfo.getFilename(),
getFileCallDurationMs))
{
throw std::runtime_error("Failed to retrieve document from storage");
}
getFileCallDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
_docState.setStatus(DocumentState::Status::Loading); // Done downloading.
#if !MOBILEAPP
if (!processPlugins(localPath))
{
// FIXME: Why don't we resume anyway?
LOG_WRN("Failed to process plugins on file [" << localPath << ']');
LOG_DBG("Failed to download or process downloaded document");
return false;
}
#endif //!MOBILEAPP
const std::string localFilePath = Poco::Path(getJailRoot(), localPath).toString();
std::ifstream istr(localFilePath, std::ios::binary);
Poco::SHA1Engine sha1;
Poco::DigestOutputStream dos(sha1);
Poco::StreamCopier::copyStream(istr, dos);
dos.close();
LOG_INF("SHA1 for DocKey [" << _docKey << "] of [" << COOLWSD::anonymizeUrl(localPath)
<< "]: " << Poco::DigestEngine::digestToHex(sha1.digest()));
std::string localPathEncoded;
Poco::URI::encode(localPath, "#?", localPathEncoded);
_uriJailed = Poco::URI(Poco::URI("file://"), localPathEncoded).toString();
_uriJailedAnonym =
Poco::URI(Poco::URI("file://"), COOLWSD::anonymizeUrl(localPathEncoded)).toString();
_filename = fileInfo.getFilename();
#if !MOBILEAPP
_quarantine = std::make_unique<Quarantine>(*this, _filename);
#endif
if (!templateSource.empty())
{
// Invalid timestamp for templates, to force uploading once we save-after-loading.
_saveManager.setLastModifiedTime(std::chrono::system_clock::time_point());
_storageManager.setLastUploadedFileModifiedTime(
std::chrono::system_clock::time_point());
}
else
{
// Use the local temp file's timestamp.
const auto timepoint = FileUtil::Stat(localFilePath).modifiedTimepoint();
_saveManager.setLastModifiedTime(timepoint);
_storageManager.setLastUploadedFileModifiedTime(
timepoint); // Used to detect modifications.
}
bool dontUseCache = Util::isMobileApp();
_tileCache = std::make_unique<TileCache>(_storage->getUri().toString(),
_saveManager.getLastModifiedTime(), dontUseCache);
_tileCache->setThreadOwner(std::this_thread::get_id());
}
#if !MOBILEAPP
@ -1147,10 +1091,45 @@ bool DocumentBroker::download(
std::chrono::milliseconds getFileCallDurationMs = std::chrono::milliseconds::zero();
if (!_storage->isDownloaded())
{
const Authorization auth =
session ? session->getAuthorization() : Authorization::create(uriPublic);
if (!doDownloadDocument(session, auth, templateSource, fileInfo.getFilename(),
getFileCallDurationMs))
{
LOG_DBG("Failed to download or process downloaded document");
return false;
}
}
#if !MOBILEAPP
COOLWSD::dumpNewSessionTrace(getJailId(), sessionId, _uriOrig, _storage->getRootFilePath());
// Since document has been loaded, send the stats if its WOPI
if (wopiStorage != nullptr)
{
// Add the time taken to load the file from storage and to check file info.
_wopiDownloadDuration += getFileCallDurationMs + checkFileInfoCallDurationMs;
const auto downloadSecs = _wopiDownloadDuration.count() / 1000.;
const std::string msg =
"stats: wopiloadduration " + std::to_string(downloadSecs); // In seconds.
LOG_TRC("Sending to Client [" << msg << "].");
session->sendTextFrame(msg);
}
#endif
return true;
}
bool DocumentBroker::doDownloadDocument(const std::shared_ptr<ClientSession>& session,
const Authorization& auth,
const std::string& templateSource,
const std::string& filename,
std::chrono::milliseconds& getFileCallDurationMs)
{
assert(_storage && !_storage->isDownloaded());
LOG_DBG("Download file for docKey [" << _docKey << ']');
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
std::string localPath = _storage->downloadStorageFileToLocal(session->getAuthorization(),
*_lockCtx, templateSource);
std::string localPath = _storage->downloadStorageFileToLocal(auth, *_lockCtx, templateSource);
if (localPath.empty())
{
throw std::runtime_error("Failed to retrieve document from storage");
@ -1163,13 +1142,12 @@ bool DocumentBroker::download(
// Only lock the document on storage for editing sessions
// FIXME: why not lock before downloadStorageFileToLocal? Would also prevent race conditions
if (!session->isReadOnly())
if (session && !session->isReadOnly())
{
std::string error;
if (!updateStorageLockState(*session, /*lock=*/true, error))
{
LOG_ERR("Failed to lock docKey [" << _docKey << "] with session ["
<< session->getId()
LOG_ERR("Failed to lock docKey [" << _docKey << "] with session [" << session->getId()
<< "] after downloading: " << error);
}
}
@ -1198,7 +1176,7 @@ bool DocumentBroker::download(
_uriJailedAnonym =
Poco::URI(Poco::URI("file://"), COOLWSD::anonymizeUrl(localPathEncoded)).toString();
_filename = fileInfo.getFilename();
_filename = filename;
#if !MOBILEAPP
_quarantine = std::make_unique<Quarantine>(*this, _filename);
#endif
@ -1207,40 +1185,22 @@ bool DocumentBroker::download(
{
// Invalid timestamp for templates, to force uploading once we save-after-loading.
_saveManager.setLastModifiedTime(std::chrono::system_clock::time_point());
_storageManager.setLastUploadedFileModifiedTime(
std::chrono::system_clock::time_point());
_storageManager.setLastUploadedFileModifiedTime(std::chrono::system_clock::time_point());
}
else
{
// Use the local temp file's timestamp.
const auto timepoint = FileUtil::Stat(localFilePath).modifiedTimepoint();
_saveManager.setLastModifiedTime(timepoint);
_storageManager.setLastUploadedFileModifiedTime(
timepoint); // Used to detect modifications.
_storageManager.setLastUploadedFileModifiedTime(timepoint); // Used to detect modifications.
}
bool dontUseCache = Util::isMobileApp();
const bool dontUseCache = Util::isMobileApp();
_tileCache = std::make_unique<TileCache>(_storage->getUri().toString(),
_saveManager.getLastModifiedTime(), dontUseCache);
_tileCache->setThreadOwner(std::this_thread::get_id());
}
#if !MOBILEAPP
COOLWSD::dumpNewSessionTrace(getJailId(), sessionId, _uriOrig, _storage->getRootFilePath());
// Since document has been loaded, send the stats if its WOPI
if (wopiStorage != nullptr)
{
// Add the time taken to load the file from storage and to check file info.
_wopiDownloadDuration += getFileCallDurationMs + checkFileInfoCallDurationMs;
const auto downloadSecs = _wopiDownloadDuration.count() / 1000.;
const std::string msg =
"stats: wopiloadduration " + std::to_string(downloadSecs); // In seconds.
LOG_TRC("Sending to Client [" << msg << "].");
session->sendTextFrame(msg);
}
#endif
return true;
}

View file

@ -594,6 +594,13 @@ private:
bool download(const std::shared_ptr<ClientSession>& session, const std::string& jailId,
std::unique_ptr<WopiStorage::WOPIFileInfo> wopiFileInfo);
/// Actual document download and post-download processing.
/// Must be called only when creating the storage for the first time.
bool doDownloadDocument(const std::shared_ptr<ClientSession>& session,
const Authorization& auth, const std::string& templateSource,
const std::string& filename,
std::chrono::milliseconds& getFileCallDurationMs);
#if !MOBILEAPP
/// Updates the Session with the wopiFileInfo given.
/// Returns the templateSource, if any.