userver: /data/code/userver/libraries/sqs/src/sqs/json_client.cpp Source File
Loading...
Searching...
No Matches
json_client.cpp
1#include <userver/sqs/json_client.hpp>
2
3#include <aws/core/http/HttpTypes.h>
4#include <aws/core/utils/Array.h>
5#include <aws/core/utils/StringUtils.h>
6#include <aws/core/utils/json/JsonSerializer.h>
7#include <aws/sqs/SQSErrors.h>
8#include <aws/sqs/model/AddPermissionRequest.h>
9#include <aws/sqs/model/ChangeMessageVisibilityBatchRequest.h>
10#include <aws/sqs/model/ChangeMessageVisibilityRequest.h>
11#include <aws/sqs/model/CreateQueueRequest.h>
12#include <aws/sqs/model/DeleteMessageBatchRequest.h>
13#include <aws/sqs/model/DeleteMessageRequest.h>
14#include <aws/sqs/model/DeleteQueueRequest.h>
15#include <aws/sqs/model/GetQueueAttributesRequest.h>
16#include <aws/sqs/model/GetQueueUrlRequest.h>
17#include <aws/sqs/model/ListDeadLetterSourceQueuesRequest.h>
18#include <aws/sqs/model/ListQueueTagsRequest.h>
19#include <aws/sqs/model/ListQueuesRequest.h>
20#include <aws/sqs/model/MessageSystemAttributeNameForSends.h>
21#include <aws/sqs/model/PurgeQueueRequest.h>
22#include <aws/sqs/model/ReceiveMessageRequest.h>
23#include <aws/sqs/model/RemovePermissionRequest.h>
24#include <aws/sqs/model/SendMessageBatchRequest.h>
25#include <aws/sqs/model/SendMessageRequest.h>
26#include <aws/sqs/model/SetQueueAttributesRequest.h>
27#include <aws/sqs/model/TagQueueRequest.h>
28#include <aws/sqs/model/UntagQueueRequest.h>
29
30#include <userver/clients/http/client.hpp>
31#include <userver/clients/http/request.hpp>
32#include <userver/clients/http/response.hpp>
33#include <userver/crypto/aws.hpp>
34#include <userver/crypto/base64.hpp>
35#include <userver/http/common_headers.hpp>
36#include <userver/http/predefined_header.hpp>
37#include <userver/http/url.hpp>
38#include <userver/logging/log.hpp>
39#include <userver/logging/log_extra.hpp>
40#include <userver/tracing/tags.hpp>
41#include <userver/utils/assert.hpp>
42#include <userver/utils/string_literal.hpp>
43#include <userver/utils/text.hpp>
44#include <userver/utils/uuid4.hpp>
45#include <userver/utils/zstring_view.hpp>
46
47#include <algorithm>
48#include <exception>
49#include <string>
50#include <string_view>
51#include <utility>
52#include <vector>
53
54USERVER_NAMESPACE_BEGIN
55
56namespace sqs {
57
58// NOLINTNEXTLINE(google-build-using-namespace)
59using namespace Aws::SQS::Model;
60
61namespace {
62
63constexpr auto kContentTypeValue = "application/x-amz-json-1.0";
64constexpr auto kAmzSdkRequestValue = "attempt=1";
65constexpr auto kXAmzAPIVersionValue = "2012-11-05";
66constexpr auto kAuthorizationOverrideDate = "20150830T123600Z";
67constexpr auto kServiceName = "sqs";
68
69constexpr http::headers::PredefinedHeader kAmzSdkRequestHeader{"amz-sdk-request"};
70constexpr http::headers::PredefinedHeader kXAmzAPIVersionHeader{"x-amz-api-version"};
71constexpr http::headers::PredefinedHeader kXYaCloudSubjectTokenHeader{"X-YaCloud-SubjectToken"};
72constexpr http::headers::PredefinedHeader kAmzSdkInvocationIdHeader{"amz-sdk-invocation-id"};
73constexpr http::headers::PredefinedHeader kXAmzDateHeader{"x-amz-date"};
74constexpr http::headers::PredefinedHeader kXAmzSecurityTokenHeader{"x-amz-security-token"};
75constexpr http::headers::PredefinedHeader kXAmzTargetHeader{"x-amz-target"};
76constexpr http::headers::PredefinedHeader kXAmznQueryModeHeader{"x-amzn-query-mode"};
77
78constexpr utils::StringLiteral kTracingTypeRequest = "request";
79constexpr utils::StringLiteral kTracingBody = "body";
80constexpr utils::StringLiteral kTracingUri = "uri";
81constexpr utils::StringLiteral kTracingRequestBodyLength = "request_body_length";
82constexpr utils::StringLiteral kHttpMethodPost = "POST";
83constexpr std::string_view kMaskedHeaderValue = "***";
84
85bool IsSensitiveHeader(std::string_view header_name) {
86 const auto lower = utils::text::ToLower(header_name);
87 return lower == "authorization" || lower == "x-yacloud-subjecttoken" || lower == "x-amz-security-token";
88}
89
90std::string FormatRequestHeaders(const clients::http::Headers& headers) {
91 std::vector<std::pair<std::string_view, std::string_view>> sorted_headers;
92 sorted_headers.reserve(headers.size());
93 for (const auto& [name, value] : headers) {
94 sorted_headers.emplace_back(name, value);
95 }
96 std::ranges::sort(sorted_headers, [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; });
97
98 std::string result;
99 for (const auto& [name, value] : sorted_headers) {
100 result.append(name);
101 result.append(": ");
102 result.append(IsSensitiveHeader(name) ? kMaskedHeaderValue : value);
103 result.push_back('\n');
104 }
105 return result;
106}
107
108void LogRequest(
109 const char* operation_name,
110 std::string_view url,
111 const clients::http::Headers& headers,
112 std::string_view body
113) {
114 LOG_INFO() << [&](auto& logger) {
115 logging::LogExtra log_extra{
116 {tracing::kHttpMetaType, operation_name},
117 {tracing::kType, kTracingTypeRequest},
118 {kTracingRequestBodyLength, static_cast<unsigned long long>(body.size())},
119 {kTracingBody, body},
120 {kTracingUri, url},
121 {tracing::kHttpMethod, kHttpMethodPost},
122 };
123 log_extra.Extend("request_headers", FormatRequestHeaders(headers));
124 logger.Format("start SQS {} {}", kHttpMethodPost, operation_name) << log_extra;
125 };
126}
127
128// SigV4 signs the Host header including the port when the URL specifies one.
129// ExtractHostnameView returns host only, so the port is taken from the URL
130// immediately after that hostname substring.
131std::string MakeHostHeaderValue(std::string_view url) {
132 const auto host = http::ExtractHostnameView(url);
133 const auto after_host = static_cast<std::size_t>(host.data() + host.size() - url.data());
134 if (after_host >= url.size() || url[after_host] != ':') {
135 return std::string{host};
136 }
137
138 auto port = url.substr(after_host);
139 const auto port_end = port.find_first_of("/?#");
140 if (port_end != std::string_view::npos) {
141 port = port.substr(0, port_end);
142 }
143
144 std::string result;
145 result.reserve(host.size() + port.size());
146 result.append(host);
147 result.append(port);
148 return result;
149}
150
151std::string CanonicalUri(std::string_view url) {
152 auto path = http::ExtractPathView(url);
153 if (path.empty()) {
154 path = "/";
155 }
156 return http::EncodeS3Key(path);
157}
158
159std::string EncodeBinary(const Aws::Utils::ByteBuffer& buffer) {
160 return crypto::base64::Base64Encode(std::string_view{
161 reinterpret_cast<const char*>(buffer.GetUnderlyingData()),
162 buffer.GetLength()
163 });
164}
165
166Aws::Utils::ByteBuffer DecodeBinary(const Aws::String& value) {
167 const auto decoded = crypto::base64::Base64Decode(std::string_view{value.c_str(), value.size()});
168 return Aws::Utils::ByteBuffer{reinterpret_cast<const unsigned char*>(decoded.data()), decoded.size()};
169}
170
171template <typename T>
172Aws::Utils::Json::JsonValue BuildAttributeValueJson(const T& attr_value) {
173 Aws::Utils::Json::JsonValue attr_value_json;
174 attr_value_json.WithString("DataType", attr_value.GetDataType());
175
176 if (attr_value.StringValueHasBeenSet()) {
177 attr_value_json.WithString("StringValue", attr_value.GetStringValue());
178 }
179
180 if (attr_value.StringListValuesHasBeenSet()) {
181 Aws::Vector<Aws::Utils::Json::JsonValue> string_list_values_vector;
182 string_list_values_vector.reserve(attr_value.GetStringListValues().size());
183 for (const auto& string_value : attr_value.GetStringListValues()) {
184 Aws::Utils::Json::JsonValue string_value_json;
185 string_value_json.AsString(string_value);
186 string_list_values_vector.push_back(string_value_json);
187 }
188 Aws::Utils::Array<Aws::Utils::Json::JsonValue> string_list_values_array(string_list_values_vector.size());
189 for (size_t i = 0; i < string_list_values_vector.size(); ++i) {
190 string_list_values_array[i] = string_list_values_vector[i];
191 }
192 attr_value_json.WithArray("StringListValues", string_list_values_array);
193 }
194
195 if (attr_value.BinaryValueHasBeenSet()) {
196 const auto& binary_value = attr_value.GetBinaryValue();
197 attr_value_json.WithString("BinaryValue", Aws::String{EncodeBinary(binary_value)});
198 }
199
200 if (attr_value.BinaryListValuesHasBeenSet()) {
201 Aws::Vector<Aws::Utils::Json::JsonValue> binary_list_values_vector;
202 binary_list_values_vector.reserve(attr_value.GetBinaryListValues().size());
203 for (const auto& binary_value : attr_value.GetBinaryListValues()) {
204 const auto encoded = EncodeBinary(binary_value);
205 Aws::Utils::Json::JsonValue binary_value_json;
206 binary_value_json.AsString(Aws::String{encoded});
207 binary_list_values_vector.push_back(binary_value_json);
208 }
209 Aws::Utils::Array<Aws::Utils::Json::JsonValue> binary_list_values_array(binary_list_values_vector.size());
210 for (size_t i = 0; i < binary_list_values_vector.size(); ++i) {
211 binary_list_values_array[i] = binary_list_values_vector[i];
212 }
213 attr_value_json.WithArray("BinaryListValues", binary_list_values_array);
214 }
215
216 return attr_value_json;
217}
218
219Aws::Utils::Json::JsonValue BuildMessageAttributesJson(
220 const Aws::Map<Aws::String, MessageAttributeValue>& message_attributes
221) {
222 Aws::Utils::Json::JsonValue message_attributes_json;
223 for (const auto& attr_pair : message_attributes) {
224 message_attributes_json.WithObject(attr_pair.first, BuildAttributeValueJson(attr_pair.second));
225 }
226 return message_attributes_json;
227}
228
229Aws::Utils::Json::JsonValue BuildMessageSystemAttributesJson(
230 const Aws::Map<MessageSystemAttributeNameForSends, MessageSystemAttributeValue>& message_system_attributes
231) {
232 Aws::Utils::Json::JsonValue message_system_attributes_json;
233 for (const auto& attr_pair : message_system_attributes) {
234 Aws::String attr_name =
235 MessageSystemAttributeNameForSendsMapper::GetNameForMessageSystemAttributeNameForSends(attr_pair.first);
236 message_system_attributes_json.WithObject(attr_name, BuildAttributeValueJson(attr_pair.second));
237 }
238 return message_system_attributes_json;
239}
240
241Aws::Utils::Json::JsonValue BuildQueueAttributesJson(const Aws::Map<QueueAttributeName, Aws::String>& attributes) {
242 Aws::Utils::Json::JsonValue attributes_json;
243 for (const auto& attr_pair : attributes) {
244 attributes_json
245 .WithString(QueueAttributeNameMapper::GetNameForQueueAttributeName(attr_pair.first), attr_pair.second);
246 }
247 return attributes_json;
248}
249
250Aws::Utils::Json::JsonValue BuildTagsJson(const Aws::Map<Aws::String, Aws::String>& tags) {
251 Aws::Utils::Json::JsonValue tags_json;
252 for (const auto& tag_pair : tags) {
253 tags_json.WithString(tag_pair.first, tag_pair.second);
254 }
255 return tags_json;
256}
257
258template <typename Container>
259Aws::Utils::Array<Aws::Utils::Json::JsonValue> BuildStringArrayJson(const Container& strings) {
260 Aws::Utils::Array<Aws::Utils::Json::JsonValue> array(strings.size());
261 for (size_t i = 0; i < strings.size(); ++i) {
262 array[i].AsString(strings[i]);
263 }
264 return array;
265}
266
267Aws::String JsonViewToString(const Aws::Utils::Json::JsonView& value_view) {
268 if (value_view.IsString()) {
269 return value_view.AsString();
270 }
271 if (value_view.IsIntegerType()) {
272 return Aws::Utils::StringUtils::to_string(value_view.AsInteger());
273 }
274 if (value_view.IsFloatingPointType()) {
275 return Aws::Utils::StringUtils::to_string(value_view.AsDouble());
276 }
277 if (value_view.IsBool()) {
278 return value_view.AsBool() ? "true" : "false";
279 }
280 return {};
281}
282
283bool JsonViewIsScalar(const Aws::Utils::Json::JsonView& value_view) {
284 return value_view.IsString() || value_view.IsIntegerType() || value_view.IsFloatingPointType() ||
285 value_view.IsBool();
286}
287
288Aws::String ExtractErrorMessage(const Aws::Utils::Json::JsonView& error_view) {
289 Aws::Vector<Aws::String> parts;
290
291 if (error_view.KeyExists("Code")) {
292 parts.push_back(error_view.GetString("Code"));
293 }
294 if (error_view.KeyExists("__type")) {
295 parts.push_back(error_view.GetString("__type"));
296 }
297 if (error_view.KeyExists("Message")) {
298 parts.push_back(error_view.GetString("Message"));
299 }
300 if (error_view.KeyExists("message")) {
301 parts.push_back(error_view.GetString("message"));
302 }
303
304 if (parts.empty()) {
305 return {};
306 }
307
308 Aws::String result = parts.front();
309 for (size_t i = 1; i < parts.size(); ++i) {
310 result += ": ";
311 result += parts[i];
312 }
313 return result;
314}
315
316Aws::String ExtractErrorMessageFromBody(utils::zstring_view body_string) {
317 if (body_string.empty()) {
318 return {};
319 }
320
321 Aws::Utils::Json::JsonValue response_json(Aws::String{body_string.c_str(), body_string.size()});
322 if (!response_json.WasParseSuccessful()) {
323 return Aws::String{body_string.c_str(), body_string.size()};
324 }
325
326 auto response_view = response_json.View();
327 if (response_view.KeyExists("Error") && response_view.GetObject("Error").IsObject()) {
328 const auto error_message = ExtractErrorMessage(response_view.GetObject("Error"));
329 if (!error_message.empty()) {
330 return error_message;
331 }
332 }
333
334 return ExtractErrorMessage(response_view);
335}
336
337Aws::Map<QueueAttributeName, Aws::String> ParseQueueAttributesJson(const Aws::Utils::Json::JsonView& attributes_view) {
338 Aws::Map<QueueAttributeName, Aws::String> attributes;
339 for (const auto& [attribute_name, attribute_value] : attributes_view.GetAllObjects()) {
340 if (JsonViewIsScalar(attribute_value)) {
341 attributes[QueueAttributeNameMapper::GetQueueAttributeNameForName(attribute_name
342 )] = JsonViewToString(attribute_value);
343 }
344 }
345 return attributes;
346}
347
348Aws::Map<Aws::String, Aws::String> ParseTagsJson(const Aws::Utils::Json::JsonView& tags_view) {
349 Aws::Map<Aws::String, Aws::String> tags;
350 for (const auto& [tag_key, tag_value] : tags_view.GetAllObjects()) {
351 if (tag_value.IsString()) {
352 tags[tag_key] = tag_value.AsString();
353 }
354 }
355 return tags;
356}
357
358Message ParseMessageJson(const Aws::Utils::Json::JsonView& message_view) {
359 Message message;
360 message.WithBody(message_view.GetString("Body"))
361 .WithMessageId(message_view.GetString("MessageId"))
362 .WithReceiptHandle(message_view.GetString("ReceiptHandle"))
363 .WithMD5OfBody(message_view.GetString("MD5OfBody"));
364
365 if (message_view.KeyExists("MD5OfMessageAttributes")) {
366 message.WithMD5OfMessageAttributes(message_view.GetString("MD5OfMessageAttributes"));
367 }
368
369 if (message_view.KeyExists("Attributes")) {
370 const auto& message_attributes = message_view.GetObject("Attributes");
371 Aws::Map<MessageSystemAttributeName, Aws::String> message_system_attributes_map;
372 for (const auto& [attribute_name, attribute_value] : message_attributes.GetAllObjects()) {
373 auto message_attribute =
374 MessageSystemAttributeNameMapper::GetMessageSystemAttributeNameForName(attribute_name);
375 if (JsonViewIsScalar(attribute_value)) {
376 message_system_attributes_map[message_attribute] = JsonViewToString(attribute_value);
377 }
378 }
379 message.WithAttributes(message_system_attributes_map);
380 }
381
382 if (message_view.KeyExists("MessageAttributes")) {
383 const auto& message_attributes = message_view.GetObject("MessageAttributes");
384 Aws::Map<Aws::String, MessageAttributeValue> message_attributes_map;
385 for (const auto& [attribute_name, attribute_value] : message_attributes.GetAllObjects()) {
386 if (attribute_value.IsObject()) {
387 const auto attr_object = attribute_value.AsObject();
388 MessageAttributeValue attr;
389 if (attr_object.KeyExists("DataType")) {
390 attr.WithDataType(attr_object.GetString("DataType"));
391 }
392 if (attr_object.KeyExists("StringValue")) {
393 attr.WithStringValue(attr_object.GetString("StringValue"));
394 }
395 if (attr_object.KeyExists("BinaryValue")) {
396 attr.WithBinaryValue(DecodeBinary(attr_object.GetString("BinaryValue")));
397 }
398 if (attr_object.KeyExists("StringListValues")) {
399 const auto string_list_values = attr_object.GetArray("StringListValues");
400 for (size_t i = 0; i < string_list_values.GetLength(); ++i) {
401 attr.AddStringListValues(string_list_values[i].AsString());
402 }
403 }
404 if (attr_object.KeyExists("BinaryListValues")) {
405 const auto binary_list_values = attr_object.GetArray("BinaryListValues");
406 for (size_t i = 0; i < binary_list_values.GetLength(); ++i) {
407 attr.AddBinaryListValues(DecodeBinary(binary_list_values[i].AsString()));
408 }
409 }
410 message_attributes_map[attribute_name] = attr;
411 }
412 }
413 message.WithMessageAttributes(message_attributes_map);
414 }
415
416 return message;
417}
418
419template <typename Outcome>
420Outcome MakeHttpErrorOutcome(int status_code, utils::zstring_view body, Aws::String message = {}) {
421 Aws::SQS::SQSError error;
422 error.SetResponseCode(static_cast<Aws::Http::HttpResponseCode>(status_code));
423 if (message.empty()) {
424 message = ExtractErrorMessageFromBody(body);
425 }
426 if (!message.empty()) {
427 error.SetMessage(message);
428 }
429 return Outcome(error);
430}
431
432template <typename Outcome>
433Outcome MakeJsonParseErrorOutcome(const impl::JsonResponse& response) {
434 return MakeHttpErrorOutcome<Outcome>(response.status_code, response.body, response.json.GetErrorMessage());
435}
436
437template <typename Outcome>
438Outcome MakeFailedOutcome(const impl::JsonResponse& response) {
439 if (!response.transport_error.empty()) {
440 return MakeHttpErrorOutcome<Outcome>(
441 response.status_code,
442 response.body,
443 Aws::String{response.transport_error.c_str(), response.transport_error.size()}
444 );
445 }
446 if (response.status_code != 200) {
447 return MakeHttpErrorOutcome<Outcome>(response.status_code, response.body);
448 }
449 return MakeJsonParseErrorOutcome<Outcome>(response);
450}
451
452} // namespace
453
454class JsonClient::Impl {
455public:
456 Impl(
461 )
469 {
470 UINVARIANT(!this->settings.endpoint.empty(), "sqs::ClientSettings.endpoint is empty; set the SQS JSON API URL");
473 "sqs::ClientSettings.timeout must be positive"
474 );
476 !this->settings.region.empty(),
477 "sqs::ClientSettings.region is empty; set the AWS signing region "
478 "(for example, ru-central1 or us-east-1)"
479 );
480 }
481
483 const char* operation_name,
486 ) const;
487
495};
496
506
507JsonClient::JsonClient(JsonClient&&) noexcept = default;
508
509JsonClient& JsonClient::operator=(JsonClient&&) noexcept = default;
510
511JsonClient::~JsonClient() = default;
512
514 const char* operation_name,
515 const Aws::String& /*endpoint*/,
518) const {
520}
521
523 const char* operation_name,
526) const {
528 const auto compact_json = json_body.View().WriteCompact();
530
532 for (const auto& header : custom_headers) {
534 }
544 }
545 if (!session_token.empty()) {
547 }
548
550 // authorization_override is a prebuilt Authorization header; this date is only
551 // required to keep the SigV4-shaped header set complete.
554 } else if (has_signing_credentials) {
557 headers,
558 {
562 .payload = body,
567 }
568 );
569 }
570
572
573 try {
574 const auto response =
579 .retry(1)
581 .perform();
582
583 result.status_code = static_cast<int>(response->status_code());
585 if (result.status_code != 200) {
586 return result;
587 }
588
591 LOG_ERROR()
592 << "Failed to parse JSON: " << result.json.GetErrorMessage() << ". Response body was: " << result.body;
593 return result;
594 }
595
596 result.ok = true;
597 return result;
598 } catch (const std::exception& ex) {
600 LOG_ERROR() << operation_name << " HTTP request failed: " << result.transport_error;
601 return result;
602 }
603}
604
624
644
647) const {
650
652 for (size_t i = 0; i < request.GetEntries().size(); ++i) {
653 const auto& entry = request.GetEntries()[i];
656 .WithString("Id", entry.GetId())
657 .WithString("ReceiptHandle", entry.GetReceiptHandle())
658 .WithInteger("VisibilityTimeout", entry.GetVisibilityTimeout());
659 }
661
662 const auto response = ExecuteJsonOperation(
663 "ChangeMessageVisibilityBatch",
667 );
668 if (!response.ok) {
670 }
671
673 if (response.json.View().KeyExists("Successful")) {
674 const auto& successful = response.json.View().GetArray("Successful");
675 for (size_t i = 0; i < successful.GetLength(); ++i) {
677 }
678 }
679 if (response.json.View().KeyExists("Failed")) {
680 const auto& failed = response.json.View().GetArray("Failed");
681 for (size_t i = 0; i < failed.GetLength(); ++i) {
682 result
684 .WithId(failed[i].GetString("Id"))
685 .WithSenderFault(failed[i].GetBool("SenderFault"))
686 .WithCode(failed[i].GetString("Code"))
687 .WithMessage(failed[i].GetString("Message")));
688 }
689 }
690
692}
693
722
739
743
745 for (size_t i = 0; i < request.GetEntries().size(); ++i) {
746 const auto& entry = request.GetEntries()[i];
749 .WithString("Id", entry.GetId())
750 .WithString("ReceiptHandle", entry.GetReceiptHandle());
751 }
753
754 const auto response = ExecuteJsonOperation(
755 "DeleteMessageBatch",
759 );
760 if (!response.ok) {
762 }
763
765 if (response.json.View().KeyExists("Successful")) {
766 const auto& successful = response.json.View().GetArray("Successful");
767 for (size_t i = 0; i < successful.GetLength(); ++i) {
769 }
770 }
771 if (response.json.View().KeyExists("Failed")) {
772 const auto& failed = response.json.View().GetArray("Failed");
773 for (size_t i = 0; i < failed.GetLength(); ++i) {
774 result
776 .WithId(failed[i].GetString("Id"))
777 .WithSenderFault(failed[i].GetBool("SenderFault"))
778 .WithCode(failed[i].GetString("Code"))
779 .WithMessage(failed[i].GetString("Message")));
780 }
781 }
782
784}
785
798
829
855
858) const {
861
864 }
867 }
868
869 const auto response = ExecuteJsonOperation(
870 "ListDeadLetterSourceQueues",
874 );
875 if (!response.ok) {
877 }
878
880 if (response.json.View().KeyExists("queue_urls")) {
881 const auto& queue_urls = response.json.View().GetArray("queue_urls");
882 for (size_t i = 0; i < queue_urls.GetLength(); ++i) {
884 }
885 } else if (response.json.View().KeyExists("QueueUrls")) {
886 const auto& queue_urls = response.json.View().GetArray("QueueUrls");
887 for (size_t i = 0; i < queue_urls.GetLength(); ++i) {
889 }
890 }
891 if (response.json.View().KeyExists("NextToken")) {
893 }
894
896}
897
919
922
925 }
928 }
931 }
932
933 const auto response = ExecuteJsonOperation(
934 "ListQueues",
938 );
939 if (!response.ok) {
941 }
942
944 if (response.json.View().KeyExists("QueueUrls")) {
945 const auto& queue_urls = response.json.View().GetArray("QueueUrls");
946 for (size_t i = 0; i < queue_urls.GetLength(); ++i) {
948 }
949 }
950 if (response.json.View().KeyExists("NextToken")) {
952 }
953
955}
956
969
973
975 json_request.WithInteger("MaxNumberOfMessages", request.GetMaxNumberOfMessages());
976 }
979 }
982 }
984 json_request.WithString("ReceiveRequestAttemptId", request.GetReceiveRequestAttemptId());
985 }
986
990 for (const auto& attribute_name : request.GetAttributeNames()) {
992 }
994 }
995
998 }
999
1000 const auto response = ExecuteJsonOperation(
1001 "ReceiveMessage",
1005 );
1006 if (!response.ok) {
1008 }
1009
1011 if (response.json.View().KeyExists("Messages")) {
1012 const auto& messages = response.json.View().GetArray("Messages");
1013 for (size_t i = 0; i < messages.GetLength(); ++i) {
1015 }
1016 }
1017
1019}
1020
1037
1041
1044 }
1046 json_request.WithString("MessageGroupId", request.GetMessageGroupId());
1047 }
1049 json_request.WithString("MessageDeduplicationId", request.GetMessageDeduplicationId());
1050 }
1053 }
1056 "MessageSystemAttributes",
1058 );
1059 }
1060
1061 const auto response =
1063 if (!response.ok) {
1065 }
1066
1068 if (response.json.View().KeyExists("MessageId")) {
1070 }
1071 if (response.json.View().KeyExists("MD5OfMessageBody")) {
1072 result.SetMD5OfMessageBody(response.json.View().GetString("MD5OfMessageBody"));
1073 }
1074 if (response.json.View().KeyExists("MD5OfMessageAttributes")) {
1075 result.SetMD5OfMessageAttributes(response.json.View().GetString("MD5OfMessageAttributes"));
1076 }
1077 if (response.json.View().KeyExists("MD5OfMessageSystemAttributes")) {
1078 result.SetMD5OfMessageSystemAttributes(response.json.View().GetString("MD5OfMessageSystemAttributes"));
1079 }
1080 if (response.json.View().KeyExists("SequenceNumber")) {
1081 result.SetSequenceNumber(response.json.View().GetString("SequenceNumber"));
1082 }
1083
1084 return SendMessageOutcome(result);
1085}
1086
1090
1093 for (const auto& entry : request.GetEntries()) {
1095 json_entry.WithString("Id", entry.GetId()).WithString("MessageBody", entry.GetMessageBody());
1096
1098 json_entry.WithString("MessageGroupId", entry.GetMessageGroupId());
1099 }
1101 json_entry.WithString("MessageDeduplicationId", entry.GetMessageDeduplicationId());
1102 }
1104 json_entry.WithInteger("DelaySeconds", entry.GetDelaySeconds());
1105 }
1108 }
1111 "MessageSystemAttributes",
1113 );
1114 }
1115
1117 }
1118
1120 for (size_t i = 0; i < entries_vector.size(); ++i) {
1122 }
1124
1125 const auto response = ExecuteJsonOperation(
1126 "SendMessageBatch",
1130 );
1131 if (!response.ok) {
1133 }
1134
1136 if (response.json.View().KeyExists("Successful")) {
1137 const auto& successful = response.json.View().GetArray("Successful");
1138 for (size_t i = 0; i < successful.GetLength(); ++i) {
1139 auto entry =
1141 .WithId(successful[i].GetString("Id"))
1142 .WithMessageId(successful[i].GetString("MessageId"))
1143 .WithMD5OfMessageBody(successful[i].GetString("MD5OfMessageBody"));
1144 if (successful[i].KeyExists("MD5OfMessageAttributes")) {
1145 entry.WithMD5OfMessageAttributes(successful[i].GetString("MD5OfMessageAttributes"));
1146 }
1147 if (successful[i].KeyExists("MD5OfMessageSystemAttributes")) {
1148 entry.WithMD5OfMessageSystemAttributes(successful[i].GetString("MD5OfMessageSystemAttributes"));
1149 }
1150 if (successful[i].KeyExists("SequenceNumber")) {
1151 entry.WithSequenceNumber(successful[i].GetString("SequenceNumber"));
1152 }
1154 }
1155 }
1156 if (response.json.View().KeyExists("Failed")) {
1157 const auto& failed = response.json.View().GetArray("Failed");
1158 for (size_t i = 0; i < failed.GetLength(); ++i) {
1159 result
1161 .WithId(failed[i].GetString("Id"))
1162 .WithSenderFault(failed[i].GetBool("SenderFault"))
1163 .WithCode(failed[i].GetString("Code"))
1164 .WithMessage(failed[i].GetString("Message")));
1165 }
1166 }
1167
1169}
1170
1188
1201
1215
1216} // namespace sqs
1217
1218USERVER_NAMESPACE_END