Skip to content

Commit e4d52fe

Browse files
committed
Add AWS S3 IO handler
1 parent f2d6097 commit e4d52fe

File tree

5 files changed

+174
-1
lines changed

5 files changed

+174
-1
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ install:
3535
# Install mamba
3636
- conda install mamba -c conda-forge
3737
# Install host dependencies
38-
- mamba install openimageio=2.1.10 libsndfile=1.0.28 zlib=1.2.11 highfive=2.1.1 blosc gdal nlohmann_json google-cloud-cpp=1.19.0 xtensor=0.21.9 cpp-filesystem -c conda-forge
38+
- mamba install openimageio=2.1.10 libsndfile=1.0.28 zlib=1.2.11 highfive=2.1.1 blosc gdal nlohmann_json google-cloud-cpp=1.19.0 aws-sdk-cpp xtensor=0.21.9 cpp-filesystem -c conda-forge
3939
- mamba install ffmpeg=4.1.3 -c conda-forge # openimageio is missing ffmpedg as a runtime requirement
4040
# Install build dependencies
4141
- mamba install cmake -c conda-forge

CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,28 @@ else()
212212
message(WARNING "Google Cloud Storage not found - install google-cloud-cpp for GCS IO handler support")
213213
endif()
214214

215+
if (NOT DEFINED BUILD_SHARED_LIBS)
216+
set (BUILD_SHARED_LIBS ON)
217+
find_package(AWSSDK REQUIRED COMPONENTS s3)
218+
unset (BUILD_SHARED_LIBS)
219+
else ()
220+
find_package(AWSSDK REQUIRED COMPONENTS s3)
221+
endif ()
222+
message(STATUS "Trying to find AWS SDK for AWS S3 IO handler support")
223+
if(${AWSSDK_FOUND})
224+
message(STATUS "AWSSDK ${AWSSDK_VERSION} found, AWS S3 IO handler support enabled")
225+
target_include_directories(xtensor-io
226+
INTERFACE
227+
${AWSSDK_INCLUDE_DIRS}
228+
)
229+
target_link_libraries(xtensor-io
230+
INTERFACE
231+
${AWSSDK_LINK_LIBRARIES}
232+
)
233+
else()
234+
message(WARNING "AWSSDK not found - install aws-sdk-cpp for AWS S3 IO handler support")
235+
endif()
236+
215237
if(DOWNLOAD_GTEST OR GTEST_SRC_DIR)
216238
set(BUILD_TESTS ON)
217239
endif()
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#ifndef XTENSOR_IO_AWS_HANDLER_HPP
2+
#define XTENSOR_IO_AWS_HANDLER_HPP
3+
4+
#include "xtensor/xarray.hpp"
5+
#include "xtensor/xexpression.hpp"
6+
#include "xfile_array.hpp"
7+
#include <aws/core/Aws.h>
8+
#include <aws/s3/S3Client.h>
9+
#include <aws/s3/model/GetObjectRequest.h>
10+
#include <aws/s3/model/PutObjectRequest.h>
11+
12+
namespace xt
13+
{
14+
struct xio_aws_config
15+
{
16+
Aws::S3::S3Client client;
17+
Aws::String bucket;
18+
};
19+
20+
template <class C>
21+
class xio_aws_handler
22+
{
23+
public:
24+
using io_config = xio_aws_config;
25+
26+
xio_aws_handler();
27+
28+
template <class E>
29+
void write(const xexpression<E>& expression, const Aws::String& path, xfile_dirty dirty);
30+
31+
template <class ET>
32+
void read(ET& array, const Aws::String& path);
33+
34+
void configure(const C& format_config, const xio_aws_config& io_config);
35+
void configure_io(const xio_aws_config& io_config);
36+
37+
private:
38+
39+
C m_format_config;
40+
Aws::S3::S3Client m_client;
41+
Aws::String m_bucket;
42+
};
43+
44+
template <class C>
45+
xio_aws_handler<C>::xio_aws_handler()
46+
{
47+
}
48+
49+
template <class C>
50+
template <class E>
51+
inline void xio_aws_handler<C>::write(const xexpression<E>& expression, const Aws::String& path, xfile_dirty dirty)
52+
{
53+
if (m_format_config.will_dump(dirty))
54+
{
55+
Aws::S3::Model::PutObjectRequest request;
56+
request.SetBucket(m_bucket);
57+
request.SetKey(path);
58+
59+
std::shared_ptr<Aws::IOStream> writer = Aws::MakeShared<Aws::FStream>("SampleAllocationTag", path.c_str(), std::ios_base::in | std::ios_base::binary);
60+
dump_file(writer, expression, m_format_config);
61+
62+
request.SetBody(writer);
63+
64+
Aws::S3::Model::PutObjectOutcome outcome = m_client.PutObject(request);
65+
66+
if (!outcome.IsSuccess())
67+
{
68+
auto err = outcome.GetError();
69+
XTENSOR_THROW(std::runtime_error, std::string("Error: PutObject: ") + err.GetExceptionName().c_str() + ": " + err.GetMessage().c_str());
70+
}
71+
}
72+
}
73+
74+
template <class C>
75+
template <class ET>
76+
inline void xio_aws_handler<C>::read(ET& array, const Aws::String& path)
77+
{
78+
Aws::S3::Model::GetObjectRequest request;
79+
request.SetBucket(m_bucket);
80+
request.SetKey(path);
81+
82+
Aws::S3::Model::GetObjectOutcome outcome = m_client.GetObject(request);
83+
84+
if (!outcome.IsSuccess())
85+
{
86+
auto err = outcome.GetError();
87+
XTENSOR_THROW(std::runtime_error, std::string("Error: GetObject: ") + err.GetExceptionName().c_str() + ": " + err.GetMessage().c_str());
88+
}
89+
90+
auto& reader = outcome.GetResultWithOwnership().GetBody();
91+
load_file<ET>(reader, array, m_format_config);
92+
}
93+
94+
template <class C>
95+
inline void xio_aws_handler<C>::configure(const C& format_config, const xio_aws_config& io_config)
96+
{
97+
m_format_config = format_config;
98+
m_client = io_config.client;
99+
m_bucket = io_config.bucket;
100+
}
101+
102+
template <class C>
103+
inline void xio_aws_handler<C>::configure_io(const xio_aws_config& io_config)
104+
{
105+
m_client = io_config.client;
106+
m_bucket = io_config.bucket;
107+
}
108+
109+
}
110+
111+
#endif

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ set(XTENSOR_IO_TESTS
8484
test_xio_gzip.cpp
8585
test_xio_binary.cpp
8686
test_xio_gcs_handler.cpp
87+
test_xio_aws_handler.cpp
8788
)
8889

