summaryrefslogtreecommitdiff
path: root/indra/newview/llsyntaxid.cpp
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2026-09-01 18:35:23 +0800
committerErik Kundiman <erik@megapahit.org>2026-09-04 21:58:53 +0800
commit00bb3bb6f07660bd914d29a1389342bb3060d254 (patch)
tree431f574922494d2201718f13085f17bc6bd7fb42 /indra/newview/llsyntaxid.cpp
parenta8636720129952c10cf49ab80da21bf8b340b96c (diff)
parent4ef9f8f14b35ed388c294d53767a0dca0e890924 (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.cpp511
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();
}