AlexaClientSDK  1.26.0
A cross-platform, modular SDK for interacting with the Alexa Voice Service
DefaultAttachmentReader.h
Go to the documentation of this file.
1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  * http://aws.amazon.com/apache2.0/
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 #ifndef ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_ATTACHMENT_DEFAULTATTACHMENTREADER_H_
17 #define ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_ATTACHMENT_DEFAULTATTACHMENTREADER_H_
18 
21 #include "AttachmentReader.h"
22 
23 namespace alexaClientSDK {
24 namespace avsCommon {
25 namespace avs {
26 namespace attachment {
27 
33 template <typename SDSType>
35 public:
49  static std::unique_ptr<AttachmentReader> create(
50  typename SDSType::Reader::Policy policy,
51  std::shared_ptr<SDSType> sds,
52  typename SDSType::Index offset = 0,
53  typename SDSType::Reader::Reference reference = SDSType::Reader::Reference::ABSOLUTE,
54  bool resetOnOverrun = false);
55 
60 
63  std::size_t read(
64  void* buf,
65  std::size_t numBytes,
66  ReadStatus* readStatus,
67  std::chrono::milliseconds timeoutMs = std::chrono::milliseconds(0)) override;
68 
70 
71  bool seek(uint64_t offset) override;
72 
73  uint64_t getNumUnreadBytes() override;
74 
76 private:
85  DefaultAttachmentReader(typename SDSType::Reader::Policy policy, std::shared_ptr<SDSType> sds, bool resetOnOverrun);
86 
88  static const std::string TAG;
89 
91  std::shared_ptr<typename SDSType::Reader> m_reader;
92 
93  // On @c read overrun, Whether to close the attachment, or reset it to catch up with the write
94  bool m_resetOnOverrun;
95 };
96 
97 template <typename SDSType>
98 const std::string DefaultAttachmentReader<SDSType>::TAG = "DefaultAttachmentReader";
99 
100 template <typename SDSType>
101 std::unique_ptr<AttachmentReader> DefaultAttachmentReader<SDSType>::create(
102  typename SDSType::Reader::Policy policy,
103  std::shared_ptr<SDSType> sds,
104  typename SDSType::Index offset,
105  typename SDSType::Reader::Reference reference,
106  bool resetOnOverrun) {
107  auto reader =
108  std::unique_ptr<DefaultAttachmentReader>(new DefaultAttachmentReader<SDSType>(policy, sds, resetOnOverrun));
109  if (!reader->m_reader) {
110  ACSDK_ERROR(utils::logger::LogEntry(TAG, "createFailed").d("reason", "object not fully created"));
111  return nullptr;
112  }
113 
114  if (!reader->m_reader->seek(offset, reference)) {
115  ACSDK_ERROR(utils::logger::LogEntry(TAG, "ConstructorFailed").d("reason", "seek failed"));
116  return nullptr;
117  }
118 
119  return std::unique_ptr<AttachmentReader>(reader.release());
120 }
121 
122 template <typename SDSType>
124  close();
125 }
126 
127 template <typename SDSType>
129  void* buf,
130  std::size_t numBytes,
131  AttachmentReader::ReadStatus* readStatus,
132  std::chrono::milliseconds timeoutMs) {
133  if (!readStatus) {
134  ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "read status is nullptr"));
135  return 0;
136  }
137 
138  if (!buf) {
139  ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "buf is nullptr"));
140  *readStatus = ReadStatus::ERROR_INTERNAL;
141  return 0;
142  }
143 
144  if (!m_reader) {
145  ACSDK_INFO(utils::logger::LogEntry(TAG, "readFailed").d("reason", "closed or uninitialized SDS"));
146  *readStatus = ReadStatus::CLOSED;
147  return 0;
148  }
149 
150  if (timeoutMs.count() < 0) {
151  ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "negative timeout"));
152  *readStatus = ReadStatus::ERROR_INTERNAL;
153  return 0;
154  }
155 
156  *readStatus = ReadStatus::OK;
157 
158  if (0 == numBytes) {
159  return 0;
160  }
161 
162  const auto wordSize = m_reader->getWordSize();
163  if (numBytes < wordSize) {
164  ACSDK_ERROR(
165  utils::logger::LogEntry(TAG, "readFailed").d("reason", "bytes requested smaller than SDS word size"));
167  return 0;
168  }
169 
170  std::size_t bytesRead = 0;
171  const auto numWords = numBytes / wordSize;
172 
173  const auto readResult = m_reader->read(buf, numWords, timeoutMs);
174 
175  /*
176  * Convert SDS return code accordingly:
177  *
178  * < 0 : Error code.
179  * 0 : The underlying SDS is closed.
180  * > 0 : The number of bytes read.
181  */
182 
183  if (readResult < 0) {
184  switch (readResult) {
185  // This means the writer has overwritten the reader.
186  case SDSType::Reader::Error::OVERRUN:
187  if (m_resetOnOverrun) {
188  // An attachment's read position will be reset to current writer position.
189  // Subsequent reads will deliver data from current writer position onward.
190  *readStatus = ReadStatus::OK_OVERRUN_RESET;
191  ACSDK_DEBUG5(utils::logger::LogEntry(TAG, "readFailed").d("reason", "memory overrun by writer"));
192  m_reader->seek(0, SDSType::Reader::Reference::BEFORE_WRITER);
193  } else {
194  // An attachment cannot recover from this.
195  *readStatus = ReadStatus::ERROR_OVERRUN;
196  ACSDK_ERROR(utils::logger::LogEntry(TAG, "readFailed").d("reason", "memory overrun by writer"));
197  close();
198  }
199  break;
200 
201  // This means there is still an active writer, but no data. A read would block if the policy was blocking.
202  case SDSType::Reader::Error::WOULDBLOCK:
203  *readStatus = ReadStatus::OK_WOULDBLOCK;
204  break;
205 
206  // This means there is still an active writer, but no data. A read call timed out waiting for data.
207  case SDSType::Reader::Error::TIMEDOUT:
208  *readStatus = ReadStatus::OK_TIMEDOUT;
209  break;
210  }
211 
212  // If the status was not updated, then there's an error code from SDS we may not be handling.
213  if (ReadStatus::OK == *readStatus) {
214  ACSDK_ERROR(
215  utils::logger::LogEntry(TAG, "readFailed").d("reason", "unhandled error code").d("code", readResult));
216  *readStatus = ReadStatus::ERROR_INTERNAL;
217  }
218 
219  } else if (0 == readResult) {
220  *readStatus = ReadStatus::CLOSED;
221  ACSDK_DEBUG0(utils::logger::LogEntry(TAG, "readFailed").d("reason", "SDS is closed"));
222  } else {
223  bytesRead = static_cast<size_t>(readResult) * wordSize;
224  }
225 
226  return bytesRead;
227 }
228 
229 template <typename SDSType>
231  if (m_reader) {
232  switch (closePoint) {
234  m_reader->close();
235  return;
237  m_reader->close(0, SDSType::Reader::Reference::BEFORE_WRITER);
238  return;
239  }
240  }
241 }
242 
243 template <typename SDSType>
245  if (m_reader) {
246  return m_reader->seek(offset);
247  }
248  return false;
249 }
250 
251 template <typename SDSType>
253  if (m_reader) {
254  return m_reader->tell(SDSType::Reader::Reference::BEFORE_WRITER);
255  }
256 
257  ACSDK_ERROR(utils::logger::LogEntry(TAG, "getNumUnreadBytesFailed").d("reason", "noReader"));
258  return 0;
259 }
260 
261 template <typename SDSType>
263  typename SDSType::Reader::Policy policy,
264  std::shared_ptr<SDSType> sds,
265  bool resetOnOverrun) :
266  m_resetOnOverrun{resetOnOverrun} {
267  if (!sds) {
268  ACSDK_ERROR(utils::logger::LogEntry(TAG, "ConstructorFailed").d("reason", "SDS parameter is nullptr"));
269  return;
270  }
271 
272  m_reader = sds->createReader(policy);
273 
274  if (!m_reader) {
275  ACSDK_ERROR(utils::logger::LogEntry(TAG, "ConstructorFailed").d("reason", "could not create an SDS reader"));
276  return;
277  }
278 }
279 
280 } // namespace attachment
281 } // namespace avs
282 } // namespace avsCommon
283 } // namespace alexaClientSDK
284 
285 #endif // ALEXA_CLIENT_SDK_AVSCOMMON_AVS_INCLUDE_AVSCOMMON_AVS_ATTACHMENT_DEFAULTATTACHMENTREADER_H_
bool seek(uint64_t offset) override
Definition: DefaultAttachmentReader.h:244
Reference
Specifies a reference to measure seek()/tell()/close() offsets against.
Definition: Reader.h:51
On a request for n bytes, less than n bytes were available on a blocking read.
#define ACSDK_DEBUG5(entry)
Definition: Logger.h:506
uint64_t getNumUnreadBytes() override
Definition: DefaultAttachmentReader.h:252
static std::unique_ptr< AttachmentReader > create(typename SDSType::Reader::Policy policy, std::shared_ptr< SDSType > sds, typename SDSType::Index offset=0, typename SDSType::Reader::Reference reference=SDSType::Reader::Reference::ABSOLUTE, bool resetOnOverrun=false)
Definition: DefaultAttachmentReader.h:101
~DefaultAttachmentReader()
Definition: DefaultAttachmentReader.h:123
Stop returning data when all of the data in the buffer at the time close() was called has been read...
#define ACSDK_ERROR(entry)
Definition: Logger.h:580
Index
Index used for setting access.
Definition: StateReportGeneratorTest.cpp:41
Whether or not curl logs should be emitted.
Definition: AVSConnectionManager.h:36
On a request for n bytes, less than n bytes were available on a non-blocking read.
std::size_t read(void *buf, std::size_t numBytes, ReadStatus *readStatus, std::chrono::milliseconds timeoutMs=std::chrono::milliseconds(0)) override
Definition: DefaultAttachmentReader.h:128
The underlying data representation is no longer readable.
#define ACSDK_INFO(entry)
Definition: Logger.h:564
The number of bytes in the request is smaller than the word-size of the underlying data representatio...
The writer has corrupted the reader data. The attachment is no longer valid.
ClosePoint
An enum class to indicate when the read() function should stop returning data after a call to close()...
Definition: AttachmentReader.h:59
void close(ClosePoint closePoint=ClosePoint::AFTER_DRAINING_CURRENT_BUFFER) override
Definition: DefaultAttachmentReader.h:230
#define ACSDK_DEBUG0(entry)
Definition: Logger.h:546
LogEntry is used to compile the log entry text to log via Logger.
Definition: LogEntry.h:32

AlexaClientSDK 1.26.0 - Copyright 2016-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0