8990
set(XTENSOR_IO_HO_TESTS

test/test_xio_aws_handler.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/***************************************************************************
2+
* Copyright (c) Wolf Vollprecht, Sylvain Corlay and Johan Mabille *
3+
* Copyright (c) QuantStack *
4+
* *
5+
* Distributed under the terms of the BSD 3-Clause License. *
6+
* *
7+
* The full license is in the file LICENSE, distributed with this software. *
8+
****************************************************************************/
9+
10+
#include <cstdint>
11+
#include <sstream>
12+
#include <exception>
13+
14+
#include "gtest/gtest.h"
15+
#include "xtensor/xview.hpp"
16+
#include "xtensor-io/xio_binary.hpp"
17+
#include "xtensor-io/xio_aws_handler.hpp"
18+
19+
namespace xt
20+
{
21+
TEST(xio_aws_handler, read)
22+
{
23+
Aws::SDKOptions options;
24+
Aws::InitAPI(options);
25+
26+
xio_aws_handler<xio_binary_config> h;
27+
28+
Aws::S3::S3Client client;
29+
30+
xio_aws_config c = {client, "elevation-tiles-prod"};
31+
h.configure_io(c);
32+
xarray<char> a0;
33+
h.read(a0, "main.js");
34+
xarray<char> a1 = {'/', '*', 'j', 's', 'l', 'i', 'n', 't', ' ', 'b', 'r' ,'o', 'w', 's', 'e', 'r', ':', ' ', 't', 'r', 'u', 'e', '*', '/'};
35+
EXPECT_TRUE(xt::all(xt::equal(xt::view(a0, xt::range(0, 24)), a1)));
36+
37+
Aws::ShutdownAPI(options);
38+
}
39+
}

0 commit comments

Comments
 (0)