diff options
Diffstat (limited to 'indra/newview/llsyntaxid.cpp')
-rw-r--r-- | indra/newview/llsyntaxid.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp new file mode 100644 index 0000000000..94226b82b1 --- /dev/null +++ b/indra/newview/llsyntaxid.cpp @@ -0,0 +1,297 @@ +/** + * @file LLSyntaxId + * @author Ima Mechanique + * @brief Handles downloading, saving, and checking of LSL keyword/syntax files + * for each region. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llhttpclient.h" +#include "llsdserialize.h" +#include "llsyntaxid.h" + + +//----------------------------------------------------------------------------- +// fetchKeywordsFileResponder +//----------------------------------------------------------------------------- +fetchKeywordsFileResponder::fetchKeywordsFileResponder(std::string filespec) +{ + mFileSpec = filespec; + LL_INFOS("SyntaxLSL") + << "Instantiating with file saving to: '" << filespec << "'" + << LL_ENDL; +} + +void fetchKeywordsFileResponder::errorWithContent(U32 status, + const std::string& reason, + const LLSD& content) +{ + LL_ERRS("SyntaxLSL") + << "fetchKeywordsFileResponder error [status:" + << status << "]: " << content + << LL_ENDL; +} + +void fetchKeywordsFileResponder::result(const LLSD& content_ref) +{ + LLSyntaxIdLSL::setKeywordsXml(content_ref); + + std::stringstream str; + LLSDSerialize::toPrettyXML(content_ref, str); + const std::string xml = str.str(); + + // save the str to disc, usually to the cache. + llofstream file(mFileSpec, std::ios_base::out); + file.write(xml.c_str(), str.str().size()); + file.close(); + + LL_INFOS("SyntaxLSL") + << "Syntax file received, saving as: '" << mFileSpec << "'" << LL_ENDL; +} + + +//----------------------------------------------------------------------------- +// LLSyntaxIdLSL +//----------------------------------------------------------------------------- +/** + * @brief LLSyntaxIdLSL constructor + */ +LLSyntaxIdLSL::LLSyntaxIdLSL() : + // Move these to signature? + mFileNameDefault("keywords_lsl_default.xml"), + mSimulatorFeature("LSLSyntaxId"), + mCapabilityName("LSLSyntax"), + mCapabilityURL(""), + mFilePath(LL_PATH_APP_SETTINGS) +{ + mSyntaxIdCurrent = LLUUID(); + mFileNameCurrent = mFileNameDefault; +} + +LLSD LLSyntaxIdLSL::sKeywordsXml; + +std::string LLSyntaxIdLSL::buildFileNameNew() +{ + mFileNameNew = mSyntaxIdNew.isNull() ? mFileNameDefault : "keywords_lsl_" + gLastVersionChannel + "_" + mSyntaxIdNew.asString() + ".llsd.xml"; + return mFileNameNew; +} + +std::string LLSyntaxIdLSL::buildFullFileSpec() +{ + ELLPath path = mSyntaxIdNew.isNull() ? LL_PATH_APP_SETTINGS : LL_PATH_CACHE; + buildFileNameNew(); + mFullFileSpec = gDirUtilp->getExpandedFilename(path, mFileNameNew); + return mFullFileSpec; +} + +//----------------------------------------------------------------------------- +// checkSyntaxIdChange() +//----------------------------------------------------------------------------- +bool LLSyntaxIdLSL::checkSyntaxIdChanged() +{ + bool changed = false; + LLViewerRegion* region = gAgent.getRegion(); + + if (region) + { + if (!region->capabilitiesReceived()) + { // Shouldn't be possible, but experience shows that it may be needed. + LL_WARNS("SyntaxLSL") + << "Region '" << region->getName() + << "' has not received capabilities yet! Cannot process SyntaxId." + << LL_ENDL; + } + else + { + LLSD simFeatures; + std::string message; + region->getSimulatorFeatures(simFeatures); + + // get and check the hash + if (simFeatures.has("LSLSyntaxId")) + { + mSyntaxIdNew = simFeatures["LSLSyntaxId"].asUUID(); + mCapabilityURL = region->getCapability(mCapabilityName); + if (mSyntaxIdCurrent != mSyntaxIdNew) + { + message = "' it has LSLSyntaxId capability, and the new hash is '" + + mSyntaxIdNew.asString() + "'"; + + changed = true; + } + else + { + message = "' it has the same LSLSyntaxId! Leaving hash as '" + + mSyntaxIdCurrent.asString() + "'"; + } + } + else + { + if ( mSyntaxIdCurrent.isNull() ) + { + message = " it does not have LSLSyntaxId capability, remaining with default keywords file!"; + } + else + { + // The hash is set to NULL_KEY to indicate use of default keywords file + mSyntaxIdNew = LLUUID(); + message = " it does not have LSLSyntaxId capability, using default keywords file!"; + changed = true; + } + } + LL_INFOS("SyntaxLSL") + << "Region is '" << region->getName() << message << LL_ENDL; + } + } + return changed; +} + +//----------------------------------------------------------------------------- +// fetchKeywordsFile +//----------------------------------------------------------------------------- +void LLSyntaxIdLSL::fetchKeywordsFile() +{ + if ( !mCapabilityURL.empty() ) + { + LLHTTPClient::get(mCapabilityURL, + new fetchKeywordsFileResponder(mFullFileSpec), + LLSD(), 30.f + ); + LL_INFOS("SyntaxLSL") + << "LSLSyntaxId capability URL is: " << mCapabilityURL + << ". Filename to use is: '" << mFullFileSpec << "'." + << LL_ENDL; + } + else + { + LL_ERRS("SyntaxLSL") + << "LSLSyntaxId capability URL is empty!!" << LL_ENDL; + } +} + +void LLSyntaxIdLSL::initialise() +{ + mFileNameNew = mFileNameCurrent; + mSyntaxIdNew = mSyntaxIdCurrent; + if (checkSyntaxIdChanged()) + { + LL_INFOS("SyntaxLSL") + << "LSL version has changed, getting appropriate file." + << LL_ENDL; + + // Need a full spec regardless of file source, so build it now. + buildFullFileSpec(); + if ( !mSyntaxIdNew.isNull() ) + { + if ( !gDirUtilp->fileExists(mFullFileSpec) ) + { // Does not exist, so fetch it from the capability + fetchKeywordsFile(); + LL_INFOS("SyntaxLSL") + << "File is not cached, we will try to download it!" + << LL_ENDL; + } + else + { + LL_INFOS("SyntaxLSL") + << "File is cached, no need to download!" + << LL_ENDL; + loadKeywordsIntoLLSD(); + } + } + else + { // Need to open the default + loadDefaultKeywordsIntoLLSD("LSLSyntaxId is null so we will use the default file!"); + } + } + else if (sKeywordsXml.isDefined()) + { + LL_INFOS("SyntaxLSL") + << "No change to Syntax! Nothing to see. Move along now!" + << LL_ENDL; + } + else + { // Need to open the default + loadDefaultKeywordsIntoLLSD("LSLSyntaxId is null so we will use the default file!"); + } + + mFileNameCurrent = mFileNameNew; + mSyntaxIdCurrent = mSyntaxIdNew; +} + +//----------------------------------------------------------------------------- +// loadDefaultKeywordsIntoLLSD() +//----------------------------------------------------------------------------- +void LLSyntaxIdLSL::loadDefaultKeywordsIntoLLSD(const std::string message) +{ + LL_INFOS("SyntaxLSL") << message << LL_ENDL; + mSyntaxIdNew = LLUUID(); + buildFullFileSpec(); + loadKeywordsIntoLLSD(); +} + +//----------------------------------------------------------------------------- +// loadKeywordsFileIntoLLSD +//----------------------------------------------------------------------------- +/** + * @brief Load xml serialised LLSD + * @desc Opens the specified filespec and attempts to deserialise the + * contained data to the specified LLSD object. + * @return Returns boolean true/false indicating success or failure. + */ +bool LLSyntaxIdLSL::loadKeywordsIntoLLSD() +{ + LL_INFOS("SyntaxLSL") + << "Trying to open cached or default keyword file ;-)" + << LL_ENDL; + + bool loaded = false; + LLSD content; + llifstream file; + file.open(mFullFileSpec); + if (file.is_open()) + { + loaded = (bool)LLSDSerialize::fromXML(content, file); + if (!loaded) + { + LL_ERRS("SyntaxLSL") << "Unable to deserialise file: " << mFullFileSpec << LL_ENDL; + + // Is this the right thing to do, or should we leave the old content + // even if it isn't entirely accurate anymore? + sKeywordsXml = LLSD().emptyMap(); + } + else + { + sKeywordsXml = content; + LL_INFOS("SyntaxLSL") << "Deserialised file: " << mFullFileSpec << LL_ENDL; + } + } + else + { + LL_ERRS("SyntaxLSL") << "Unable to open file: " << mFullFileSpec << LL_ENDL; + } + return loaded; +} |