| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/IO/FileIO.h>
- #include <AzCore/IO/SystemFile.h>
- #include <AzCore/RTTI/BehaviorContext.h>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzFramework/StringFunc/StringFunc.h>
- #include <aws/core/auth/AWSCredentials.h>
- #include <aws/s3/S3Client.h>
- #include <aws/s3/model/GetObjectRequest.h>
- #include <aws/s3/model/HeadObjectRequest.h>
- #include <fstream>
- #include <Framework/AWSApiRequestJob.h>
- #include <ResourceMapping/AWSResourceMappingBus.h>
- #include <ScriptCanvas/AWSScriptBehaviorS3.h>
- namespace AWSCore
- {
- void AWSScriptBehaviorS3::Reflect(AZ::ReflectContext* context)
- {
- if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
- {
- serializeContext->Class<AWSScriptBehaviorS3>()
- ->Version(0);
- }
- if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
- {
- behaviorContext->Class<AWSScriptBehaviorS3>(AWSScriptBehaviorS3Name)
- ->Attribute(AZ::Script::Attributes::Category, "AWSCore")
- ->Method("GetObject", &AWSScriptBehaviorS3::GetObject,
- {{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
- {"Object KeyName", "The object key."},
- {"Outfile Name", "Filename where the content will be saved."}}})
- ->Method("GetObjectRaw", &AWSScriptBehaviorS3::GetObjectRaw,
- {{{"Bucket Name", "The name of the bucket containing the object."},
- {"Object KeyName", "The object key."},
- {"Region Name", "The region of the bucket located in."},
- {"Outfile Name", "Filename where the content will be saved."}}})
- ->Method("HeadObject", &AWSScriptBehaviorS3::HeadObject,
- {{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
- {"Object KeyName", "The object key."}}})
- ->Method("HeadObjectRaw", &AWSScriptBehaviorS3::HeadObjectRaw,
- {{{"Bucket Name", "The name of the bucket containing the object."},
- {"Object KeyName", "The object key."},
- {"Region Name", "The region of the bucket located in."}}});
- behaviorContext->EBus<AWSScriptBehaviorS3NotificationBus>("AWSS3BehaviorNotificationBus")
- ->Attribute(AZ::Script::Attributes::Category, "AWSCore")
- ->Handler<AWSScriptBehaviorS3NotificationBusHandler>();
- }
- }
- void AWSScriptBehaviorS3::GetObject(
- const AZStd::string& bucketResourceKey, const AZStd::string& objectKey, const AZStd::string& outFile)
- {
- AZStd::string requestBucket = "";
- AWSResourceMappingRequestBus::BroadcastResult(requestBucket, &AWSResourceMappingRequests::GetResourceNameId, bucketResourceKey);
- AZStd::string requestRegion = "";
- AWSResourceMappingRequestBus::BroadcastResult(requestRegion, &AWSResourceMappingRequests::GetResourceRegion, bucketResourceKey);
- GetObjectRaw(requestBucket, objectKey, requestRegion, outFile);
- }
- void AWSScriptBehaviorS3::GetObjectRaw(
- const AZStd::string& bucket, const AZStd::string& objectKey, const AZStd::string& region, const AZStd::string& outFile)
- {
- AZStd::string normalizedOutFile = outFile;
- if (!ValidateGetObjectRequest(
- &AWSScriptBehaviorS3NotificationBus::Events::OnGetObjectError, bucket, objectKey, region, normalizedOutFile))
- {
- return;
- }
- using S3GetObjectRequestJob = AWS_API_REQUEST_JOB(S3, GetObject);
- S3GetObjectRequestJob::Config config(S3GetObjectRequestJob::GetDefaultConfig());
- config.region = region.c_str();
- auto job = S3GetObjectRequestJob::Create(
- [objectKey](S3GetObjectRequestJob*) // OnSuccess handler
- {
- AWSScriptBehaviorS3NotificationBus::Broadcast(
- &AWSScriptBehaviorS3NotificationBus::Events::OnGetObjectSuccess,
- AZStd::string::format("Object %s is downloaded.", objectKey.c_str()));
- },
- [](S3GetObjectRequestJob* job) // OnError handler
- {
- Aws::String errorMessage = job->error.GetMessage();
- AWSScriptBehaviorS3NotificationBus::Broadcast(
- &AWSScriptBehaviorS3NotificationBus::Events::OnGetObjectError, errorMessage.c_str());
- },
- &config);
- job->request.SetBucket(Aws::String(bucket.c_str()));
- job->request.SetKey(Aws::String(objectKey.c_str()));
- Aws::String outFileName(normalizedOutFile.c_str());
- job->request.SetResponseStreamFactory([outFileName]() {
- return Aws::New<Aws::FStream>(
- AWSScriptBehaviorS3Name, outFileName.c_str(),
- std::ios_base::out | std::ios_base::in | std::ios_base::binary | std::ios_base::trunc);
- });
- job->Start();
- }
- void AWSScriptBehaviorS3::HeadObject(const AZStd::string& bucketResourceKey, const AZStd::string& objectKey)
- {
- AZStd::string requestBucket = "";
- AWSResourceMappingRequestBus::BroadcastResult(requestBucket, &AWSResourceMappingRequests::GetResourceNameId, bucketResourceKey);
- AZStd::string requestRegion = "";
- AWSResourceMappingRequestBus::BroadcastResult(requestRegion, &AWSResourceMappingRequests::GetResourceRegion, bucketResourceKey);
- HeadObjectRaw(requestBucket, objectKey, requestRegion);
- }
- void AWSScriptBehaviorS3::HeadObjectRaw(
- const AZStd::string& bucket, const AZStd::string& objectKey, const AZStd::string& region)
- {
- if (!ValidateHeadObjectRequest(&AWSScriptBehaviorS3NotificationBus::Events::OnHeadObjectError, bucket, objectKey, region))
- {
- return;
- }
- using S3HeadObjectRequestJob = AWS_API_REQUEST_JOB(S3, HeadObject);
- S3HeadObjectRequestJob::Config config(S3HeadObjectRequestJob::GetDefaultConfig());
- config.region = region.c_str();
- auto job = S3HeadObjectRequestJob::Create(
- [objectKey](S3HeadObjectRequestJob*) // OnSuccess handler
- {
- AWSScriptBehaviorS3NotificationBus::Broadcast(
- &AWSScriptBehaviorS3NotificationBus::Events::OnHeadObjectSuccess,
- AZStd::string::format("Object %s is found.", objectKey.c_str()));
- },
- [](S3HeadObjectRequestJob* job) // OnError handler
- {
- Aws::String errorMessage = job->error.GetMessage();
- AWSScriptBehaviorS3NotificationBus::Broadcast(
- &AWSScriptBehaviorS3NotificationBus::Events::OnHeadObjectError, errorMessage.c_str());
- },
- &config);
- job->request.SetBucket(Aws::String(bucket.c_str()));
- job->request.SetKey(Aws::String(objectKey.c_str()));
- job->Start();
- }
- bool AWSScriptBehaviorS3::ValidateGetObjectRequest(S3NotificationFunctionType notificationFunc,
- const AZStd::string& bucket, const AZStd::string& objectKey, const AZStd::string& region, AZStd::string& outFile)
- {
- if (ValidateHeadObjectRequest(notificationFunc, bucket, objectKey, region))
- {
- AzFramework::StringFunc::Path::Normalize(outFile);
- if (outFile.empty())
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, OutputFileIsEmptyErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, OutputFileIsEmptyErrorMessage);
- return false;
- }
- char resolvedPath[AZ_MAX_PATH_LEN] = { 0 };
- if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(outFile.c_str(), resolvedPath, AZ_MAX_PATH_LEN))
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, OutputFileFailedToResolveErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, OutputFileFailedToResolveErrorMessage);
- return false;
- }
- outFile = resolvedPath;
- if (AZ::IO::FileIOBase::GetInstance()->IsDirectory(outFile.c_str()))
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, OutputFileIsDirectoryErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, OutputFileIsDirectoryErrorMessage);
- return false;
- }
- auto lastSeparator = outFile.find_last_of(AZ_CORRECT_FILESYSTEM_SEPARATOR);
- if (lastSeparator != AZStd::string::npos)
- {
- auto parentPath = outFile.substr(0, lastSeparator);
- if (!AZ::IO::FileIOBase::GetInstance()->Exists(parentPath.c_str()))
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, OutputFileDirectoryNotExistErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, OutputFileDirectoryNotExistErrorMessage);
- return false;
- }
- }
- if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(outFile.c_str()))
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, OutputFileIsReadOnlyErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, OutputFileIsReadOnlyErrorMessage);
- return false;
- }
- return true;
- }
- return false;
- }
- bool AWSScriptBehaviorS3::ValidateHeadObjectRequest(S3NotificationFunctionType notificationFunc,
- const AZStd::string& bucket, const AZStd::string& objectKey, const AZStd::string& region)
- {
- if (bucket.empty())
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, BucketNameIsEmptyErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, BucketNameIsEmptyErrorMessage);
- return false;
- }
- if (objectKey.empty())
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, ObjectKeyNameIsEmptyErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, ObjectKeyNameIsEmptyErrorMessage);
- return false;
- }
- if (region.empty())
- {
- AZ_Warning(AWSScriptBehaviorS3Name, false, RegionNameIsEmptyErrorMessage);
- AWSScriptBehaviorS3NotificationBus::Broadcast(notificationFunc, RegionNameIsEmptyErrorMessage);
- return false;
- }
- return true;
- }
- }
|