diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-02-20 22:06:15 +0200 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-02-20 22:25:04 +0200 |
commit | e40f9af831c1257dea37a4565aafd73baa5005b6 (patch) | |
tree | 1c479174dd3d2e2e4538e984ccee484e4b4cccd8 | |
parent | 4f5d7f12563f1829856023d6967507fe783bbe5e (diff) |
SL-19108 WIP Managing inventory thumbnail #5
-rw-r--r-- | indra/newview/llfloaterchangeitemthumbnail.cpp | 201 | ||||
-rw-r--r-- | indra/newview/llpanelprofile.cpp | 14 | ||||
-rwxr-xr-x | indra/newview/llviewerregion.cpp | 2 |
3 files changed, 212 insertions, 5 deletions
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp index bd528f43dc..b267c7e0a3 100644 --- a/indra/newview/llfloaterchangeitemthumbnail.cpp +++ b/indra/newview/llfloaterchangeitemthumbnail.cpp @@ -38,10 +38,204 @@ #include "lltextbox.h" #include "lltexturectrl.h" #include "llthumbnailctrl.h" +#include "llviewermenufile.h" #include "llviewerobjectlist.h" #include "llwindow.h" +//TODO: this part is likely to be moved into outfit snapshot floater +// and flaoter is likely to become a thumbnail snapshot floater + +#include "llagent.h" +#include "llnotificationsutil.h" +#include "llviewertexturelist.h" + +static const std::string THUMBNAIL_ITEM_UPLOAD_CAP = "InventoryItemThumbnailUpload"; +static const std::string THUMBNAIL_CATEGORY_UPLOAD_CAP = "InventoryCategoryThumbnailUpload"; + +void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, LLSD first_data) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + // todo: notification? + LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL; + return; + } + if (!result.has("uploader")) + { + // todo: notification? + LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL; + return; + } + std::string uploader_cap = result["uploader"].asString(); + if (uploader_cap.empty()) + { + LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL; + return; + } + + // Upload the image + + LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); + S64 length; + + { + llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate); + if (!instream.is_open()) + { + LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL; + return; + } + length = instream.tellg(); + } + + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required! + uploaderhttpOpts->setFollowRedirects(true); + + result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders); + + httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LL_DEBUGS("Thumbnail") << result << LL_ENDL; + + if (!status) + { + LL_WARNS("Thumbnail") << "Failed to upload image " << status.toString() << LL_ENDL; + return; + } + + if (result["state"].asString() != "complete") + { + if (result.has("message")) + { + LL_WARNS("Thumbnail") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL; + } + else + { + LL_WARNS("Thumbnail") << "Failed to upload image " << result << LL_ENDL; + } + return; + } + + // todo: issue an inventory udpate? + //return result["new_asset"].asUUID(); +} + +class LLThumbnailImagePicker : public LLFilePickerThread +{ +public: + LLThumbnailImagePicker(const LLUUID &item_id, LLHandle<LLFloater> *handle); + LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id, LLHandle<LLFloater> *handle); + ~LLThumbnailImagePicker(); + void notify(const std::vector<std::string>& filenames) override; + +private: + LLHandle<LLFloater> *mHandle; + LLUUID mInventoryId; + LLUUID mTaskId; +}; + +LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, LLHandle<LLFloater> *handle) + : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE) + , mHandle(handle) + , mInventoryId(item_id) +{ +} + +LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id, LLHandle<LLFloater> *handle) + : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE) + , mHandle(handle) + , mInventoryId(item_id) + , mTaskId(task_id) +{ +} + +LLThumbnailImagePicker::~LLThumbnailImagePicker() +{ + delete mHandle; +} + +void LLThumbnailImagePicker::notify(const std::vector<std::string>& filenames) +{ + if (mHandle->isDead()) + { + return; + } + if (filenames.empty()) + { + return; + } + std::string file_path = filenames[0]; + if (file_path.empty()) + { + return; + } + + // generate a temp texture file for coroutine + std::string temp_file = gDirUtilp->getTempFilename(); + U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path)); + const S32 MAX_DIM = 256; + if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) + { + LLSD notif_args; + notif_args["REASON"] = LLImage::getLastError().c_str(); + LLNotificationsUtil::add("CannotUploadTexture", notif_args); + LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << mInventoryId << " " << mTaskId << ", reason: " << notif_args["REASON"].asString() << LL_ENDL; + return; + } + + std::string cap_name; + LLSD data; + + if (mTaskId.notNull()) + { + cap_name = THUMBNAIL_ITEM_UPLOAD_CAP; + data["item_id"] = mInventoryId; + data["task_id"] = mTaskId; + } + else if (gInventory.getCategory(mInventoryId)) + { + cap_name = THUMBNAIL_CATEGORY_UPLOAD_CAP; + data["category_id"] = mInventoryId; + } + else + { + cap_name = THUMBNAIL_ITEM_UPLOAD_CAP; + data["item_id"] = mInventoryId; + } + + std::string cap_url = gAgent.getRegionCapability(cap_name); + if (cap_url.empty()) + { + LLSD args; + args["CAPABILITY"] = cap_url; + LLNotificationsUtil::add("RegionCapabilityRequestError", args); + LL_WARNS("Thumbnail") << "Failed to upload profile image for item " << mInventoryId << " " << mTaskId << ", no cap found" << LL_ENDL; + return; + } + + LLCoros::instance().launch("postAgentUserImageCoro", + boost::bind(post_thumbnail_image_coro, cap_url, temp_file, data)); +} + LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key) : LLFloater(key) , mObserverInitialized(false) @@ -236,7 +430,14 @@ void LLFloaterChangeItemThumbnail::refreshFromItem(LLViewerInventoryItem* item) void LLFloaterChangeItemThumbnail::onUploadLocal(void *userdata) { + LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata; + (new LLThumbnailImagePicker(self->mItemId, self->mTaskId, new LLHandle<LLFloater>(self->getHandle())))->getFile(); + LLFloater* floaterp = self->mPickerHandle.get(); + if (floaterp) + { + floaterp->closeFloater(); + } } void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata) diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index bc3c8ae6b1..078c1370ee 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -366,7 +366,7 @@ LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::stri httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - LL_WARNS("AvatarProperties") << result << LL_ENDL; + LL_DEBUGS("AvatarProperties") << result << LL_ENDL; if (!status) { @@ -1438,7 +1438,6 @@ void LLPanelProfileSecondLife::setLoaded() } - class LLProfileImagePicker : public LLFilePickerThread { public: @@ -1485,15 +1484,20 @@ void LLProfileImagePicker::notify(const std::vector<std::string>& filenames) const S32 MAX_DIM = 256; if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) { - //todo: image not supported notification - LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL; + LLSD notif_args; + notif_args["REASON"] = LLImage::getLastError().c_str(); + LLNotificationsUtil::add("CannotUploadTexture", notif_args); + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)mType << ", " << notif_args["REASON"].asString() << LL_ENDL; return; } std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); if (cap_url.empty()) { - LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL; + LLSD args; + args["CAPABILITY"] = PROFILE_IMAGE_UPLOAD_CAP; + LLNotificationsUtil::add("RegionCapabilityRequestError", args); + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)mType << ", no cap found" << LL_ENDL; return; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ad7321ca4b..e5d703a6ee 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3024,6 +3024,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("InterestList"); + capabilityNames.append("InventoryCategoryThumbnailUpload"); + capabilityNames.append("InventoryItemThumbnailUpload"); capabilityNames.append("GetDisplayNames"); capabilityNames.append("GetExperiences"); capabilityNames.append("AgentExperiences"); |