diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llcompilequeue.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llcompilequeue.cpp')
-rw-r--r-- | indra/newview/llcompilequeue.cpp | 1655 |
1 files changed, 826 insertions, 829 deletions
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 19b2ce77c5..906c61c535 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -1,829 +1,826 @@ -/** - * @file llcompilequeue.cpp - * @brief LLCompileQueueData class implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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$ - */ - -/** - * - * Implementation of the script queue which keeps an array of object - * UUIDs and manipulates all of the scripts on each of them. - * - */ - - -#include "llviewerprecompiledheaders.h" - -#include "llcompilequeue.h" - -#include "llagent.h" -#include "llchat.h" -#include "llfloaterreg.h" -#include "llviewerwindow.h" -#include "llviewerobject.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llviewercontrol.h" -#include "llviewerobject.h" -#include "llviewerregion.h" -#include "llresmgr.h" - -#include "llbutton.h" -#include "lldir.h" -#include "llnotificationsutil.h" -#include "llviewerstats.h" -#include "llfilesystem.h" -#include "lluictrlfactory.h" -#include "lltrans.h" - -#include "llselectmgr.h" -#include "llexperiencecache.h" - -#include "llviewerassetupload.h" -#include "llcorehttputil.h" - -namespace -{ - - const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue"); - - // ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged - // callback mechanism and the LLEventPump coroutine architecture allowing the - // coroutine to wait for the inventory event. - class ObjectInventoryFetcher: public LLVOInventoryListener - { - public: - typedef std::shared_ptr<ObjectInventoryFetcher> ptr_t; - - ObjectInventoryFetcher(LLEventPump &pump, LLViewerObject* object, void* user_data) : - mPump(pump), - LLVOInventoryListener() - { - registerVOInventoryListener(object, this); - } - - virtual void inventoryChanged(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void* user_data); - - void fetchInventory() - { - requestVOInventory(); - } - - const LLInventoryObject::object_list_t & getInventoryList() const { return mInventoryList; } - - private: - LLInventoryObject::object_list_t mInventoryList; - LLEventPump & mPump; - }; - - class HandleScriptUserData - { - public: - HandleScriptUserData(const std::string &pumpname) : - mPumpname(pumpname) - { } - - const std::string &getPumpName() const { return mPumpname; } - - private: - std::string mPumpname; - }; - - -} - -// *NOTE$: A minor specialization of LLScriptAssetUpload, it does not require a buffer -// (and does not save a buffer to the cache) and it finds the compile queue window and -// displays a compiling message. -class LLQueuedScriptAssetUpload : public LLScriptAssetUpload -{ -public: - LLQueuedScriptAssetUpload(LLUUID taskId, LLUUID itemId, LLUUID assetId, TargetType_t targetType, - bool isRunning, std::string scriptName, LLUUID queueId, LLUUID exerienceId, taskUploadFinish_f finish) : - LLScriptAssetUpload(taskId, itemId, targetType, isRunning, - exerienceId, std::string(), finish, nullptr), - mScriptName(scriptName), - mQueueId(queueId) - { - setAssetId(assetId); - } - - virtual LLSD prepareUpload() - { - /* *NOTE$: The parent class (LLScriptAssetUpload will attempt to save - * the script buffer into to the cache. Since the resource is already in - * the cache we don't want to do that. Just put a compiling message in - * the window and move on - */ - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId)); - if (queue) - { - std::string message = std::string("Compiling \"") + getScriptName() + std::string("\"..."); - - queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM); - } - - return LLSDMap("success", LLSD::Boolean(true)); - } - - - std::string getScriptName() const { return mScriptName; } - -private: - void setScriptName(const std::string &scriptName) { mScriptName = scriptName; } - - LLUUID mQueueId; - std::string mScriptName; -}; - -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - -struct LLScriptQueueData -{ - LLUUID mQueueID; - LLUUID mTaskId; - LLPointer<LLInventoryItem> mItem; - LLHost mHost; - LLUUID mExperienceId; - std::string mExperiencename; - LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item) : - mQueueID(q_id), mTaskId(task_id), mItem(new LLInventoryItem(item)) {} - -}; - -///---------------------------------------------------------------------------- -/// Class LLFloaterScriptQueue -///---------------------------------------------------------------------------- - -// Default constructor -LLFloaterScriptQueue::LLFloaterScriptQueue(const LLSD& key) : - LLFloater(key), - mDone(false), - mMono(false) -{ - -} - -// Destroys the object -LLFloaterScriptQueue::~LLFloaterScriptQueue() -{ -} - -bool LLFloaterScriptQueue::postBuild() -{ - childSetAction("close",onCloseBtn,this); - getChildView("close")->setEnabled(false); - setVisible(true); - return true; -} - -// static -void LLFloaterScriptQueue::onCloseBtn(void* user_data) -{ - LLFloaterScriptQueue* self = (LLFloaterScriptQueue*)user_data; - self->closeFloater(); -} - -void LLFloaterScriptQueue::addObject(const LLUUID& id, std::string name) -{ - ObjectData obj = { id, name }; - mObjectList.push_back(obj); -} - -bool LLFloaterScriptQueue::start() -{ - std::string buffer; - - LLStringUtil::format_map_t args; - args["[START]"] = mStartString; - args["[COUNT]"] = llformat ("%d", mObjectList.size()); - buffer = getString ("Starting", args); - - getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM); - - return startQueue(); -} - -void LLFloaterScriptQueue::addProcessingMessage(const std::string &message, const LLSD &args) -{ - std::string buffer(LLTrans::getString(message, args)); - - getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM); -} - -void LLFloaterScriptQueue::addStringMessage(const std::string &message) -{ - getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM); -} - - -bool LLFloaterScriptQueue::isDone() const -{ - return (mCurrentObjectID.isNull() && (mObjectList.size() == 0)); -} - -///---------------------------------------------------------------------------- -/// Class LLFloaterCompileQueue -///---------------------------------------------------------------------------- -LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key) - : LLFloaterScriptQueue(key) -{ - setTitle(LLTrans::getString("CompileQueueTitle")); - setStartString(LLTrans::getString("CompileQueueStart")); - -} - -LLFloaterCompileQueue::~LLFloaterCompileQueue() -{ -} - -void LLFloaterCompileQueue::experienceIdsReceived( const LLSD& content ) -{ - for(LLSD::array_const_iterator it = content.beginArray(); it != content.endArray(); ++it) - { - mExperienceIds.insert(it->asUUID()); - } -} - -bool LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const -{ - return mExperienceIds.find(id) != mExperienceIds.end(); -} - -// //Attempt to record this asset ID. If it can not be inserted into the set -// //then it has already been processed so return false. - -void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD &expresult) -{ - LLEventPumps::instance().post(pumpName, expresult); -} - -// *TODO: handleSCriptRetrieval is passed into the cache via a legacy C function pointer -// future project would be to convert these to C++ callables (std::function<>) so that -// we can use bind and remove the userData parameter. -// -void LLFloaterCompileQueue::handleScriptRetrieval(const LLUUID& assetId, - LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus) -{ - LLSD result(LLSD::emptyMap()); - - result["asset_id"] = assetId; - if (status) - { - result["error"] = status; - - if (status == LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE) - { - result["message"] = LLTrans::getString("CompileQueueProblemDownloading") + (":"); - result["alert"] = LLTrans::getString("CompileQueueScriptNotFound"); - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) - { - result["message"] = LLTrans::getString("CompileQueueInsufficientPermFor") + (":"); - result["alert"] = LLTrans::getString("CompileQueueInsufficientPermDownload"); - } - else - { - result["message"] = LLTrans::getString("CompileQueueUnknownFailure"); - } - } - - LLEventPumps::instance().post(((HandleScriptUserData *)userData)->getPumpName(), result); - -} - -/*static*/ -void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID parent) -{ - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", parent); - if (!queue) - return; - - queue->experienceIdsReceived(result["experience_ids"]); - - // getDerived handle gets a handle that can be resolved to a parent class of the derived object. - LLHandle<LLFloaterScriptQueue> hFloater(queue->getDerivedHandle<LLFloaterScriptQueue>()); - - // note subtle difference here: getDerivedHandle in this case is for an LLFloaterCompileQueue - fnQueueAction_t fn = boost::bind(LLFloaterCompileQueue::processScript, - queue->getDerivedHandle<LLFloaterCompileQueue>(), _1, _2, _3); - - - LLCoros::instance().launch("ScriptQueueCompile", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, - queue->mStartString, - hFloater, - queue->mObjectList, - fn)); - -} - -/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro. -/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception. -bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloater, - const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump) -{ - if (LLApp::isExiting()) - { - // Reply from coroutine came on shutdown - // We are quiting, don't start any more coroutines! - return true; - } - - LLSD result; - LLCheckedHandle<LLFloaterCompileQueue> floater(hfloater); - // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. - // which is caught in objectScriptProcessingQueueCoro - bool monocompile = floater->mMono; - F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout"); - - - // Initial test to see if we can (or should) attempt to compile the script. - LLInventoryItem *item = dynamic_cast<LLInventoryItem *>(inventory); - - if (!item) - { - LL_WARNS("SCRIPTQ") << "item retrieved is not an LLInventoryItem." << LL_ENDL; - return true; - } - - if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) || - !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID())) - { - std::string buffer = "Skipping: " + item->getName() + "(Permissions)"; - floater->addStringMessage(buffer); - return true; - } - - // Attempt to retrieve the experience - LLUUID experienceId; - { - LLExperienceCache::instance().fetchAssociatedExperience(inventory->getParentUUID(), inventory->getUUID(), - boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1)); - - result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, - LLSDMap("timeout", LLSD::Boolean(true))); - - floater.check(); - - if (result.has("timeout")) - { // A timeout filed in the result will always be true if present. - LLStringUtil::format_map_t args; - args["[OBJECT_NAME]"] = inventory->getName(); - std::string buffer = floater->getString("Timeout", args); - floater->addStringMessage(buffer); - return true; - } - - if (result.has(LLExperienceCache::EXPERIENCE_ID)) - { - experienceId = result[LLExperienceCache::EXPERIENCE_ID].asUUID(); - if (!floater->hasExperience(experienceId)) - { - floater->addProcessingMessage("CompileNoExperiencePerm", - LLSDMap("SCRIPT", inventory->getName()) - ("EXPERIENCE", result[LLExperienceCache::NAME].asString())); - return true; - } - } - - } - - if (!gAssetStorage) - { - // viewer likely is shutting down - return true; - } - - { - HandleScriptUserData userData(pump.getName()); - - - // request the asset - gAssetStorage->getInvItemAsset(LLHost(), - gAgent.getID(), - gAgent.getSessionID(), - item->getPermissions().getOwner(), - object->getID(), - item->getUUID(), - item->getAssetUUID(), - item->getType(), - &LLFloaterCompileQueue::handleScriptRetrieval, - &userData); - - result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, - LLSDMap("timeout", LLSD::Boolean(true))); - } - - if (result.has("timeout")) - { // A timeout filed in the result will always be true if present. - LLStringUtil::format_map_t args; - args["[OBJECT_NAME]"] = inventory->getName(); - std::string buffer = floater->getString("Timeout", args); - floater->addStringMessage(buffer); - return true; - } - - if (result.has("error")) - { - LL_WARNS("SCRIPTQ") << "Inventory fetch returned with error. Code: " << result["error"].asString() << LL_ENDL; - std::string buffer = result["message"].asString() + " " + inventory->getName(); - floater->addStringMessage(buffer); - - if (result.has("alert")) - { - LLSD args; - args["MESSAGE"] = result["alert"].asString(); - LLNotificationsUtil::add("SystemMessage", args); - } - return true; - } - - LLUUID assetId = result["asset_id"]; - - std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - - { - LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(object->getID(), - inventory->getUUID(), - assetId, - monocompile ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, - true, - inventory->getName(), - LLUUID(), - experienceId, - boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _4))); - - LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); - } - - result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true))); - - floater.check(); - - if (result.has("timeout")) - { // A timeout filed in the result will always be true if present. - LLStringUtil::format_map_t args; - args["[OBJECT_NAME]"] = inventory->getName(); - std::string buffer = floater->getString("Timeout", args); - floater->addStringMessage(buffer); - return true; - } - - // Bytecode save completed - if (result["compiled"]) - { - std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" succeeded"); - - floater->addStringMessage(buffer); - LL_INFOS() << buffer << LL_ENDL; - } - else - { - LLSD compile_errors = result["errors"]; - std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" failed:"); - floater->addStringMessage(buffer); - for (LLSD::array_const_iterator line = compile_errors.beginArray(); - line < compile_errors.endArray(); line++) - { - std::string str = line->asString(); - str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); - - floater->addStringMessage(str); - } - LL_INFOS() << result["errors"] << LL_ENDL; - } - - return true; -} - -bool LLFloaterCompileQueue::startQueue() -{ - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string lookup_url = region->getCapability("GetCreatorExperiences"); - if (!lookup_url.empty()) - { - LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success = - boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, _1, getKey().asUUID()); - - LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t failure = - boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, LLSD(), getKey().asUUID()); - - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url, - success, failure); - return true; - } - } - - return true; -} - - -///---------------------------------------------------------------------------- -/// Class LLFloaterResetQueue -///---------------------------------------------------------------------------- - -LLFloaterResetQueue::LLFloaterResetQueue(const LLSD& key) - : LLFloaterScriptQueue(key) -{ - setTitle(LLTrans::getString("ResetQueueTitle")); - setStartString(LLTrans::getString("ResetQueueStart")); -} - -LLFloaterResetQueue::~LLFloaterResetQueue() -{ -} - -/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro. -/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception. -bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater, - const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump) -{ - LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater); - // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. - // which is caught in objectScriptProcessingQueueCoro - - std::string buffer; - buffer = floater->getString("Resetting") + (": ") + inventory->getName(); - floater->addStringMessage(buffer); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ScriptReset); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); - msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID()); - msg->sendReliable(object->getRegion()->getHost()); - - return true; -} - -bool LLFloaterResetQueue::startQueue() -{ - // Bind the resetObjectScripts method into a QueueAction function and pass it - // into the object queue processing coroutine. - fnQueueAction_t fn = boost::bind(LLFloaterResetQueue::resetObjectScripts, - getDerivedHandle<LLFloaterScriptQueue>(), _1, _2, _3); - - LLCoros::instance().launch("ScriptResetQueue", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, - mStartString, - getDerivedHandle<LLFloaterScriptQueue>(), - mObjectList, - fn)); - - return true; -} - -///---------------------------------------------------------------------------- -/// Class LLFloaterRunQueue -///---------------------------------------------------------------------------- - -LLFloaterRunQueue::LLFloaterRunQueue(const LLSD& key) - : LLFloaterScriptQueue(key) -{ - setTitle(LLTrans::getString("RunQueueTitle")); - setStartString(LLTrans::getString("RunQueueStart")); -} - -LLFloaterRunQueue::~LLFloaterRunQueue() -{ -} - -/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro. -/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception. -bool LLFloaterRunQueue::runObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater, - const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump) -{ - LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater); - // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. - // which is caught in objectScriptProcessingQueueCoro - - std::string buffer; - buffer = floater->getString("Running") + (": ") + inventory->getName(); - floater->addStringMessage(buffer); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SetScriptRunning); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); - msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID()); - msg->addBOOLFast(_PREHASH_Running, true); - msg->sendReliable(object->getRegion()->getHost()); - - return true; -} - -bool LLFloaterRunQueue::startQueue() -{ - LLHandle<LLFloaterScriptQueue> hFloater(getDerivedHandle<LLFloaterScriptQueue>()); - fnQueueAction_t fn = boost::bind(LLFloaterRunQueue::runObjectScripts, hFloater, _1, _2, _3); - - LLCoros::instance().launch("ScriptRunQueue", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, - mStartString, - hFloater, - mObjectList, - fn)); - - return true; -} - - -///---------------------------------------------------------------------------- -/// Class LLFloaterNotRunQueue -///---------------------------------------------------------------------------- - -LLFloaterNotRunQueue::LLFloaterNotRunQueue(const LLSD& key) - : LLFloaterScriptQueue(key) -{ - setTitle(LLTrans::getString("NotRunQueueTitle")); - setStartString(LLTrans::getString("NotRunQueueStart")); -} - -LLFloaterNotRunQueue::~LLFloaterNotRunQueue() -{ -} - -/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro. -/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception. -bool LLFloaterNotRunQueue::stopObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater, - const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump) -{ - LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater); - // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. - // which is caught in objectScriptProcessingQueueCoro - - std::string buffer; - buffer = floater->getString("NotRunning") + (": ") + inventory->getName(); - floater->addStringMessage(buffer); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SetScriptRunning); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); - msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID()); - msg->addBOOLFast(_PREHASH_Running, false); - msg->sendReliable(object->getRegion()->getHost()); - - return true; -} - -bool LLFloaterNotRunQueue::startQueue() -{ - LLHandle<LLFloaterScriptQueue> hFloater(getDerivedHandle<LLFloaterScriptQueue>()); - - fnQueueAction_t fn = boost::bind(&LLFloaterNotRunQueue::stopObjectScripts, hFloater, _1, _2, _3); - LLCoros::instance().launch("ScriptQueueNotRun", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro, - mStartString, - hFloater, - mObjectList, - fn)); - - return true; -} - -///---------------------------------------------------------------------------- -/// Local function definitions -///---------------------------------------------------------------------------- -void ObjectInventoryFetcher::inventoryChanged(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data) -{ - mInventoryList.clear(); - mInventoryList.assign(inventory->begin(), inventory->end()); - - mPump.post(LLSDMap("changed", LLSD::Boolean(true))); - -} - -void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, LLHandle<LLFloaterScriptQueue> hfloater, - object_data_list_t objectList, fnQueueAction_t func) -{ - LLCoros::set_consuming(true); - LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater); - // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. - // This is expected if the dialog closes. - LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true); - F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout"); - - - try - { - for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj) - { - bool firstForObject = true; - LLUUID object_id = (*itObj).mObjectId; - LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL; - - LLPointer<LLViewerObject> obj = gObjectList.findObject(object_id); - LLInventoryObject::object_list_t inventory; - if (obj) - { - ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL)); - - fetcher->fetchInventory(); - - LLStringUtil::format_map_t args; - args["[OBJECT_NAME]"] = (*itObj).mObjectName; - floater->addStringMessage(floater->getString("LoadingObjInv", args)); - - LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout, - LLSDMap("timeout", LLSD::Boolean(true))); - - if (result.has("timeout")) - { // A timeout filed in the result will always be true if present. - LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() << - ". Skipping to next object." << LL_ENDL; - - LLStringUtil::format_map_t args; - args["[OBJECT_NAME]"] = (*itObj).mObjectName; - floater->addStringMessage(floater->getString("Timeout", args)); - - continue; - } - - inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end()); - } - else - { - LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id << - ". Skipping to next." << LL_ENDL; - continue; - } - - // TODO: Get the name of the object we are looking at here so that we can display it below. - //std::string objName = (dynamic_cast<LLInventoryObject *>(obj.get()))->getName(); - LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL; - - for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin(); - itInv != inventory.end(); ++itInv) - { - floater.check(); - - // note, we have a smart pointer to the obj above... but if we didn't we'd check that - // it still exists here. - - if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT)) - { - LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL; - if (firstForObject) - { - //floater->addStringMessage(objName + ":"); - firstForObject = false; - } - - if (!func(obj, (*itInv), maildrop)) - { - continue; - } - } - - // no other explicit suspension point in this loop. func(...) MIGHT suspend - // but offers no guarantee of doing so. - llcoro::suspend(); - } - floater.check(); - } - - floater->addStringMessage("Done"); - floater->getChildView("close")->setEnabled(true); - } - catch (LLCheckedHandleBase::Stale &) - { - // This is expected. It means that floater has been closed before - // processing was completed. - LL_DEBUGS("SCRIPTQ") << "LLExeceptionStaleHandle caught! Floater has most likely been closed." << LL_ENDL; - } -} +/**
+ * @file llcompilequeue.cpp
+ * @brief LLCompileQueueData class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+/**
+ *
+ * Implementation of the script queue which keeps an array of object
+ * UUIDs and manipulates all of the scripts on each of them.
+ *
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llcompilequeue.h"
+
+#include "llagent.h"
+#include "llchat.h"
+#include "llfloaterreg.h"
+#include "llviewerwindow.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewercontrol.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+#include "llresmgr.h"
+
+#include "llbutton.h"
+#include "lldir.h"
+#include "llnotificationsutil.h"
+#include "llviewerstats.h"
+#include "llfilesystem.h"
+#include "lluictrlfactory.h"
+#include "lltrans.h"
+
+#include "llselectmgr.h"
+#include "llexperiencecache.h"
+
+#include "llviewerassetupload.h"
+#include "llcorehttputil.h"
+
+namespace
+{
+
+ const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue");
+ const F32 QUEUE_INVENTORY_FETCH_TIMEOUT = 300.f;
+
+ // ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged
+ // callback mechanism and the LLEventPump coroutine architecture allowing the
+ // coroutine to wait for the inventory event.
+ class ObjectInventoryFetcher: public LLVOInventoryListener
+ {
+ public:
+ typedef std::shared_ptr<ObjectInventoryFetcher> ptr_t;
+
+ ObjectInventoryFetcher(LLEventPump &pump, LLViewerObject* object, void* user_data) :
+ mPump(pump),
+ LLVOInventoryListener()
+ {
+ registerVOInventoryListener(object, this);
+ }
+
+ virtual void inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data);
+
+ void fetchInventory()
+ {
+ requestVOInventory();
+ }
+
+ const LLInventoryObject::object_list_t & getInventoryList() const { return mInventoryList; }
+
+ private:
+ LLInventoryObject::object_list_t mInventoryList;
+ LLEventPump & mPump;
+ };
+
+ class HandleScriptUserData
+ {
+ public:
+ HandleScriptUserData(const std::string &pumpname) :
+ mPumpname(pumpname)
+ { }
+
+ const std::string &getPumpName() const { return mPumpname; }
+
+ private:
+ std::string mPumpname;
+ };
+
+
+}
+
+// *NOTE$: A minor specialization of LLScriptAssetUpload, it does not require a buffer
+// (and does not save a buffer to the cache) and it finds the compile queue window and
+// displays a compiling message.
+class LLQueuedScriptAssetUpload : public LLScriptAssetUpload
+{
+public:
+ LLQueuedScriptAssetUpload(LLUUID taskId, LLUUID itemId, LLUUID assetId, TargetType_t targetType,
+ bool isRunning, std::string scriptName, LLUUID queueId, LLUUID exerienceId, taskUploadFinish_f finish) :
+ LLScriptAssetUpload(taskId, itemId, targetType, isRunning,
+ exerienceId, std::string(), finish, nullptr),
+ mScriptName(scriptName),
+ mQueueId(queueId)
+ {
+ setAssetId(assetId);
+ }
+
+ virtual LLSD prepareUpload()
+ {
+ /* *NOTE$: The parent class (LLScriptAssetUpload will attempt to save
+ * the script buffer into to the cache. Since the resource is already in
+ * the cache we don't want to do that. Just put a compiling message in
+ * the window and move on
+ */
+ LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId));
+ if (queue)
+ {
+ std::string message = std::string("Compiling \"") + getScriptName() + std::string("\"...");
+
+ queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
+ }
+
+ return LLSDMap("success", LLSD::Boolean(true));
+ }
+
+
+ std::string getScriptName() const { return mScriptName; }
+
+private:
+ void setScriptName(const std::string &scriptName) { mScriptName = scriptName; }
+
+ LLUUID mQueueId;
+ std::string mScriptName;
+};
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+struct LLScriptQueueData
+{
+ LLUUID mQueueID;
+ LLUUID mTaskId;
+ LLPointer<LLInventoryItem> mItem;
+ LLHost mHost;
+ LLUUID mExperienceId;
+ std::string mExperiencename;
+ LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item) :
+ mQueueID(q_id), mTaskId(task_id), mItem(new LLInventoryItem(item)) {}
+
+};
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterScriptQueue
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLFloaterScriptQueue::LLFloaterScriptQueue(const LLSD& key) :
+ LLFloater(key),
+ mDone(false),
+ mMono(false)
+{
+
+}
+
+// Destroys the object
+LLFloaterScriptQueue::~LLFloaterScriptQueue()
+{
+}
+
+bool LLFloaterScriptQueue::postBuild()
+{
+ childSetAction("close",onCloseBtn,this);
+ getChildView("close")->setEnabled(false);
+ setVisible(true);
+ return true;
+}
+
+// static
+void LLFloaterScriptQueue::onCloseBtn(void* user_data)
+{
+ LLFloaterScriptQueue* self = (LLFloaterScriptQueue*)user_data;
+ self->closeFloater();
+}
+
+void LLFloaterScriptQueue::addObject(const LLUUID& id, std::string name)
+{
+ ObjectData obj = { id, name };
+ mObjectList.push_back(obj);
+}
+
+bool LLFloaterScriptQueue::start()
+{
+ std::string buffer;
+
+ LLStringUtil::format_map_t args;
+ args["[START]"] = mStartString;
+ args["[COUNT]"] = llformat ("%d", mObjectList.size());
+ buffer = getString ("Starting", args);
+
+ getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
+
+ return startQueue();
+}
+
+void LLFloaterScriptQueue::addProcessingMessage(const std::string &message, const LLSD &args)
+{
+ std::string buffer(LLTrans::getString(message, args));
+
+ getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
+}
+
+void LLFloaterScriptQueue::addStringMessage(const std::string &message)
+{
+ getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
+}
+
+
+bool LLFloaterScriptQueue::isDone() const
+{
+ return (mCurrentObjectID.isNull() && (mObjectList.size() == 0));
+}
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterCompileQueue
+///----------------------------------------------------------------------------
+LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key)
+ : LLFloaterScriptQueue(key)
+{
+ setTitle(LLTrans::getString("CompileQueueTitle"));
+ setStartString(LLTrans::getString("CompileQueueStart"));
+
+}
+
+LLFloaterCompileQueue::~LLFloaterCompileQueue()
+{
+}
+
+void LLFloaterCompileQueue::experienceIdsReceived( const LLSD& content )
+{
+ for(LLSD::array_const_iterator it = content.beginArray(); it != content.endArray(); ++it)
+ {
+ mExperienceIds.insert(it->asUUID());
+ }
+}
+
+bool LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const
+{
+ return mExperienceIds.find(id) != mExperienceIds.end();
+}
+
+// //Attempt to record this asset ID. If it can not be inserted into the set
+// //then it has already been processed so return false.
+
+void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD &expresult)
+{
+ LLEventPumps::instance().post(pumpName, expresult);
+}
+
+// *TODO: handleSCriptRetrieval is passed into the cache via a legacy C function pointer
+// future project would be to convert these to C++ callables (std::function<>) so that
+// we can use bind and remove the userData parameter.
+//
+void LLFloaterCompileQueue::handleScriptRetrieval(const LLUUID& assetId,
+ LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus)
+{
+ LLSD result(LLSD::emptyMap());
+
+ result["asset_id"] = assetId;
+ if (status)
+ {
+ result["error"] = status;
+
+ if (status == LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE)
+ {
+ result["message"] = LLTrans::getString("CompileQueueProblemDownloading") + (":");
+ result["alert"] = LLTrans::getString("CompileQueueScriptNotFound");
+ }
+ else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
+ {
+ result["message"] = LLTrans::getString("CompileQueueInsufficientPermFor") + (":");
+ result["alert"] = LLTrans::getString("CompileQueueInsufficientPermDownload");
+ }
+ else
+ {
+ result["message"] = LLTrans::getString("CompileQueueUnknownFailure");
+ }
+ }
+
+ LLEventPumps::instance().post(((HandleScriptUserData *)userData)->getPumpName(), result);
+
+}
+
+/*static*/
+void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID parent)
+{
+ LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", parent);
+ if (!queue)
+ return;
+
+ queue->experienceIdsReceived(result["experience_ids"]);
+
+ // getDerived handle gets a handle that can be resolved to a parent class of the derived object.
+ LLHandle<LLFloaterScriptQueue> hFloater(queue->getDerivedHandle<LLFloaterScriptQueue>());
+
+ // note subtle difference here: getDerivedHandle in this case is for an LLFloaterCompileQueue
+ fnQueueAction_t fn = boost::bind(LLFloaterCompileQueue::processScript,
+ queue->getDerivedHandle<LLFloaterCompileQueue>(), _1, _2, _3);
+
+
+ LLCoros::instance().launch("ScriptQueueCompile", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro,
+ queue->mStartString,
+ hFloater,
+ queue->mObjectList,
+ fn));
+
+}
+
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloater,
+ const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
+{
+ if (LLApp::isExiting())
+ {
+ // Reply from coroutine came on shutdown
+ // We are quiting, don't start any more coroutines!
+ return true;
+ }
+
+ LLSD result;
+ LLCheckedHandle<LLFloaterCompileQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+ bool monocompile = floater->mMono;
+
+ // Initial test to see if we can (or should) attempt to compile the script.
+ LLInventoryItem *item = dynamic_cast<LLInventoryItem *>(inventory);
+
+ if (!item)
+ {
+ LL_WARNS("SCRIPTQ") << "item retrieved is not an LLInventoryItem." << LL_ENDL;
+ return true;
+ }
+
+ if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) ||
+ !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
+ {
+ std::string buffer = "Skipping: " + item->getName() + "(Permissions)";
+ floater->addStringMessage(buffer);
+ return true;
+ }
+
+ // Attempt to retrieve the experience
+ LLUUID experienceId;
+ {
+ LLExperienceCache::instance().fetchAssociatedExperience(inventory->getParentUUID(), inventory->getUUID(),
+ boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1));
+
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT,
+ LLSDMap("timeout", LLSD::Boolean(true)));
+
+ floater.check();
+
+ if (result.has("timeout"))
+ { // A timeout filed in the result will always be true if present.
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = inventory->getName();
+ std::string buffer = floater->getString("Timeout", args);
+ floater->addStringMessage(buffer);
+ return true;
+ }
+
+ if (result.has(LLExperienceCache::EXPERIENCE_ID))
+ {
+ experienceId = result[LLExperienceCache::EXPERIENCE_ID].asUUID();
+ if (!floater->hasExperience(experienceId))
+ {
+ floater->addProcessingMessage("CompileNoExperiencePerm",
+ LLSDMap("SCRIPT", inventory->getName())
+ ("EXPERIENCE", result[LLExperienceCache::NAME].asString()));
+ return true;
+ }
+ }
+
+ }
+
+ if (!gAssetStorage)
+ {
+ // viewer likely is shutting down
+ return true;
+ }
+
+ {
+ HandleScriptUserData userData(pump.getName());
+
+
+ // request the asset
+ gAssetStorage->getInvItemAsset(LLHost(),
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ item->getPermissions().getOwner(),
+ object->getID(),
+ item->getUUID(),
+ item->getAssetUUID(),
+ item->getType(),
+ &LLFloaterCompileQueue::handleScriptRetrieval,
+ &userData);
+
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT,
+ LLSDMap("timeout", LLSD::Boolean(true)));
+ }
+
+ if (result.has("timeout"))
+ { // A timeout filed in the result will always be true if present.
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = inventory->getName();
+ std::string buffer = floater->getString("Timeout", args);
+ floater->addStringMessage(buffer);
+ return true;
+ }
+
+ if (result.has("error"))
+ {
+ LL_WARNS("SCRIPTQ") << "Inventory fetch returned with error. Code: " << result["error"].asString() << LL_ENDL;
+ std::string buffer = result["message"].asString() + " " + inventory->getName();
+ floater->addStringMessage(buffer);
+
+ if (result.has("alert"))
+ {
+ LLSD args;
+ args["MESSAGE"] = result["alert"].asString();
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+ return true;
+ }
+
+ LLUUID assetId = result["asset_id"];
+
+ std::string url = object->getRegion()->getCapability("UpdateScriptTask");
+
+ {
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(object->getID(),
+ inventory->getUUID(),
+ assetId,
+ monocompile ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2,
+ true,
+ inventory->getName(),
+ LLUUID(),
+ experienceId,
+ boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _4)));
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true)));
+
+ floater.check();
+
+ if (result.has("timeout"))
+ { // A timeout filed in the result will always be true if present.
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = inventory->getName();
+ std::string buffer = floater->getString("Timeout", args);
+ floater->addStringMessage(buffer);
+ return true;
+ }
+
+ // Bytecode save completed
+ if (result["compiled"])
+ {
+ std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" succeeded");
+
+ floater->addStringMessage(buffer);
+ LL_INFOS() << buffer << LL_ENDL;
+ }
+ else
+ {
+ LLSD compile_errors = result["errors"];
+ std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" failed:");
+ floater->addStringMessage(buffer);
+ for (LLSD::array_const_iterator line = compile_errors.beginArray();
+ line < compile_errors.endArray(); line++)
+ {
+ std::string str = line->asString();
+ str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
+
+ floater->addStringMessage(str);
+ }
+ LL_INFOS() << result["errors"] << LL_ENDL;
+ }
+
+ return true;
+}
+
+bool LLFloaterCompileQueue::startQueue()
+{
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ std::string lookup_url = region->getCapability("GetCreatorExperiences");
+ if (!lookup_url.empty())
+ {
+ LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success =
+ boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, _1, getKey().asUUID());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t failure =
+ boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, LLSD(), getKey().asUUID());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url,
+ success, failure);
+ return true;
+ }
+ }
+
+ return true;
+}
+
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterResetQueue
+///----------------------------------------------------------------------------
+
+LLFloaterResetQueue::LLFloaterResetQueue(const LLSD& key)
+ : LLFloaterScriptQueue(key)
+{
+ setTitle(LLTrans::getString("ResetQueueTitle"));
+ setStartString(LLTrans::getString("ResetQueueStart"));
+}
+
+LLFloaterResetQueue::~LLFloaterResetQueue()
+{
+}
+
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
+ const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
+{
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+
+ std::string buffer;
+ buffer = floater->getString("Resetting") + (": ") + inventory->getName();
+ floater->addStringMessage(buffer);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ScriptReset);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Script);
+ msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
+ msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID());
+ msg->sendReliable(object->getRegion()->getHost());
+
+ return true;
+}
+
+bool LLFloaterResetQueue::startQueue()
+{
+ // Bind the resetObjectScripts method into a QueueAction function and pass it
+ // into the object queue processing coroutine.
+ fnQueueAction_t fn = boost::bind(LLFloaterResetQueue::resetObjectScripts,
+ getDerivedHandle<LLFloaterScriptQueue>(), _1, _2, _3);
+
+ LLCoros::instance().launch("ScriptResetQueue", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro,
+ mStartString,
+ getDerivedHandle<LLFloaterScriptQueue>(),
+ mObjectList,
+ fn));
+
+ return true;
+}
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterRunQueue
+///----------------------------------------------------------------------------
+
+LLFloaterRunQueue::LLFloaterRunQueue(const LLSD& key)
+ : LLFloaterScriptQueue(key)
+{
+ setTitle(LLTrans::getString("RunQueueTitle"));
+ setStartString(LLTrans::getString("RunQueueStart"));
+}
+
+LLFloaterRunQueue::~LLFloaterRunQueue()
+{
+}
+
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterRunQueue::runObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
+ const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
+{
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+
+ std::string buffer;
+ buffer = floater->getString("Running") + (": ") + inventory->getName();
+ floater->addStringMessage(buffer);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_SetScriptRunning);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Script);
+ msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
+ msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID());
+ msg->addBOOLFast(_PREHASH_Running, true);
+ msg->sendReliable(object->getRegion()->getHost());
+
+ return true;
+}
+
+bool LLFloaterRunQueue::startQueue()
+{
+ LLHandle<LLFloaterScriptQueue> hFloater(getDerivedHandle<LLFloaterScriptQueue>());
+ fnQueueAction_t fn = boost::bind(LLFloaterRunQueue::runObjectScripts, hFloater, _1, _2, _3);
+
+ LLCoros::instance().launch("ScriptRunQueue", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro,
+ mStartString,
+ hFloater,
+ mObjectList,
+ fn));
+
+ return true;
+}
+
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterNotRunQueue
+///----------------------------------------------------------------------------
+
+LLFloaterNotRunQueue::LLFloaterNotRunQueue(const LLSD& key)
+ : LLFloaterScriptQueue(key)
+{
+ setTitle(LLTrans::getString("NotRunQueueTitle"));
+ setStartString(LLTrans::getString("NotRunQueueStart"));
+}
+
+LLFloaterNotRunQueue::~LLFloaterNotRunQueue()
+{
+}
+
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterNotRunQueue::stopObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
+ const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
+{
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+
+ std::string buffer;
+ buffer = floater->getString("NotRunning") + (": ") + inventory->getName();
+ floater->addStringMessage(buffer);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_SetScriptRunning);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Script);
+ msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
+ msg->addUUIDFast(_PREHASH_ItemID, inventory->getUUID());
+ msg->addBOOLFast(_PREHASH_Running, false);
+ msg->sendReliable(object->getRegion()->getHost());
+
+ return true;
+}
+
+bool LLFloaterNotRunQueue::startQueue()
+{
+ LLHandle<LLFloaterScriptQueue> hFloater(getDerivedHandle<LLFloaterScriptQueue>());
+
+ fnQueueAction_t fn = boost::bind(&LLFloaterNotRunQueue::stopObjectScripts, hFloater, _1, _2, _3);
+ LLCoros::instance().launch("ScriptQueueNotRun", boost::bind(LLFloaterScriptQueue::objectScriptProcessingQueueCoro,
+ mStartString,
+ hFloater,
+ mObjectList,
+ fn));
+
+ return true;
+}
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
+void ObjectInventoryFetcher::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data)
+{
+ mInventoryList.clear();
+ mInventoryList.assign(inventory->begin(), inventory->end());
+
+ mPump.post(LLSDMap("changed", LLSD::Boolean(true)));
+
+}
+
+void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, LLHandle<LLFloaterScriptQueue> hfloater,
+ object_data_list_t objectList, fnQueueAction_t func)
+{
+ LLCoros::set_consuming(true);
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // This is expected if the dialog closes.
+ LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true);
+
+ try
+ {
+ for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj)
+ {
+ bool firstForObject = true;
+ LLUUID object_id = (*itObj).mObjectId;
+ LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL;
+
+ LLPointer<LLViewerObject> obj = gObjectList.findObject(object_id);
+ LLInventoryObject::object_list_t inventory;
+ if (obj)
+ {
+ ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL));
+
+ fetcher->fetchInventory();
+
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = (*itObj).mObjectName;
+ floater->addStringMessage(floater->getString("LoadingObjInv", args));
+
+ LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, QUEUE_INVENTORY_FETCH_TIMEOUT,
+ LLSDMap("timeout", LLSD::Boolean(true)));
+
+ if (result.has("timeout"))
+ { // A timeout filed in the result will always be true if present.
+ LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() <<
+ ". Skipping to next object." << LL_ENDL;
+
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = (*itObj).mObjectName;
+ floater->addStringMessage(floater->getString("Timeout", args));
+
+ continue;
+ }
+
+ inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end());
+ }
+ else
+ {
+ LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id <<
+ ". Skipping to next." << LL_ENDL;
+ continue;
+ }
+
+ // TODO: Get the name of the object we are looking at here so that we can display it below.
+ //std::string objName = (dynamic_cast<LLInventoryObject *>(obj.get()))->getName();
+ LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL;
+
+ for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin();
+ itInv != inventory.end(); ++itInv)
+ {
+ floater.check();
+
+ // note, we have a smart pointer to the obj above... but if we didn't we'd check that
+ // it still exists here.
+
+ if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT))
+ {
+ LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL;
+ if (firstForObject)
+ {
+ //floater->addStringMessage(objName + ":");
+ firstForObject = false;
+ }
+
+ if (!func(obj, (*itInv), maildrop))
+ {
+ continue;
+ }
+ }
+
+ // no other explicit suspension point in this loop. func(...) MIGHT suspend
+ // but offers no guarantee of doing so.
+ llcoro::suspend();
+ }
+ floater.check();
+ }
+
+ floater->addStringMessage("Done");
+ floater->getChildView("close")->setEnabled(true);
+ }
+ catch (LLCheckedHandleBase::Stale &)
+ {
+ // This is expected. It means that floater has been closed before
+ // processing was completed.
+ LL_DEBUGS("SCRIPTQ") << "LLExeceptionStaleHandle caught! Floater has most likely been closed." << LL_ENDL;
+ }
+}
|