Merge branch 'srett-fileresource-open-once' into develop

This commit is contained in:
emeric
2025-06-02 21:35:41 +02:00
2 changed files with 36 additions and 43 deletions
+33 -42
View File
@@ -19,8 +19,6 @@
#include "FileResourceHandler.hpp" #include "FileResourceHandler.hpp"
#include <fstream>
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "core/MimeTypes.hpp" #include "core/MimeTypes.hpp"
@@ -32,38 +30,37 @@ namespace lms::core
} }
FileResourceHandler::FileResourceHandler(const std::filesystem::path& path, std::string_view mimeType) FileResourceHandler::FileResourceHandler(const std::filesystem::path& path, std::string_view mimeType)
: _path{ path } : _mimeType{ mimeType }
, _mimeType{ mimeType } , _ifs{ path, std::ios::in | std::ios::binary }
{ {
if (!_ifs)
LMS_LOG(UTILS, ERROR, "Cannot open file stream for " << path);
else
{
_ifs.seekg(0, std::ios::end);
if (!_ifs.fail())
_fileSize = static_cast<::uint64_t>(_ifs.tellg());
LMS_LOG(UTILS, DEBUG, "File " << path << ", fileSize = " << _fileSize);
}
} }
Wt::Http::ResponseContinuation* FileResourceHandler::processRequest(const Wt::Http::Request& request, Wt::Http::Response& response) Wt::Http::ResponseContinuation* FileResourceHandler::processRequest(const Wt::Http::Request& request, Wt::Http::Response& response)
{ {
::uint64_t startByte{ _offset }; if (_offset == 0)
std::ifstream ifs{ _path, std::ios::in | std::ios::binary };
if (startByte == 0)
{ {
if (!ifs) if (!_ifs)
{ {
LMS_LOG(UTILS, ERROR, "Cannot open file stream for " << _path);
response.setStatus(404); response.setStatus(404);
return {}; return {};
} }
ifs.seekg(0, std::ios::end);
const ::uint64_t fileSize{ static_cast<::uint64_t>(ifs.tellg()) };
ifs.seekg(0, std::ios::beg);
LMS_LOG(UTILS, DEBUG, "File " << _path << ", fileSize = " << fileSize);
response.addHeader("Accept-Ranges", "bytes"); response.addHeader("Accept-Ranges", "bytes");
const Wt::Http::Request::ByteRangeSpecifier ranges{ request.getRanges(fileSize) }; const Wt::Http::Request::ByteRangeSpecifier ranges{ request.getRanges(_fileSize) };
if (!ranges.isSatisfiable()) if (!ranges.isSatisfiable())
{ {
std::ostringstream contentRange; std::ostringstream contentRange;
contentRange << "bytes */" << fileSize; contentRange << "bytes */" << _fileSize;
response.setStatus(416); // Requested range not satisfiable response.setStatus(416); // Requested range not satisfiable
response.addHeader("Content-Range", contentRange.str()); response.addHeader("Content-Range", contentRange.str());
@@ -76,57 +73,51 @@ namespace lms::core
LMS_LOG(UTILS, DEBUG, "Range requested = " << ranges[0].firstByte() << "-" << ranges[0].lastByte()); LMS_LOG(UTILS, DEBUG, "Range requested = " << ranges[0].firstByte() << "-" << ranges[0].lastByte());
response.setStatus(206); response.setStatus(206);
startByte = ranges[0].firstByte(); _offset = ranges[0].firstByte();
_beyondLastByte = ranges[0].lastByte() + 1; _beyondLastByte = ranges[0].lastByte() + 1;
std::ostringstream contentRange; std::ostringstream contentRange;
contentRange << "bytes " << startByte << "-" contentRange << "bytes " << _offset << "-"
<< _beyondLastByte - 1 << "/" << fileSize; << _beyondLastByte - 1 << "/" << _fileSize;
response.addHeader("Content-Range", contentRange.str()); response.addHeader("Content-Range", contentRange.str());
response.setContentLength(_beyondLastByte - startByte); response.setContentLength(_beyondLastByte - _offset);
} }
else else
{ {
LMS_LOG(UTILS, DEBUG, "No range requested"); LMS_LOG(UTILS, DEBUG, "No range requested");
response.setStatus(200); response.setStatus(200);
_beyondLastByte = fileSize; _beyondLastByte = _fileSize;
response.setContentLength(_beyondLastByte); response.setContentLength(_beyondLastByte);
} }
LMS_LOG(UTILS, DEBUG, "Mimetype set to '" << _mimeType << "'"); LMS_LOG(UTILS, DEBUG, "Mimetype set to '" << _mimeType << "'");
response.setMimeType(_mimeType); response.setMimeType(_mimeType);
}
else if (!ifs)
{
LMS_LOG(UTILS, ERROR, "Cannot reopen file stream for " << _path);
return {};
}
ifs.seekg(static_cast<std::istream::pos_type>(startByte)); _ifs.seekg(static_cast<std::istream::pos_type>(_offset));
} // end initial response setup
std::vector<char> buf; ::uint64_t restSize = _beyondLastByte - _offset;
buf.resize(_chunkSize); ::uint64_t pieceSize = std::min(restSize, _chunkSize);
::uint64_t restSize = _beyondLastByte - startByte; std::vector<char> buf(pieceSize);
::uint64_t pieceSize = buf.size() > restSize ? restSize : buf.size();
ifs.read(&buf[0], pieceSize); _ifs.read(buf.data(), buf.size());
const ::uint64_t actualPieceSize{ static_cast<::uint64_t>(ifs.gcount()) }; const ::uint64_t actualPieceSize{ static_cast<::uint64_t>(_ifs.gcount()) };
if (actualPieceSize > 0) if (actualPieceSize > 0)
{ {
response.out().write(&buf[0], actualPieceSize); response.out().write(buf.data(), actualPieceSize);
LMS_LOG(UTILS, DEBUG, "Written " << actualPieceSize << " bytes, range = " << startByte << "-" << startByte + actualPieceSize - 1 << ""); LMS_LOG(UTILS, DEBUG, "Written " << actualPieceSize << " bytes, range = " << _offset << "-" << _offset + actualPieceSize - 1 << "");
} }
else else
{
LMS_LOG(UTILS, DEBUG, "Written 0 byte"); LMS_LOG(UTILS, DEBUG, "Written 0 byte");
}
if (ifs.good() && actualPieceSize < restSize) if (!_ifs.good())
LMS_LOG(UTILS, WARNING, "Error reading from file!");
else if (actualPieceSize < restSize)
{ {
_offset = startByte + actualPieceSize; _offset += actualPieceSize;
LMS_LOG(UTILS, DEBUG, "Job not complete! Remaining range: " << _offset << "-" << _beyondLastByte - 1); LMS_LOG(UTILS, DEBUG, "Job not complete! Remaining range: " << _offset << "-" << _beyondLastByte - 1);
return response.createContinuation(); return response.createContinuation();
+3 -1
View File
@@ -22,6 +22,7 @@
#include <filesystem> #include <filesystem>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <fstream>
#include "core/IResourceHandler.hpp" #include "core/IResourceHandler.hpp"
@@ -38,9 +39,10 @@ namespace lms::core
static constexpr std::size_t _chunkSize{ 262'144 }; static constexpr std::size_t _chunkSize{ 262'144 };
std::filesystem::path _path;
std::string _mimeType; std::string _mimeType;
::uint64_t _beyondLastByte{}; ::uint64_t _beyondLastByte{};
::uint64_t _offset{}; ::uint64_t _offset{};
::uint64_t _fileSize{};
std::ifstream _ifs;
}; };
} // namespace lms::core } // namespace lms::core