fix: Destroy CSS Cache file when invalid (#1018)
## Summary * Destroy CSS Cache file when invalid ## Additional Context * Fixes issue where it would attempt to rebuild every book open --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? No
This commit is contained in:
@@ -268,64 +268,69 @@ void Epub::parseCssFiles() const {
|
|||||||
LOG_DBG("EBP", "No CSS files to parse, but CssParser created for inline styles");
|
LOG_DBG("EBP", "No CSS files to parse, but CssParser created for inline styles");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DBG("EBP", "CSS files to parse: %zu", cssFiles.size());
|
||||||
|
|
||||||
// See if we have a cached version of the CSS rules
|
// See if we have a cached version of the CSS rules
|
||||||
if (!cssParser->hasCache()) {
|
if (cssParser->hasCache()) {
|
||||||
// No cache yet - parse CSS files
|
LOG_DBG("EBP", "CSS cache exists, skipping parseCssFiles");
|
||||||
for (const auto& cssPath : cssFiles) {
|
return;
|
||||||
LOG_DBG("EBP", "Parsing CSS file: %s", cssPath.c_str());
|
}
|
||||||
|
|
||||||
// Check heap before parsing - CSS parsing allocates heavily
|
// No cache yet - parse CSS files
|
||||||
const uint32_t freeHeap = ESP.getFreeHeap();
|
for (const auto& cssPath : cssFiles) {
|
||||||
if (freeHeap < MIN_HEAP_FOR_CSS_PARSING) {
|
LOG_DBG("EBP", "Parsing CSS file: %s", cssPath.c_str());
|
||||||
LOG_ERR("EBP", "Insufficient heap for CSS parsing (%u bytes free, need %zu), skipping: %s", freeHeap,
|
|
||||||
MIN_HEAP_FOR_CSS_PARSING, cssPath.c_str());
|
// Check heap before parsing - CSS parsing allocates heavily
|
||||||
|
const uint32_t freeHeap = ESP.getFreeHeap();
|
||||||
|
if (freeHeap < MIN_HEAP_FOR_CSS_PARSING) {
|
||||||
|
LOG_ERR("EBP", "Insufficient heap for CSS parsing (%u bytes free, need %zu), skipping: %s", freeHeap,
|
||||||
|
MIN_HEAP_FOR_CSS_PARSING, cssPath.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check CSS file size before decompressing - skip files that are too large
|
||||||
|
size_t cssFileSize = 0;
|
||||||
|
if (getItemSize(cssPath, &cssFileSize)) {
|
||||||
|
if (cssFileSize > MAX_CSS_FILE_SIZE) {
|
||||||
|
LOG_ERR("EBP", "CSS file too large (%zu bytes > %zu max), skipping: %s", cssFileSize, MAX_CSS_FILE_SIZE,
|
||||||
|
cssPath.c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check CSS file size before decompressing - skip files that are too large
|
// Extract CSS file to temp location
|
||||||
size_t cssFileSize = 0;
|
const auto tmpCssPath = getCachePath() + "/.tmp.css";
|
||||||
if (getItemSize(cssPath, &cssFileSize)) {
|
FsFile tempCssFile;
|
||||||
if (cssFileSize > MAX_CSS_FILE_SIZE) {
|
if (!Storage.openFileForWrite("EBP", tmpCssPath, tempCssFile)) {
|
||||||
LOG_ERR("EBP", "CSS file too large (%zu bytes > %zu max), skipping: %s", cssFileSize, MAX_CSS_FILE_SIZE,
|
LOG_ERR("EBP", "Could not create temp CSS file");
|
||||||
cssPath.c_str());
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if (!readItemContentsToStream(cssPath, tempCssFile, 1024)) {
|
||||||
}
|
LOG_ERR("EBP", "Could not read CSS file: %s", cssPath.c_str());
|
||||||
|
|
||||||
// Extract CSS file to temp location
|
|
||||||
const auto tmpCssPath = getCachePath() + "/.tmp.css";
|
|
||||||
FsFile tempCssFile;
|
|
||||||
if (!Storage.openFileForWrite("EBP", tmpCssPath, tempCssFile)) {
|
|
||||||
LOG_ERR("EBP", "Could not create temp CSS file");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!readItemContentsToStream(cssPath, tempCssFile, 1024)) {
|
|
||||||
LOG_ERR("EBP", "Could not read CSS file: %s", cssPath.c_str());
|
|
||||||
tempCssFile.close();
|
|
||||||
Storage.remove(tmpCssPath.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tempCssFile.close();
|
|
||||||
|
|
||||||
// Parse the CSS file
|
|
||||||
if (!Storage.openFileForRead("EBP", tmpCssPath, tempCssFile)) {
|
|
||||||
LOG_ERR("EBP", "Could not open temp CSS file for reading");
|
|
||||||
Storage.remove(tmpCssPath.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cssParser->loadFromStream(tempCssFile);
|
|
||||||
tempCssFile.close();
|
tempCssFile.close();
|
||||||
Storage.remove(tmpCssPath.c_str());
|
Storage.remove(tmpCssPath.c_str());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
tempCssFile.close();
|
||||||
|
|
||||||
// Save to cache for next time
|
// Parse the CSS file
|
||||||
if (!cssParser->saveToCache()) {
|
if (!Storage.openFileForRead("EBP", tmpCssPath, tempCssFile)) {
|
||||||
LOG_ERR("EBP", "Failed to save CSS rules to cache");
|
LOG_ERR("EBP", "Could not open temp CSS file for reading");
|
||||||
|
Storage.remove(tmpCssPath.c_str());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
cssParser->clear();
|
cssParser->loadFromStream(tempCssFile);
|
||||||
|
tempCssFile.close();
|
||||||
LOG_DBG("EBP", "Loaded %zu CSS style rules from %zu files", cssParser->ruleCount(), cssFiles.size());
|
Storage.remove(tmpCssPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save to cache for next time
|
||||||
|
if (!cssParser->saveToCache()) {
|
||||||
|
LOG_ERR("EBP", "Failed to save CSS rules to cache");
|
||||||
|
}
|
||||||
|
cssParser->clear();
|
||||||
|
|
||||||
|
LOG_DBG("EBP", "Loaded %zu CSS style rules from %zu files", cssParser->ruleCount(), cssFiles.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// load in the meta data for the epub file
|
// load in the meta data for the epub file
|
||||||
@@ -341,12 +346,10 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
|||||||
if (bookMetadataCache->load()) {
|
if (bookMetadataCache->load()) {
|
||||||
if (!skipLoadingCss) {
|
if (!skipLoadingCss) {
|
||||||
// Rebuild CSS cache when missing or when cache version changed (loadFromCache removes stale file)
|
// Rebuild CSS cache when missing or when cache version changed (loadFromCache removes stale file)
|
||||||
bool needCssRebuild = !cssParser->hasCache();
|
if (!cssParser->hasCache() || !cssParser->loadFromCache()) {
|
||||||
if (cssParser->hasCache() && !cssParser->loadFromCache()) {
|
|
||||||
needCssRebuild = true;
|
|
||||||
}
|
|
||||||
if (needCssRebuild) {
|
|
||||||
LOG_DBG("EBP", "CSS rules cache missing or stale, attempting to parse CSS files");
|
LOG_DBG("EBP", "CSS rules cache missing or stale, attempting to parse CSS files");
|
||||||
|
cssParser->deleteCache();
|
||||||
|
|
||||||
if (!parseContentOpf(bookMetadataCache->coreMetadata)) {
|
if (!parseContentOpf(bookMetadataCache->coreMetadata)) {
|
||||||
LOG_ERR("EBP", "Could not parse content.opf from cached bookMetadata for CSS files");
|
LOG_ERR("EBP", "Could not parse content.opf from cached bookMetadata for CSS files");
|
||||||
// continue anyway - book will work without CSS and we'll still load any inline style CSS
|
// continue anyway - book will work without CSS and we'll still load any inline style CSS
|
||||||
|
|||||||
@@ -640,6 +640,10 @@ constexpr char rulesCache[] = "/css_rules.cache";
|
|||||||
|
|
||||||
bool CssParser::hasCache() const { return Storage.exists((cachePath + rulesCache).c_str()); }
|
bool CssParser::hasCache() const { return Storage.exists((cachePath + rulesCache).c_str()); }
|
||||||
|
|
||||||
|
void CssParser::deleteCache() const {
|
||||||
|
if (hasCache()) Storage.remove((cachePath + rulesCache).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
bool CssParser::saveToCache() const {
|
bool CssParser::saveToCache() const {
|
||||||
if (cachePath.empty()) {
|
if (cachePath.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ class CssParser {
|
|||||||
*/
|
*/
|
||||||
bool hasCache() const;
|
bool hasCache() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete CSS rules cache file exists
|
||||||
|
*/
|
||||||
|
void deleteCache() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save parsed CSS rules to a cache file.
|
* Save parsed CSS rules to a cache file.
|
||||||
* @return true if cache was written successfully
|
* @return true if cache was written successfully
|
||||||
|
|||||||
Reference in New Issue
Block a user