phoenix-firestorm/indra/newview/llviewerassetupload.cpp

1091 lines
33 KiB
C++

/**
* @file llviewerassetupload.cpp
* @author optional
* @brief brief description of the file
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "linden_common.h"
#include "llviewertexturelist.h"
#include "llimage.h"
#include "lltrans.h"
#include "lluuid.h"
#include "llvorbisencode.h"
#include "lluploaddialog.h"
#include "llnotificationsutil.h"
#include "llagent.h"
#include "llfloaterreg.h"
#include "llfloatersnapshot.h"
#include "llstatusbar.h"
#include "llinventorypanel.h"
#include "llsdutil.h"
#include "llviewerassetupload.h"
#include "llappviewer.h"
#include "llviewerstats.h"
#include "llfilesystem.h"
#include "llgesturemgr.h"
#include "llpreviewnotecard.h"
#include "llpreviewgesture.h"
#include "llcoproceduremanager.h"
#include "llthread.h"
#include "llkeyframemotion.h"
#include "lldatapacker.h"
#include "llvoavatarself.h"
#include "llviewernetwork.h"
#include "llviewercontrol.h"
#include "llfloatersidepanelcontainer.h"
#include "llsidepanelinventory.h"
void dialog_refresh_all();
static const U32 LL_ASSET_UPLOAD_TIMEOUT_SEC = 60;
LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
LLAssetType::EType assetType, std::string name, std::string description,
S32 compressionInfo, LLFolderType::EType destinationType,
LLInventoryType::EType inventoryType, U32 nextOWnerPerms,
U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) :
mTransactionId(transactId),
mAssetType(assetType),
mName(name),
mDescription(description),
mCompressionInfo(compressionInfo),
mDestinationFolderType(destinationType),
mInventoryType(inventoryType),
mNextOwnerPerms(nextOWnerPerms),
mGroupPerms(groupPerms),
mEveryonePerms(everyonePerms),
mExpectedUploadCost(expectedCost),
mShowInventory(showInventory),
mFolderId(LLUUID::null),
mItemId(LLUUID::null),
mAssetId(LLAssetID::null)
{ }
LLResourceUploadInfo::LLResourceUploadInfo(std::string name,
std::string description, S32 compressionInfo,
LLFolderType::EType destinationType, LLInventoryType::EType inventoryType,
U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) :
mName(name),
mDescription(description),
mCompressionInfo(compressionInfo),
mDestinationFolderType(destinationType),
mInventoryType(inventoryType),
mNextOwnerPerms(nextOWnerPerms),
mGroupPerms(groupPerms),
mEveryonePerms(everyonePerms),
mExpectedUploadCost(expectedCost),
mShowInventory(showInventory),
mTransactionId(),
mAssetType(LLAssetType::AT_NONE),
mFolderId(LLUUID::null),
mItemId(LLUUID::null),
mAssetId(LLAssetID::null)
{
mTransactionId.generate();
}
LLResourceUploadInfo::LLResourceUploadInfo(LLAssetID assetId, LLAssetType::EType assetType, std::string name) :
mAssetId(assetId),
mAssetType(assetType),
mName(name),
mDescription(),
mCompressionInfo(0),
mDestinationFolderType(LLFolderType::FT_NONE),
mInventoryType(LLInventoryType::IT_NONE),
mNextOwnerPerms(0),
mGroupPerms(0),
mEveryonePerms(0),
mExpectedUploadCost(0),
mShowInventory(true),
mTransactionId(),
mFolderId(LLUUID::null),
mItemId(LLUUID::null)
{
}
LLSD LLResourceUploadInfo::prepareUpload()
{
if (mAssetId.isNull())
generateNewAssetId();
incrementUploadStats();
assignDefaults();
return LLSD().with("success", LLSD::Boolean(true));
}
std::string LLResourceUploadInfo::getAssetTypeString() const
{
return LLAssetType::lookup(mAssetType);
}
std::string LLResourceUploadInfo::getInventoryTypeString() const
{
return LLInventoryType::lookup(mInventoryType);
}
LLSD LLResourceUploadInfo::generatePostBody()
{
LLSD body;
body["folder_id"] = mFolderId;
body["asset_type"] = getAssetTypeString();
body["inventory_type"] = getInventoryTypeString();
body["name"] = mName;
body["description"] = mDescription;
body["next_owner_mask"] = LLSD::Integer(mNextOwnerPerms);
body["group_mask"] = LLSD::Integer(mGroupPerms);
body["everyone_mask"] = LLSD::Integer(mEveryonePerms);
return body;
}
void LLResourceUploadInfo::logPreparedUpload()
{
LL_INFOS() << "*** Uploading: " << std::endl <<
"Type: " << LLAssetType::lookup(mAssetType) << std::endl <<
"UUID: " << mAssetId.asString() << std::endl <<
"Name: " << mName << std::endl <<
"Desc: " << mDescription << std::endl <<
"Expected Upload Cost: " << mExpectedUploadCost << std::endl <<
"Folder: " << mFolderId << std::endl <<
"Asset Type: " << LLAssetType::lookup(mAssetType) << LL_ENDL;
}
LLUUID LLResourceUploadInfo::finishUpload(LLSD &result)
{
if (getFolderId().isNull())
{
return LLUUID::null;
}
U32 permsEveryone = PERM_NONE;
U32 permsGroup = PERM_NONE;
U32 permsNextOwner = PERM_ALL;
if (result.has("new_next_owner_mask"))
{
// The server provided creation perms so use them.
// Do not assume we got the perms we asked for in
// since the server may not have granted them all.
permsEveryone = result["new_everyone_mask"].asInteger();
permsGroup = result["new_group_mask"].asInteger();
permsNextOwner = result["new_next_owner_mask"].asInteger();
}
else
{
// The server doesn't provide creation perms
// so use old assumption-based perms.
if (getAssetTypeString() != "snapshot")
{
permsNextOwner = PERM_MOVE | PERM_TRANSFER;
}
}
LLPermissions new_perms;
new_perms.init(
gAgent.getID(),
gAgent.getID(),
LLUUID::null,
LLUUID::null);
new_perms.initMasks(
PERM_ALL,
PERM_ALL,
permsEveryone,
permsGroup,
permsNextOwner);
U32 flagsInventoryItem = 0;
if (result.has("inventory_flags"))
{
flagsInventoryItem = static_cast<U32>(result["inventory_flags"].asInteger());
if (flagsInventoryItem != 0)
{
LL_INFOS() << "inventory_item_flags " << flagsInventoryItem << LL_ENDL;
}
}
S32 creationDate = time_corrected();
LLUUID serverInventoryItem = result["new_inventory_item"].asUUID();
LLUUID serverAssetId = result["new_asset"].asUUID();
LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
serverInventoryItem,
getFolderId(),
new_perms,
serverAssetId,
getAssetType(),
getInventoryType(),
getName(),
getDescription(),
LLSaleInfo::DEFAULT,
flagsInventoryItem,
creationDate);
gInventory.updateItem(item);
gInventory.notifyObservers();
return serverInventoryItem;
}
LLAssetID LLResourceUploadInfo::generateNewAssetId()
{
if (gDisconnected)
{
LLAssetID rv;
rv.setNull();
return rv;
}
mAssetId = mTransactionId.makeAssetID(gAgent.getSecureSessionID());
return mAssetId;
}
void LLResourceUploadInfo::incrementUploadStats() const
{
if (LLAssetType::AT_SOUND == mAssetType)
{
add(LLStatViewer::UPLOAD_SOUND, 1);
}
else if (LLAssetType::AT_TEXTURE == mAssetType)
{
add(LLStatViewer::UPLOAD_TEXTURE, 1);
}
else if (LLAssetType::AT_ANIMATION == mAssetType)
{
add(LLStatViewer::ANIMATION_UPLOADS, 1);
}
}
void LLResourceUploadInfo::assignDefaults()
{
if (LLInventoryType::IT_NONE == mInventoryType)
{
mInventoryType = LLInventoryType::defaultForAssetType(mAssetType);
}
LLStringUtil::stripNonprintable(mName);
LLStringUtil::stripNonprintable(mDescription);
if (mName.empty())
{
mName = "(No Name)";
}
if (mDescription.empty())
{
mDescription = "(No Description)";
}
mFolderId = gInventory.findUserDefinedCategoryUUIDForType(
(mDestinationFolderType == LLFolderType::FT_NONE) ?
(LLFolderType::EType)mAssetType : mDestinationFolderType);
}
std::string LLResourceUploadInfo::getDisplayName() const
{
return (mName.empty()) ? mAssetId.asString() : mName;
};
bool LLResourceUploadInfo::findAssetTypeOfExtension(const std::string& exten, LLAssetType::EType& asset_type)
{
U32 codec;
return findAssetTypeAndCodecOfExtension(exten, asset_type, codec, false);
}
// static
bool LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(const std::string& exten, LLAssetType::EType& asset_type, U32& codec, bool bulk_upload)
{
bool succ = false;
std::string exten_lc(exten);
LLStringUtil::toLower(exten_lc);
codec = LLImageBase::getCodecFromExtension(exten_lc);
if (codec != IMG_CODEC_INVALID)
{
asset_type = LLAssetType::AT_TEXTURE;
succ = true;
}
else if (exten_lc == "wav")
{
asset_type = LLAssetType::AT_SOUND;
succ = true;
}
else if (exten_lc == "anim")
{
asset_type = LLAssetType::AT_ANIMATION;
succ = true;
}
else if (!bulk_upload && (exten_lc == "bvh"))
{
asset_type = LLAssetType::AT_ANIMATION;
succ = true;
}
else if (exten_lc == "ogg")
{
asset_type = LLAssetType::AT_SOUND;
succ = true;
}
else if (exten_lc == "j2k")
{
asset_type = LLAssetType::AT_TEXTURE;
succ = true;
}
return succ;
}
//=========================================================================
LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo(
std::string fileName,
std::string name,
std::string description,
S32 compressionInfo,
LLFolderType::EType destinationType,
LLInventoryType::EType inventoryType,
U32 nextOWnerPerms,
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
bool show_inventory) :
LLResourceUploadInfo(name, description, compressionInfo,
destinationType, inventoryType,
nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory),
mFileName(fileName)
{
}
LLSD LLNewFileResourceUploadInfo::prepareUpload()
{
if (getAssetId().isNull())
generateNewAssetId();
LLSD result = exportTempFile();
if (result.has("error"))
return result;
return LLResourceUploadInfo::prepareUpload();
}
LLSD LLNewFileResourceUploadInfo::exportTempFile()
{
std::string filename = gDirUtilp->getTempFilename();
std::string exten = gDirUtilp->getExtension(getFileName());
LLAssetType::EType assetType = LLAssetType::AT_NONE;
U32 codec = IMG_CODEC_INVALID;
bool found_type = findAssetTypeAndCodecOfExtension(exten, assetType, codec);
std::string errorMessage;
std::string errorLabel;
bool error = false;
if (exten.empty())
{
std::string shortName = gDirUtilp->getBaseFileName(filename);
// No extension
// <FS:Ansariel> Duplicate error message output
//errorMessage = llformat(
// "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
// shortName.c_str());
// </FS:Ansariel>
errorLabel = "NoFileExtension";
error = true;
}
else if (!found_type)
{
// Unknown extension
errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
errorLabel = "ErrorMessage";
error = TRUE;;
}
else if (assetType == LLAssetType::AT_TEXTURE)
{
// It's an image file, the upload procedure is the same for all
if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec))
{
// <FS:Ansariel> Duplicate error message output
//errorMessage = llformat("Problem with file %s:\n\n%s\n",
// getFileName().c_str(), LLImage::getLastError().c_str());
errorMessage = LLImage::getLastError();
// </FS:Ansariel>
errorLabel = "ProblemWithFile";
error = true;
}
}
else if (assetType == LLAssetType::AT_SOUND)
{
S32 encodeResult = 0;
LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL;
// <FS:Ansariel> FIRE-17812: Increase sounds length to 60s on OpenSim
//encodeResult = encode_vorbis_file(getFileName(), filename);
encodeResult = encode_vorbis_file(getFileName(), filename, LLGridManager::instance().isInSecondLife());
// </FS:Ansariel>
if (LLVORBISENC_NOERR != encodeResult)
{
switch (encodeResult)
{
case LLVORBISENC_DEST_OPEN_ERR:
//errorMessage = llformat("Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); // <FS:Ansariel> Duplicate error message output
errorLabel = "CannotOpenTemporarySoundFile";
break;
default:
//errorMessage = llformat("Unknown vorbis encode failure on: %s\n", getFileName().c_str()); // <FS:Ansariel> Duplicate error message output
errorLabel = "UnknownVorbisEncodeFailure";
break;
}
error = true;
}
}
else if (exten == "bvh")
{
//errorMessage = llformat("We do not currently support bulk upload of animation files\n"); // <FS:Ansariel> Duplicate error message output
errorLabel = "DoNotSupportBulkAnimationUpload";
error = true;
}
else if (exten == "anim")
{
// Default unless everything succeeds
errorLabel = "ProblemWithFile";
error = true;
// read from getFileName()
LLAPRFile infile;
infile.open(getFileName(),LL_APR_RB);
if (!infile.getFileHandle())
{
LL_WARNS() << "Couldn't open file for reading: " << getFileName() << LL_ENDL;
errorMessage = llformat("Failed to open animation file %s\n", getFileName().c_str());
}
else
{
S32 size = LLAPRFile::size(getFileName());
U8* buffer = new U8[size];
S32 size_read = infile.read(buffer,size);
if (size_read != size)
{
errorMessage = llformat("Failed to read animation file %s: wanted %d bytes, got %d\n", getFileName().c_str(), size, size_read);
}
else
{
LLDataPackerBinaryBuffer dp(buffer, size);
LLKeyframeMotion *motionp = new LLKeyframeMotion(getAssetId());
motionp->setCharacter(gAgentAvatarp);
if (motionp->deserialize(dp, getAssetId(), false))
{
// write to temp file
bool succ = motionp->dumpToFile(filename);
if (succ)
{
assetType = LLAssetType::AT_ANIMATION;
errorLabel = "";
error = false;
}
else
{
errorMessage = "Failed saving temporary animation file";
}
}
else
{
errorMessage = "Failed reading animation file";
}
delete motionp; // <FS:Ansariel> Memory leak fix
}
delete[] buffer; // <FS:Ansariel> Memory leak fix
}
}
else
{
// Unknown extension
errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
errorLabel = "ErrorMessage";
error = TRUE;;
}
if (error)
{
LLSD errorResult(LLSD::emptyMap());
errorResult["error"] = LLSD::Binary(true);
// <FS:Ansariel> Duplicate error message output
if (!errorMessage.empty())
errorResult["message"] = errorMessage;
errorResult["label"] = errorLabel;
return errorResult;
}
setAssetType(assetType);
// copy this file into the cache for upload
S32 file_size;
LLAPRFile infile;
infile.open(filename, LL_APR_RB, NULL, &file_size);
if (infile.getFileHandle())
{
LLFileSystem file(getAssetId(), assetType, LLFileSystem::APPEND);
const S32 buf_size = 65536;
U8 copy_buf[buf_size];
while ((file_size = infile.read(copy_buf, buf_size)))
{
file.write(copy_buf, file_size);
}
}
else
{
errorMessage = llformat("Unable to access output file: %s", filename.c_str());
LLSD errorResult(LLSD::emptyMap());
errorResult["error"] = LLSD::Binary(true);
errorResult["message"] = errorMessage;
return errorResult;
}
return LLSD();
}
//=========================================================================
LLNewBufferedResourceUploadInfo::LLNewBufferedResourceUploadInfo(
const std::string& buffer,
const LLAssetID& asset_id,
std::string name,
std::string description,
S32 compressionInfo,
LLFolderType::EType destinationType,
LLInventoryType::EType inventoryType,
LLAssetType::EType assetType,
U32 nextOWnerPerms,
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
bool show_inventory,
uploadFinish_f finish,
uploadFailure_f failure)
: LLResourceUploadInfo(name, description, compressionInfo,
destinationType, inventoryType,
nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory)
, mBuffer(buffer)
, mFinishFn(finish)
, mFailureFn(failure)
{
setAssetType(assetType);
setAssetId(asset_id);
}
LLSD LLNewBufferedResourceUploadInfo::prepareUpload()
{
if (getAssetId().isNull())
generateNewAssetId();
LLSD result = exportTempFile();
if (result.has("error"))
return result;
return LLResourceUploadInfo::prepareUpload();
}
LLSD LLNewBufferedResourceUploadInfo::exportTempFile()
{
std::string filename = gDirUtilp->getTempFilename();
// copy buffer to the cache for upload
LLFileSystem file(getAssetId(), getAssetType(), LLFileSystem::APPEND);
file.write((U8*) mBuffer.c_str(), mBuffer.size());
return LLSD();
}
LLUUID LLNewBufferedResourceUploadInfo::finishUpload(LLSD &result)
{
LLUUID newItemId = LLResourceUploadInfo::finishUpload(result);
if (mFinishFn)
{
mFinishFn(result["new_asset"].asUUID(), result);
}
return newItemId;
}
bool LLNewBufferedResourceUploadInfo::failedUpload(LLSD &result, std::string &reason)
{
if (mFailureFn)
{
return mFailureFn(getAssetId(), result, reason);
}
return false; // Not handled
}
//=========================================================================
LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish, uploadFailed_f failed) :
LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
0, 0, 0, 0),
mTaskUpload(false),
mTaskId(LLUUID::null),
mContents(buffer),
mInvnFinishFn(finish),
mTaskFinishFn(nullptr),
mFailureFn(failed),
mStoredToCache(false)
{
setItemId(itemId);
setAssetType(assetType);
}
LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish) :
LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
0, 0, 0, 0),
mTaskUpload(false),
mTaskId(LLUUID::null),
mContents(),
mInvnFinishFn(finish),
mTaskFinishFn(nullptr),
mFailureFn(nullptr),
mStoredToCache(false)
{
setItemId(itemId);
EImageCodec codec = static_cast<EImageCodec>(image->getCodec());
switch (codec)
{
case IMG_CODEC_JPEG:
setAssetType(LLAssetType::AT_IMAGE_JPEG);
LL_INFOS() << "Upload Asset type set to JPEG." << LL_ENDL;
break;
case IMG_CODEC_TGA:
setAssetType(LLAssetType::AT_IMAGE_TGA);
LL_INFOS() << "Upload Asset type set to TGA." << LL_ENDL;
break;
default:
LL_WARNS() << "Unknown codec to asset type transition. Codec=" << (int)codec << "." << LL_ENDL;
break;
}
size_t imageSize = image->getDataSize();
mContents.reserve(imageSize);
mContents.assign((char *)image->getData(), imageSize);
}
LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish, uploadFailed_f failed) :
LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
0, 0, 0, 0),
mTaskUpload(true),
mTaskId(taskId),
mContents(buffer),
mInvnFinishFn(nullptr),
mTaskFinishFn(finish),
mFailureFn(failed),
mStoredToCache(false)
{
setItemId(itemId);
setAssetType(assetType);
}
LLSD LLBufferedAssetUploadInfo::prepareUpload()
{
if (getAssetId().isNull())
generateNewAssetId();
LLFileSystem file(getAssetId(), getAssetType(), LLFileSystem::APPEND);
S32 size = mContents.length() + 1;
file.write((U8*)mContents.c_str(), size);
mStoredToCache = true;
return LLSD().with("success", LLSD::Boolean(true));
}
LLSD LLBufferedAssetUploadInfo::generatePostBody()
{
LLSD body;
if (!getTaskId().isNull())
{
body["task_id"] = getTaskId();
}
body["item_id"] = getItemId();
return body;
}
LLUUID LLBufferedAssetUploadInfo::finishUpload(LLSD &result)
{
LLUUID newAssetId = result["new_asset"].asUUID();
LLUUID itemId = getItemId();
if (mStoredToCache)
{
LLAssetType::EType assetType(getAssetType());
LLFileSystem::renameFile(getAssetId(), assetType, newAssetId, assetType);
}
if (mTaskUpload)
{
LLUUID taskId = getTaskId();
dialog_refresh_all();
if (mTaskFinishFn)
{
mTaskFinishFn(itemId, taskId, newAssetId, result);
}
}
else
{
LLUUID newItemId(LLUUID::null);
if (itemId.notNull())
{
LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(itemId);
if (!item)
{
LL_WARNS() << "Inventory item for " << getDisplayName() << " is no longer in agent inventory." << LL_ENDL;
return newAssetId;
}
// Update viewer inventory item
LLPointer<LLViewerInventoryItem> newItem = new LLViewerInventoryItem(item);
newItem->setAssetUUID(newAssetId);
gInventory.updateItem(newItem);
newItemId = newItem->getUUID();
LL_INFOS() << "Inventory item " << item->getName() << " saved into " << newAssetId.asString() << LL_ENDL;
}
if (mInvnFinishFn)
{
mInvnFinishFn(itemId, newAssetId, newItemId, result);
}
gInventory.notifyObservers();
}
return newAssetId;
}
bool LLBufferedAssetUploadInfo::failedUpload(LLSD &result, std::string &reason)
{
if (mFailureFn)
{
return mFailureFn(getItemId(), getTaskId(), result, reason);
}
return false;
}
//=========================================================================
LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish, uploadFailed_f failed):
LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish, failed),
mExerienceId(),
mTargetType(MONO),
mIsRunning(false)
{
}
LLScriptAssetUpload::LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType,
bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish, uploadFailed_f failed):
LLBufferedAssetUploadInfo(taskId, itemId, LLAssetType::AT_LSL_TEXT, buffer, finish, failed),
mExerienceId(exerienceId),
mTargetType(targetType),
mIsRunning(isRunning)
{
}
LLSD LLScriptAssetUpload::generatePostBody()
{
LLSD body;
if (getTaskId().isNull())
{
body["item_id"] = getItemId();
body["target"] = "mono";
}
else
{
body["task_id"] = getTaskId();
body["item_id"] = getItemId();
// <FS:Ansariel> OpenSim expects an integer here...
//body["is_script_running"] = getIsRunning();
body["is_script_running"] = (BOOL)getIsRunning();
// </FS:Ansariel>
body["target"] = (getTargetType() == MONO) ? "mono" : "lsl2";
body["experience"] = getExerienceId();
}
return body;
}
//=========================================================================
/*static*/
LLUUID LLViewerAssetUpload::EnqueueInventoryUpload(const std::string &url, const LLResourceUploadInfo::ptr_t &uploadInfo)
{
std::string procName("LLViewerAssetUpload::AssetInventoryUploadCoproc(");
LLUUID queueId = LLCoprocedureManager::instance().enqueueCoprocedure("Upload",
procName + LLAssetType::lookup(uploadInfo->getAssetType()) + ")",
boost::bind(&LLViewerAssetUpload::AssetInventoryUploadCoproc, _1, _2, url, uploadInfo));
return queueId;
}
//=========================================================================
/*static*/
void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter,
const LLUUID &id, std::string url, LLResourceUploadInfo::ptr_t uploadInfo)
{
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
httpOptions->setTimeout(LL_ASSET_UPLOAD_TIMEOUT_SEC);
LLSD result = uploadInfo->prepareUpload();
uploadInfo->logPreparedUpload();
if (result.has("error"))
{
HandleUploadError(LLCore::HttpStatus(499), result, uploadInfo);
return;
}
llcoro::suspend();
if (uploadInfo->showUploadDialog())
{
// <FS:Ansariel> Localization fix
//std::string uploadMessage = "Uploading...\n\n";
//uploadMessage.append(uploadInfo->getDisplayName());
LLStringUtil::format_map_t args;
args["ASSET_NAME"] = uploadInfo->getDisplayName();
std::string uploadMessage = LLTrans::getString("Asset_Uploading", args);
// </FS:Ansariel>
LLUploadDialog::modalUploadDialog(uploadMessage);
}
LLSD body = uploadInfo->generatePostBody();
result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOptions);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if ((!status) || (result.has("error")))
{
HandleUploadError(status, result, uploadInfo);
if (uploadInfo->showUploadDialog())
LLUploadDialog::modalUploadFinished();
return;
}
std::string uploader = result["uploader"].asString();
bool success = false;
if (!uploader.empty() && uploadInfo->getAssetId().notNull())
{
result = httpAdapter->postFileAndSuspend(httpRequest, uploader, uploadInfo->getAssetId(), uploadInfo->getAssetType(), httpOptions);
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
std::string ulstate = result["state"].asString();
if ((!status) || (ulstate != "complete"))
{
HandleUploadError(status, result, uploadInfo);
if (uploadInfo->showUploadDialog())
LLUploadDialog::modalUploadFinished();
return;
}
if (!result.has("success"))
{
result["success"] = LLSD::Boolean((ulstate == "complete") && status);
}
S32 uploadPrice = result["upload_price"].asInteger();
if (uploadPrice > 0)
{
// this upload costed us L$, update our balance
// and display something saying that it cost L$
LLStatusBar::sendMoneyBalanceRequest();
// <FS:Ansariel> FIRE-10628 - Option to supress upload cost notification
if (gSavedSettings.getBOOL("FSShowUploadPaymentToast"))
{
LLSD args;
args["AMOUNT"] = llformat("%d", uploadPrice);
LLNotificationsUtil::add("UploadPayment", args);
}
// </FS:Ansariel>
}
}
else
{
LL_WARNS() << "No upload url provided. Nothing uploaded, responding with previous result." << LL_ENDL;
}
LLUUID serverInventoryItem = uploadInfo->finishUpload(result);
if (uploadInfo->showInventoryPanel())
{
if (serverInventoryItem.notNull())
{
success = true;
LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
// Show the preview panel for textures and sounds to let
// user know that the image (or snapshot) arrived intact.
LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
// <FS:Ansariel> Use correct inventory floater for showing the upload
if (!panel)
{
// Having no active panel here could either mean the primary inventory floater
// is the most-active inventory, but showing the object properties panel, or
// no inventory floater is open. In that case we make sure to show the inventory
// panel on the primary inventory floater. We don't have to deal with selecting
// the correct floater because only the primary inventory floater can show
// object properties.
LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
sidepanel_inventory->showInventoryPanel();
}
// </FS:Ansariel>
// <FS:Testy> FIRE-22943: Don't switch away from the "Recent Items" tab.
//LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, FALSE, TAKE_FOCUS_NO, (panel == NULL));
BOOL show_main_panel = (!panel || panel->getName() != "Recent Items");
LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, show_main_panel, TAKE_FOCUS_NO, (panel == NULL));
// </FS:Testy>
// restore keyboard focus
gFocusMgr.setKeyboardFocus(focus);
}
else
{
LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL;
}
}
// remove the "Uploading..." message
if (uploadInfo->showUploadDialog())
LLUploadDialog::modalUploadFinished();
// Let the Snapshot floater know we have finished uploading a snapshot to inventory
LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
if (uploadInfo->getAssetType() == LLAssetType::AT_TEXTURE && floater_snapshot && floater_snapshot->isShown())
{
floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory")));
}
}
//=========================================================================
/*static*/
void LLViewerAssetUpload::HandleUploadError(LLCore::HttpStatus status, LLSD &result, LLResourceUploadInfo::ptr_t &uploadInfo)
{
std::string reason;
std::string label("CannotUploadReason");
LL_WARNS() << ll_pretty_print_sd(result) << LL_ENDL;
if (result.has("label"))
{
label = result["label"].asString();
}
if (result.has("message"))
{
reason = result["message"].asString();
}
else
{
switch (status.getType())
{
case 404:
reason = LLTrans::getString("AssetUploadServerUnreacheble");
break;
case 499:
reason = LLTrans::getString("AssetUploadServerDifficulties");
break;
case 503:
reason = LLTrans::getString("AssetUploadServerUnavaliable");
break;
default:
reason = LLTrans::getString("AssetUploadRequestInvalid");
}
}
LLSD args;
if(label == "ErrorMessage")
{
args["ERROR_MESSAGE"] = reason;
}
else
{
args["FILE"] = uploadInfo->getDisplayName();
args["REASON"] = reason;
args["ERROR"] = reason;
}
LLNotificationsUtil::add(label, args);
if (uploadInfo->failedUpload(result, reason))
{
// no further action required, already handled by a callback
// ex: do not trigger snapshot floater when failing material texture
return;
}
// Todo: move these floater specific actions into proper callbacks
// Let the Snapshot floater know we have failed uploading.
LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
if (floater_snapshot && floater_snapshot->isWaitingState())
{
if (uploadInfo->getAssetType() == LLAssetType::AT_IMAGE_JPEG)
{
floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "postcard")));
}
if (uploadInfo->getAssetType() == LLAssetType::AT_TEXTURE)
{
floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory")));
}
}
}