diff options
| author | Erik Kundiman <erik@megapahit.org> | 2026-09-01 18:35:23 +0800 |
|---|---|---|
| committer | Erik Kundiman <erik@megapahit.org> | 2026-09-04 21:58:53 +0800 |
| commit | 00bb3bb6f07660bd914d29a1389342bb3060d254 (patch) | |
| tree | 431f574922494d2201718f13085f17bc6bd7fb42 /indra/newview/llsyntaxid.cpp | |
| parent | a8636720129952c10cf49ab80da21bf8b340b96c (diff) | |
| parent | 4ef9f8f14b35ed388c294d53767a0dca0e890924 (diff) | |
Merge remote-tracking branch 'secondlife/release/26.4' into 26.4
Diffstat (limited to 'indra/newview/llsyntaxid.cpp')
| -rw-r--r-- | indra/newview/llsyntaxid.cpp | 511 |
1 files changed, 384 insertions, 127 deletions
diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index f89ae00c5b..58d1287979 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -35,39 +35,59 @@ #include "llviewerregion.h" #include "llcorehttputil.h" + //----------------------------------------------------------------------------- // LLSyntaxIdLSL //----------------------------------------------------------------------------- -const std::string SYNTAX_ID_CAPABILITY_NAME = "LSLSyntax"; -const std::string SYNTAX_ID_SIMULATOR_FEATURE = "LSLSyntaxId"; -const std::string FILENAME_DEFAULT = "keywords_lsl_default.xml"; +namespace +{ + const std::string SYNTAX_ID_CAPABILITY_NAME = "LSLSyntax"; + const std::string SYNTAX_DEF_CAPABILITY_NAME = "ScriptDefinitions"; + const std::string SYNTAX_ID_SIMULATOR_FEATURE = "LSLSyntaxId"; + const std::string FILENAME_INTERNAL_LSL = "lsl_keywords.xml"; + const std::string FILENAME_INTERNAL_LUA = "lua_keywords.xml"; + const std::string FILENAME_DEFAULT_LSL = "keywords_lsl_default.xml"; + const std::string FILENAME_DEFAULT_LUA = "keywords_lua_default.xml"; -/** - * @brief LLSyntaxIdLSL constructor - */ -LLSyntaxIdLSL::LLSyntaxIdLSL() -: mKeywordsXml(LLSD()) -, mCapabilityURL(std::string()) -, mFilePath(LL_PATH_APP_SETTINGS) -, mSyntaxId(LLUUID()) -, mInitialized(false) + constexpr U32 LLSD_SYNTAX_LSL_VERSION_EXPECTED = 2; + const std::string LLSD_SYNTAX_LSL_VERSION_KEY("llsd-lsl-syntax-version"); + + const std::unordered_set<std::string> MEMCACHED_LLSD = { + FILENAME_INTERNAL_LSL, + FILENAME_INTERNAL_LUA + }; +} // namespace + +//======================================================================== +void LLSyntaxDefCache::initSingleton() { - loadDefaultKeywordsIntoLLSD(); - mRegionChangedCallback = gAgent.addRegionChangedCallback(boost::bind(&LLSyntaxIdLSL::handleRegionChanged, this)); + buildDefaultCache(); + loadKeywordsIntoLLSD(); + mRegionChangedCallback = gAgent.addRegionChangedCallback(boost::bind(&LLSyntaxDefCache::handleRegionChanged, this)); handleRegionChanged(); // Kick off an initial caps query and fetch } -void LLSyntaxIdLSL::buildFullFileSpec() +void LLSyntaxDefCache::cleanupSingleton() { - ELLPath path = mSyntaxId.isNull() ? LL_PATH_APP_SETTINGS : LL_PATH_CACHE; - const std::string filename = mSyntaxId.isNull() ? FILENAME_DEFAULT : "keywords_lsl_" + mSyntaxId.asString() + ".llsd.xml"; - mFullFileSpec = gDirUtilp->getExpandedFilename(path, filename); + gAgent.removeRegionChangedCallback(mRegionChangedCallback); + mLSLKeywords = LLSD(); + mLuaKeywords = LLSD(); + mCapabilityURL = std::string(); + mSyntaxId = LLUUID(); + mFileCachePaths.clear(); } -//----------------------------------------------------------------------------- -// syntaxIdChange() -//----------------------------------------------------------------------------- -bool LLSyntaxIdLSL::syntaxIdChanged() +boost::signals2::connection LLSyntaxDefCache::addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb) +{ + return mSyntaxIDChangedSignal.connect(cb); +} + +//======================================================================== +// checkSyntaxId() +// Checks the current region for the LSLSyntaxId feature and capability, and +// if found checks the syntax ID against the one we have. If they differ, +// updates the syntax ID and returns true. Otherwise returns false. +bool LLSyntaxDefCache::updateSyntaxId() { LLViewerRegion* region = gAgent.getRegion(); @@ -82,51 +102,97 @@ bool LLSyntaxIdLSL::syntaxIdChanged() { // get and check the hash LLUUID new_syntax_id = sim_features[SYNTAX_ID_SIMULATOR_FEATURE].asUUID(); - mCapabilityURL = region->getCapability(SYNTAX_ID_CAPABILITY_NAME); + + // *Note* the syntax ID may not have changed, but the region almost certainly has. + // update the cap URL + mCapabilityURL = region->getCapability(SYNTAX_DEF_CAPABILITY_NAME); + mUseDefsCap = !mCapabilityURL.empty(); + if (!mUseDefsCap) + { + mCapabilityURL = region->getCapability(SYNTAX_ID_CAPABILITY_NAME); + } LL_DEBUGS("SyntaxLSL") << SYNTAX_ID_SIMULATOR_FEATURE << " capability URL: " << mCapabilityURL << LL_ENDL; + if (new_syntax_id != mSyntaxId) { LL_DEBUGS("SyntaxLSL") << "New SyntaxID '" << new_syntax_id << "' found." << LL_ENDL; mSyntaxId = new_syntax_id; return true; } - else - LL_DEBUGS("SyntaxLSL") << "SyntaxID matches what we have." << LL_ENDL; + + LL_DEBUGS("SyntaxLSL") << "SyntaxID has not changed. Still " << mSyntaxId << LL_ENDL; } } else { - region->setCapabilitiesReceivedCallback(boost::bind(&LLSyntaxIdLSL::handleCapsReceived, this, _1)); + region->setCapabilitiesReceivedCallback(boost::bind(&LLSyntaxDefCache::handleCapsReceived, this, _1)); LL_DEBUGS("SyntaxLSL") << "Region has not received capabilities. Waiting for caps..." << LL_ENDL; } } return false; } +void LLSyntaxDefCache::handleRegionChanged() +{ + if (updateSyntaxId()) + { + if (!checkCacheAndLoad(mSyntaxId)) + { + fetchKeywords(); + } + } +} + +void LLSyntaxDefCache::handleCapsReceived(const LLUUID& region_uuid) +{ + LLViewerRegion* current_region = gAgent.getRegion(); + + if (region_uuid.notNull() && current_region->getRegionID() == region_uuid) + { + updateSyntaxId(); + if (!checkCacheAndLoad(mSyntaxId)) + { + fetchKeywords(); + } + } +} + //----------------------------------------------------------------------------- -// fetchKeywordsFile -//----------------------------------------------------------------------------- -void LLSyntaxIdLSL::fetchKeywordsFile(const std::string& filespec) +// fetchKeywords +// Initiates a fetch of the current language definitions from the region caps. +void LLSyntaxDefCache::fetchKeywords() { - LLCoros::instance().launch("LLSyntaxIdLSL::fetchKeywordsFileCoro", - boost::bind(&LLSyntaxIdLSL::fetchKeywordsFileCoro, this, mCapabilityURL, filespec)); - LL_DEBUGS("SyntaxLSL") << "LSLSyntaxId capability URL is: " << mCapabilityURL << ". Filename to use is: '" << filespec << "'." << LL_ENDL; + if (mCapabilityURL.empty()) + { + LL_WARNS("SyntaxLSL") << "No capability URL for fetching syntax definitions." << LL_ENDL; + return; + } + if (mUseDefsCap) + { + LLCoros::instance().launch("LLSyntaxDefCache::fetchKeywordsDefsCoro", + boost::bind(&LLSyntaxDefCache::fetchKeywordsDefsCoro, this, mCapabilityURL, mSyntaxId)); + } + else + { + LLCoros::instance().launch("LLSyntaxDefCache::fetchKeywordsFileCoro", + boost::bind(&LLSyntaxDefCache::fetchKeywordsFileCoro, this, mCapabilityURL, mSyntaxId)); + } } //----------------------------------------------------------------------------- // fetchKeywordsFileCoro -//----------------------------------------------------------------------------- -void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) +// This uses the legacy language cap which only sends the LSL keywords file. +void LLSyntaxDefCache::fetchKeywordsFileCoro(std::string url, LLUUID syntax_id) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("fetchKeywordsFileCoro", httpPolicy); LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>(); - std::pair<std::set<std::string>::iterator, bool> insrt = mInflightFetches.insert(fileSpec); + auto insrt = mInflightFetches.insert(syntax_id); if (!insrt.second) { - LL_WARNS("SyntaxLSL") << "Already downloading keyword file called \"" << fileSpec << "\"." << LL_ENDL; + LL_WARNS("SyntaxLSL") << "Already downloading keyword file for syntax ID \"" << syntax_id << "\"." << LL_ENDL; return; } @@ -135,11 +201,11 @@ void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - mInflightFetches.erase(fileSpec); + mInflightFetches.erase(syntax_id); if (!status) { - LL_WARNS("SyntaxLSL") << "Failed to fetch syntax file \"" << fileSpec << "\"" << LL_ENDL; + LL_WARNS("SyntaxLSL") << "Failed to fetch syntax file for syntax ID \"" << syntax_id << "\"" << LL_ENDL; return; } @@ -147,9 +213,39 @@ void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) if (isSupportedVersion(result)) { - setKeywordsXml(result); - cacheFile(fileSpec, result); - loadKeywordsIntoLLSD(); + std::string path = buildCacheDirectoryName(syntax_id); + + if (!LLFile::exists(path)) + { + LL_DEBUGS("SyntaxLSL") << "Cache directory '" << path << "' does not exist. Attempting to create." << LL_ENDL; + if (LLFile::mkdir(path)) + { + LL_WARNS("SyntaxLSL") << "Failed to create cache directory '" << path << "'. Cannot cache syntax defs file." << LL_ENDL; + return; + } + } + + // Note that after this call the file cache will have all well known files pointing + // to the default versions, so below, where we get the path to the lua keywords + // well be loading the default version. + buildDefaultCache(); + + // The LSL keywords we just received + std::string full_path = gDirUtilp->add(path, FILENAME_INTERNAL_LSL); + if (writeCacheFile(full_path, result)) + { + mFileCachePaths.addNamePath(FILENAME_INTERNAL_LSL, full_path); + } + // We need to manually load the Lua keywords + full_path = mFileCachePaths.getPath(FILENAME_INTERNAL_LUA); + LLSD lua_defs = loadDeserializedCacheFile(full_path); + + setKeywords(result, lua_defs); + + // Shuttle this task to the main coro/worker. + LLAppViewer::instance()->postToMainCoro([this]() { + mSyntaxIDChangedSignal(); + }); } else { @@ -158,73 +254,212 @@ void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) } -//----------------------------------------------------------------------------- -// cacheFile -//----------------------------------------------------------------------------- -void LLSyntaxIdLSL::cacheFile(const std::string &fileSpec, const LLSD& content_ref) +void LLSyntaxDefCache::fetchKeywordsDefsCoro(std::string url, LLUUID syntax_id) { - std::stringstream str; - LLSDSerialize::toXML(content_ref, str); - const std::string xml = str.str(); + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter = + std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("fetchKeywordsDefsCoro", httpPolicy); + LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>(); - // save the str to disk, usually to the cache. - llofstream file(fileSpec.c_str(), std::ios_base::out); - file.write(xml.c_str(), str.str().size()); - file.close(); + static std::set<LLUUID> inflightDefsFetches; + auto insrt = inflightDefsFetches.insert(syntax_id); + //auto insrt = mInflightFetches.insert(syntax_id); + if (!insrt.second) + { + LL_WARNS("SyntaxLSL") << "Already downloading keyword defs for \"" << syntax_id << "\"." << LL_ENDL; + return; + } - LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << fileSpec << "'" << LL_ENDL; -} + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); -//----------------------------------------------------------------------------- -// initialize -//----------------------------------------------------------------------------- -void LLSyntaxIdLSL::initialize() -{ - if(mInitialized) return; - if (mSyntaxId.isNull()) + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + inflightDefsFetches.erase(syntax_id); + + if (!status) { - loadDefaultKeywordsIntoLLSD(); + LL_WARNS("SyntaxLSL") << "Failed to fetch syntax file \"" << syntax_id << "\"" << LL_ENDL; + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + return; } - else if (!mCapabilityURL.empty()) + + // Now we need to walk through the returned LLSD. It consists of a map keyed on the file name containing a binary + // blob of the actual file contents. + LLSD files = result["files"]; + // A region may omit definitions for languages it does not support. Keep + // the defaults/current definitions for any omitted file. + LLSD lsl_keywords = mLSLKeywords; + LLSD lua_keywords = mLuaKeywords; + if (files.isMap()) { - LL_DEBUGS("SyntaxLSL") << "LSL version has changed, getting appropriate file." << LL_ENDL; + std::string path = buildCacheDirectoryName(syntax_id); - // Need a full spec regardless of file source, so build it now. - buildFullFileSpec(); - if (mSyntaxId.notNull()) + if (!LLFile::exists(path)) { - if (!gDirUtilp->fileExists(mFullFileSpec)) - { // Does not exist, so fetch it from the capability - LL_DEBUGS("SyntaxLSL") << "LSL syntax not cached, attempting download." << LL_ENDL; - fetchKeywordsFile(mFullFileSpec); - } - else + LL_DEBUGS("SyntaxLSL") << "Cache directory '" << path << "' does not exist. Attempting to create." << LL_ENDL; + if (LLFile::mkdir(path)) { - LL_DEBUGS("SyntaxLSL") << "Found cached Syntax file: " << mFullFileSpec << " Loading keywords." << LL_ENDL; - loadKeywordsIntoLLSD(); + LL_WARNS("SyntaxLSL") << "Failed to create cache directory '" << path << "'. Cannot cache syntax defs file." << LL_ENDL; + return; } } - else + + buildDefaultCache(); + + for (const auto &[filename, contents] : llsd::inMap(files)) { - LL_DEBUGS("SyntaxLSL") << "LSLSyntaxId is null. Loading default values" << LL_ENDL; - loadDefaultKeywordsIntoLLSD(); + std::string full_path = gDirUtilp->add(path, filename); + + if (filename == FILENAME_INTERNAL_LSL) + { + lsl_keywords = contents; + } + else if (filename == FILENAME_INTERNAL_LUA) + { + lua_keywords = contents; + } + + if (writeCacheFile(full_path, contents)) + { + mFileCachePaths.addNamePath(filename, full_path); + } } } else { - LL_DEBUGS("SyntaxLSL") << "LSLSyntaxId capability URL is empty." << LL_ENDL; - loadDefaultKeywordsIntoLLSD(); + LL_WARNS("SyntaxLSL") << "Malformed syntax defs response, missing 'files' map." << LL_ENDL; } - mInitialized = true; + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + + setKeywords(lsl_keywords, lua_keywords); + LLAppViewer::instance()->postToMainCoro( + [this]() + { + mSyntaxIDChangedSignal(); + }); +} + +//----------------------------------------------------------------------------- +// buildCache +// Constructs the cache file paths for the given syntax ID. If the syntax ID is null, +// constructs the default cache file paths. +void LLSyntaxDefCache::buildCachePaths(const LLUUID &syntax_id) +{ + if (syntax_id.notNull()) + { // Initialize the cache files to point to the default files + buildCachePaths(LLUUID::null); + } + else + { + mFileCachePaths.clear(); + mFileCachePaths.addNamePath( + FILENAME_INTERNAL_LSL, + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, FILENAME_DEFAULT_LSL)); + mFileCachePaths.addNamePath( + FILENAME_INTERNAL_LUA, + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, FILENAME_DEFAULT_LUA)); + return; + } + + std::string cache_dir = buildCacheDirectoryName(syntax_id); + if (!LLFile::exists(cache_dir)) + { + LL_DEBUGS("SyntaxLSL") << "Cache directory '" << cache_dir << "' does not exist." << LL_ENDL; + return; + } + + auto files = gDirUtilp->getFilesInDir(cache_dir); + for (const auto &file : files) + { + mFileCachePaths.addNamePath(file, gDirUtilp->add(cache_dir, file)); + } +} + +bool LLSyntaxDefCache::writeCacheFile(const std::string &fileSpec, const LLSD& content_ref) +{ + bool binary(content_ref.isBinary()); + std::ios_base::openmode mode(binary ? (std::ios_base::out | std::ios_base::binary) + : std::ios_base::out); + std::ofstream file(fileSpec.c_str(), mode); + + if (!file.is_open()) + { + LL_WARNS("SyntaxLSL") << "Failed to open file for writing: '" << fileSpec << "'" << LL_ENDL; + return false; + } + + if (binary) + { + LL_DEBUGS("SyntaxLSL") << "Caching raw content to '" << fileSpec << "'" << LL_ENDL; + file.write((const char*)content_ref.asBinary().data(), content_ref.asBinary().size()); + } + else + { + LL_DEBUGS("SyntaxLSL") << "Caching XML content to '" << fileSpec << "'" << LL_ENDL; + LLSDSerialize::serialize(content_ref, file, LLSDSerialize::LLSD_XML, LLSDFormatter::OPTIONS_PRETTY); + } + file.close(); + + if (!file.good()) + { + LL_WARNS("SyntaxLSL") << "Failed to write content to file: '" << fileSpec << "'" << LL_ENDL; + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// checkCacheAndLoad +// Tests the local cache for the given syntax ID. If found it loads the keywords +// from the cache into LLSD and returns true. Otherwise returns false. +bool LLSyntaxDefCache::checkCacheAndLoad(const LLUUID& syntax_id) +{ + if (checkLocalCache(syntax_id)) + { + buildCachePaths(syntax_id); + loadKeywordsIntoLLSD(); + return true; + } + return false; +} + +std::string LLSyntaxDefCache::buildCacheDirectoryName(const LLUUID& syntax_id) +{ + if (syntax_id.isNull()) + { + LL_DEBUGS("SyntaxLSL") << "No SyntaxID, using app settings directory." << LL_ENDL; + return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "syntax_default"); + } + else + { + LL_DEBUGS("SyntaxLSL") << "Using cache directory for SyntaxID '" << syntax_id << "'." << LL_ENDL; + std::string cache_dir_name = "syntax_" + syntax_id.asString(); + + return gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); + } +} + +bool LLSyntaxDefCache::checkLocalCache(const LLUUID& syntax_id) const +{ + if (syntax_id.isNull()) + { // Cache check will always fail if we don't have a valid SyntaxID, so skip it in that case. + LL_DEBUGS("SyntaxLSL") << "No SyntaxID, skipping local cache check." << LL_ENDL; + return false; + } + + // Check for the existence of the cache directory for this syntax ID. If it doesn't exist, then we don't have a cached file. + std::string cache_dir = buildCacheDirectoryName(syntax_id); + return gDirUtilp->fileExists(cache_dir); } + //----------------------------------------------------------------------------- // isSupportedVersion //----------------------------------------------------------------------------- -const U32 LLSD_SYNTAX_LSL_VERSION_EXPECTED = 2; -const std::string LLSD_SYNTAX_LSL_VERSION_KEY("llsd-lsl-syntax-version"); -bool LLSyntaxIdLSL::isSupportedVersion(const LLSD& content) +bool LLSyntaxDefCache::isSupportedVersion(const LLSD& content) { bool is_valid = false; /* @@ -250,78 +485,100 @@ bool LLSyntaxIdLSL::isSupportedVersion(const LLSD& content) } //----------------------------------------------------------------------------- -// loadDefaultKeywordsIntoLLSD() -//----------------------------------------------------------------------------- -void LLSyntaxIdLSL::loadDefaultKeywordsIntoLLSD() -{ - mSyntaxId.setNull(); - buildFullFileSpec(); - loadKeywordsIntoLLSD(); -} - -//----------------------------------------------------------------------------- -// loadKeywordsFileIntoLLSD +// loadKeywordsIntoLLSD //----------------------------------------------------------------------------- /** * @brief Load xml serialized LLSD - * @desc Opens the specified filespec and attempts to deserializes the - * contained data to the specified LLSD object. indicate success/failure with - * sLoaded/sLoadFailed members. + * @desc Open the internal lsl keywords files and deserialize them into the correct + * members. */ -void LLSyntaxIdLSL::loadKeywordsIntoLLSD() +void LLSyntaxDefCache::loadKeywordsIntoLLSD() { - LLSD content; - llifstream file; - file.open(mFullFileSpec.c_str()); - if (file.is_open()) + for (auto& filename : MEMCACHED_LLSD) { - if (LLSDSerialize::fromXML(content, file) != LLSDParser::PARSE_FAILURE) + // Note, in the case of the legacy language cap (it only delivers the LSL keywords file) + // The mFileCachePaths will have been initialized in such a way that the Lua keywords + // point to the default file. + std::string full_path = mFileCachePaths.getPath(filename); + if (!full_path.empty()) { - if (isSupportedVersion(content)) + LLSD content = loadDeserializedCacheFile(full_path); + if (!content.isUndefined() && isSupportedVersion(content)) { - LL_DEBUGS("SyntaxLSL") << "Deserialized: " << mFullFileSpec << LL_ENDL; + LL_DEBUGS("SyntaxLSL") << "Deserialized cached file: " << full_path << LL_ENDL; + if (filename == FILENAME_INTERNAL_LSL) + { + mLSLKeywords = content; + } + else if (filename == FILENAME_INTERNAL_LUA) + { + mLuaKeywords = content; + } } else { - LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL; + LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file " << full_path << "." << LL_ENDL; } } } - else - { - LL_WARNS("SyntaxLSL") << "Failed to open: " << mFullFileSpec << LL_ENDL; - } - mKeywordsXml = content; + mSyntaxIDChangedSignal(); } -bool LLSyntaxIdLSL::keywordFetchInProgress() +std::vector<std::string> LLSyntaxDefCache::getCacheFileNames() const { - return !mInflightFetches.empty(); + std::vector<std::string> names; + for (const auto& [name, path] : mFileCachePaths) + { + names.push_back(name); + } + return names; } -void LLSyntaxIdLSL::handleRegionChanged() +LLSD LLSyntaxDefCache::loadDeserializedCacheFile(const std::string& file_path) { - if (syntaxIdChanged()) + std::ifstream file(file_path.c_str()); + if (file.good()) + { + LLSD content; + if (LLSDSerialize::deserialize(content, file, -1)) + { + return content; + } + } + else { - buildFullFileSpec(); - fetchKeywordsFile(mFullFileSpec); - mInitialized = false; + LL_WARNS("SyntaxLSL") << "Failed to open cached file: " << file_path << LL_ENDL; } + return LLSD(); } -void LLSyntaxIdLSL::handleCapsReceived(const LLUUID& region_uuid) +std::string LLSyntaxDefCache::loadCacheFile(const std::string& name) const { - LLViewerRegion* current_region = gAgent.getRegion(); - - if (region_uuid.notNull() - && current_region->getRegionID() == region_uuid) + std::string full_path = mFileCachePaths.getPath(name); + if (!full_path.empty()) { - syntaxIdChanged(); + std::ifstream file(full_path.c_str()); + if (file.good()) + { + std::ostringstream ss; + ss << file.rdbuf(); + return (file.good()) ? ss.str() : std::string(); + } + else + { + LL_WARNS("SyntaxLSL") << "Failed to open cached file: " << full_path << LL_ENDL; + } } + return std::string(); } -boost::signals2::connection LLSyntaxIdLSL::addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb) +LLSD LLSyntaxDefCache::loadCacheFileAsLLSD(const std::string& name) const { - return mSyntaxIDChangedSignal.connect(cb); + std::string full_path = mFileCachePaths.getPath(name); + if (!full_path.empty()) + { + return loadDeserializedCacheFile(full_path); + } + return LLSD(); } |
