You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by li...@apache.org on 2022/05/20 09:01:20 UTC
[rocketmq-client-cpp] branch main updated: Adopt protocol v2 (#414)
This is an automated email from the ASF dual-hosted git repository.
lizhanhui pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/rocketmq-client-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new a44a2c6 Adopt protocol v2 (#414)
a44a2c6 is described below
commit a44a2c611406e62bd8af66e1a2a7f2070b53f728
Author: Zhanhui Li <li...@gmail.com>
AuthorDate: Fri May 20 17:01:16 2022 +0800
Adopt protocol v2 (#414)
---
.bazelversion | 2 +-
.clang-format | 6 +-
.gitignore | 5 +-
.vscode/settings.json | 13 +
WORKSPACE | 5 +-
api/BUILD.bazel | 1 +
api/rocketmq/AsyncCallback.h | 50 -
api/rocketmq/BackoffPolicy.h | 70 ++
api/rocketmq/Configuration.h | 71 ++
.../rocketmq/ConfigurationDefaults.h | 14 +-
api/rocketmq/{MessageModel.h => ConsumeResult.h} | 11 +-
api/rocketmq/ConsumeType.h | 70 --
api/rocketmq/DefaultMQProducer.h | 154 ---
api/rocketmq/DefaultMQPullConsumer.h | 63 --
api/rocketmq/DefaultMQPushConsumer.h | 120 ---
api/rocketmq/ErrorCode.h | 17 +-
.../include => api/rocketmq}/FilterExpression.h | 8 +-
api/rocketmq/MQMessage.h | 115 ---
api/rocketmq/MQMessageExt.h | 60 --
api/rocketmq/MQMessageQueue.h | 153 ---
api/rocketmq/Message.h | 176 ++++
api/rocketmq/MessageListener.h | 43 +-
api/rocketmq/OffsetStore.h | 34 -
api/rocketmq/Producer.h | 95 ++
api/rocketmq/PullResult.h | 55 -
api/rocketmq/PushConsumer.h | 94 ++
api/rocketmq/{MessageModel.h => SendCallback.h} | 12 +-
api/rocketmq/{MessageModel.h => SendReceipt.h} | 14 +-
api/rocketmq/SendResult.h | 137 ---
api/rocketmq/SimpleConsumer.h | 111 ++
api/rocketmq/{MessageModel.h => Tracing.h} | 12 +-
api/rocketmq/Transaction.h | 17 +-
.../rocketmq/TransactionChecker.h | 12 +-
api/rocketmq/{MessageType.h => TransactionState.h} | 9 +-
bazel/rocketmq_deps.bzl | 81 +-
example/rocketmq/ExampleAsyncProducer.cpp | 257 -----
example/rocketmq/ExampleBroadcastPushConsumer.cpp | 65 --
example/rocketmq/ExamplePullConsumer.cpp | 54 -
example/rocketmq/ExamplePushConsumer.cpp | 69 --
{example/rocketmq => examples}/BUILD.bazel | 142 ++-
.../BenchmarkPushConsumer.cpp | 0
.../ExampleAsyncProducer.cpp | 62 +-
.../rocketmq => examples}/ExampleFifoProducer.cpp | 49 +-
.../ExampleFifoPushConsumer.cpp | 0
{example/rocketmq => examples}/ExampleProducer.cpp | 43 +-
.../ExamplePushConsumer.cpp | 52 +-
examples/ExampleSimpleConsumer.cpp | 66 ++
.../ExampleTransactionProducer.cpp | 0
.../PushConsumerWithCustomExecutor.cpp | 0
.../PushConsumerWithThrottle.cpp | 0
{example/rocketmq => examples}/SqlConsumer.cpp | 0
{example/rocketmq => examples}/SqlProducer.cpp | 0
proto/BUILD.bazel | 6 +-
proto/apache/rocketmq/v1/definition.proto | 349 -------
proto/apache/rocketmq/v1/service.proto | 531 ----------
proto/apache/rocketmq/{v1 => v2}/admin.proto | 12 +-
proto/apache/rocketmq/v2/definition.proto | 447 +++++++++
proto/apache/rocketmq/v2/service.proto | 436 ++++++++
src/main/cpp/admin/include/AdminClient.h | 4 +-
src/main/cpp/admin/include/AdminServerImpl.h | 8 +-
src/main/cpp/admin/include/AdminServiceImpl.h | 7 +-
src/main/cpp/admin/include/ServerCall.h | 4 +-
src/main/cpp/base/BUILD.bazel | 1 +
.../cpp/base/Configuration.cpp} | 40 +-
.../DigestType.h => ConfigurationDefaults.cpp} | 15 +-
.../cpp/{rocketmq => base}/CredentialsProvider.cpp | 0
src/main/cpp/base/ErrorCategory.cpp | 13 +-
.../cpp/{rocketmq => base}/FilterExpression.cpp | 7 +-
src/main/cpp/base/MQMessage.cpp | 190 ----
src/main/cpp/base/MQMessageExt.cpp | 77 --
src/main/cpp/base/Message.cpp | 89 ++
src/main/cpp/base/MessageAccessor.cpp | 91 --
.../cpp/base/MessageExt.cpp} | 17 +-
src/main/cpp/base/MetadataConstants.cpp | 42 +-
src/main/cpp/base/MixAll.cpp | 37 +-
src/main/cpp/base/Protocol.cpp | 136 ++-
.../cpp/base/{include/DigestType.h => Tracing.cpp} | 18 +-
src/main/cpp/base/include/InvocationContext.h | 2 +-
src/main/cpp/base/include/MessageAccessor.h | 61 --
.../main/cpp/base/include/MessageExt.h | 14 +-
src/main/cpp/base/include/MessageImpl.h | 36 -
src/main/cpp/base/include/MetadataConstants.h | 3 +
src/main/cpp/base/include/MixAll.h | 10 +-
src/main/cpp/base/include/Protocol.h | 126 +--
src/main/cpp/base/include/RetryPolicy.h | 81 ++
.../include/StsCredentialsProviderImpl.h | 0
.../include/{DigestType.h => SubscriptionEntry.h} | 11 +-
src/main/cpp/base/tests/AssignmentTest.cpp | 23 +
src/main/cpp/base/tests/BUILD.bazel | 54 +
src/main/cpp/base/tests/ConfigurationTest.cpp | 54 +
src/main/cpp/base/tests/MessageBuilderTest.cpp | 56 ++
src/main/cpp/base/tests/MessageQueueTest.cpp | 21 +
.../cpp/base/tests/MixAllTest.cpp} | 8 +-
.../cpp/base/tests/RetryPolicyTest.cpp} | 23 +-
src/main/cpp/client/ClientConfigImpl.cpp | 97 --
src/main/cpp/client/ClientManagerFactory.cpp | 12 +-
src/main/cpp/client/ClientManagerImpl.cpp | 1056 +++++---------------
src/main/cpp/client/ReceiveMessageStreamReader.cpp | 118 +++
src/main/cpp/client/RpcClientImpl.cpp | 195 ++--
.../SessionImpl.cpp} | 39 +-
src/main/cpp/client/Signature.cpp | 26 +-
src/main/cpp/client/TelemetryBidiReactor.cpp | 339 +++++++
src/main/cpp/client/TlsHelper.cpp | 214 +---
src/main/cpp/client/TopicAssignmentInfo.cpp | 57 +-
src/main/cpp/client/TopicPublishInfo.cpp | 154 ---
src/main/cpp/client/include/Assignment.h | 51 -
src/main/cpp/client/include/Broker.h | 62 --
src/main/cpp/client/include/Client.h | 35 +-
src/main/cpp/client/include/ClientConfig.h | 50 +-
src/main/cpp/client/include/ClientConfigImpl.h | 146 ---
src/main/cpp/client/include/ClientManager.h | 48 +-
src/main/cpp/client/include/ClientManagerImpl.h | 77 +-
.../client/include/InsecureCertificateVerifier.h | 42 +
.../Encoding.h => client/include/Metadata.h} | 11 +-
src/main/cpp/client/include/Partition.h | 89 --
.../cpp/client/include/ReceiveMessageCallback.h | 10 +-
.../cpp/client/include/ReceiveMessageContext.h | 17 +-
src/main/cpp/client/include/ReceiveMessageResult.h | 4 +-
.../client/include/ReceiveMessageStreamReader.h | 63 ++
src/main/cpp/client/include/RpcClient.h | 78 +-
src/main/cpp/client/include/RpcClientImpl.h | 49 +-
src/main/cpp/client/include/SendMessageContext.h | 16 +-
src/main/cpp/client/include/ServiceAddress.h | 124 ---
.../DigestType.h => client/include/Session.h} | 12 +-
.../main/cpp/client/include/SessionImpl.h | 24 +-
src/main/cpp/client/include/Signature.h | 2 +-
src/main/cpp/client/include/TelemetryBidiReactor.h | 121 +++
src/main/cpp/client/include/TlsHelper.h | 33 +-
src/main/cpp/client/include/TopicAssignmentInfo.h | 29 +-
src/main/cpp/client/include/TopicRouteData.h | 47 +-
src/main/cpp/client/mocks/RpcClientMock.cpp | 30 -
.../cpp/client/mocks/include/ClientConfigMock.h | 39 -
.../cpp/client/mocks/include/ClientManagerMock.h | 46 +-
src/main/cpp/client/mocks/include/ClientMock.h | 12 +-
src/main/cpp/client/mocks/include/RpcClientMock.h | 42 +-
.../cpp/rocketmq/AsyncReceiveMessageCallback.cpp | 21 +-
src/main/cpp/rocketmq/BUILD.bazel | 4 +-
src/main/cpp/rocketmq/ClientImpl.cpp | 518 ++++------
.../cpp/rocketmq/ConsumeFifoMessageService.cpp | 166 ++-
.../cpp/rocketmq/ConsumeMessageServiceBase.cpp | 10 +-
.../cpp/rocketmq/ConsumeStandardMessageService.cpp | 193 ++--
src/main/cpp/rocketmq/DefaultMQProducer.cpp | 253 -----
src/main/cpp/rocketmq/DefaultMQPullConsumer.cpp | 78 --
src/main/cpp/rocketmq/DefaultMQPushConsumer.cpp | 134 ---
.../cpp/rocketmq/MessageGroupQueueSelector.cpp | 3 +-
src/main/cpp/rocketmq/NamingScheme.cpp | 12 +-
src/main/cpp/rocketmq/ProcessQueueImpl.cpp | 163 +--
src/main/cpp/rocketmq/Producer.cpp | 96 ++
src/main/cpp/rocketmq/ProducerImpl.cpp | 611 ++++++-----
src/main/cpp/rocketmq/PullConsumerImpl.cpp | 189 ----
src/main/cpp/rocketmq/PushConsumer.cpp | 53 +
src/main/cpp/rocketmq/PushConsumerImpl.cpp | 434 ++++----
.../{SendCallbacks.cpp => SendContext.cpp} | 80 +-
src/main/cpp/rocketmq/SimpleConsumer.cpp | 141 +++
src/main/cpp/rocketmq/SimpleConsumerImpl.cpp | 400 ++++++++
src/main/cpp/rocketmq/TopicPublishInfo.cpp | 125 +++
src/main/cpp/rocketmq/TransactionImpl.cpp | 10 +-
.../rocketmq/include/AsyncReceiveMessageCallback.h | 16 +-
src/main/cpp/rocketmq/include/AwaitPullCallback.h | 58 --
src/main/cpp/rocketmq/include/ClientImpl.h | 108 +-
.../rocketmq/include/ConsumeFifoMessageService.h | 24 +-
.../cpp/rocketmq/include/ConsumeMessageService.h | 4 +-
.../rocketmq/include/ConsumeMessageServiceBase.h | 9 +-
.../include/ConsumeStandardMessageService.h | 18 +-
src/main/cpp/rocketmq/include/Consumer.h | 2 +
.../rocketmq/include/MessageGroupQueueSelector.h | 9 +-
src/main/cpp/rocketmq/include/NamingScheme.h | 6 +-
src/main/cpp/rocketmq/include/ProcessQueue.h | 29 +-
src/main/cpp/rocketmq/include/ProcessQueueImpl.h | 86 +-
src/main/cpp/rocketmq/include/ProducerImpl.h | 95 +-
.../cpp/rocketmq/include/PublishInfoCallback.h | 11 +-
src/main/cpp/rocketmq/include/PullConsumerImpl.h | 60 --
src/main/cpp/rocketmq/include/PushConsumer.h | 64 --
src/main/cpp/rocketmq/include/PushConsumerImpl.h | 131 +--
src/main/cpp/rocketmq/include/SendCallbacks.h | 125 ---
src/main/cpp/rocketmq/include/SendContext.h | 77 ++
src/main/cpp/rocketmq/include/SimpleConsumerImpl.h | 89 ++
.../include/TopicPublishInfo.h | 37 +-
src/main/cpp/rocketmq/include/TransactionImpl.h | 37 +-
.../mocks/include/ConsumeMessageServiceMock.h | 4 +-
.../cpp/rocketmq/mocks/include/PushConsumerMock.h | 4 +-
.../logger => main/cpp/rocketmq/tests}/BUILD.bazel | 23 +-
src/main/cpp/rocketmq/tests/SendContextTest.cpp | 17 +
.../DigestType.h => rocketmq/tests/TimeTest.cpp} | 17 +-
.../ut/scheduler => main/cpp/stats}/BUILD.bazel | 18 +-
src/main/cpp/stats/PublishStats.cpp | 56 ++
.../include/PublishStats.h} | 32 +-
.../ut/api => main/cpp/stats/tests}/BUILD.bazel | 6 +-
src/main/cpp/stats/tests/PublishStatsTest.cpp | 98 ++
src/main/cpp/{tracing => trace}/BUILD.bazel | 4 +-
src/main/cpp/{tracing => trace}/TracingUtility.cpp | 49 +-
.../{tracing => trace}/include/TracingUtility.h | 5 +-
src/main/cpp/tracing/exporters/BUILD.bazel | 34 -
src/main/cpp/tracing/exporters/OtlpExporter.cpp | 428 --------
.../cpp/tracing/exporters/include/OtlpExporter.h | 153 ---
src/test/cpp/benchmark/BUILD.bazel | 27 -
src/test/cpp/benchmark/BenchmarkTest.cpp | 34 -
src/test/cpp/it/BUILD.bazel | 51 -
src/test/cpp/it/README.md | 4 -
src/test/cpp/it/RpcClientTest.cpp | 374 -------
src/test/cpp/it/TopAddressingTest.cpp | 167 ----
src/test/cpp/it/TopicPublishInfoTest.cpp | 175 ----
src/test/cpp/ut/BUILD | 1 -
src/test/cpp/ut/BUILD.bazel | 17 -
src/test/cpp/ut/README.md | 3 -
src/test/cpp/ut/admin/AdminServerTest.cpp | 67 --
src/test/cpp/ut/admin/BUILD.bazel | 28 -
src/test/cpp/ut/base/BUILD.bazel | 153 ---
src/test/cpp/ut/base/HistogramTest.cpp | 59 --
src/test/cpp/ut/base/HostInfoTest.cpp | 65 --
src/test/cpp/ut/base/HttpClientTest.cpp | 67 --
src/test/cpp/ut/base/InvocationContextTest.cpp | 37 -
src/test/cpp/ut/base/MQMessageExtTest.cpp | 68 --
src/test/cpp/ut/base/MQMessageTest.cpp | 60 --
src/test/cpp/ut/base/MixAllTest.cpp | 120 ---
src/test/cpp/ut/base/RateLimiterTest.cpp | 69 --
src/test/cpp/ut/base/ThreadPoolTest.cpp | 76 --
src/test/cpp/ut/base/TopAddressingTest.cpp | 74 --
src/test/cpp/ut/base/UniqueIdGeneratorTest.cpp | 46 -
src/test/cpp/ut/base/UtilAllTest.cpp | 91 --
src/test/cpp/ut/client/BUILD.bazel | 86 --
.../cpp/ut/client/ClientManagerFactoryTest.cpp | 47 -
src/test/cpp/ut/client/ClientManagerTest.cpp | 357 -------
src/test/cpp/ut/client/ClientTest.cpp | 46 -
src/test/cpp/ut/client/RpcClientTest.cpp | 82 --
src/test/cpp/ut/client/TlsHelperTest.cpp | 31 -
src/test/cpp/ut/client/TopicAssignmentInfoTest.cpp | 110 --
src/test/cpp/ut/client/TracingUtilityTest.cpp | 50 -
src/test/cpp/ut/concurrent/BUILD.bazel | 28 -
src/test/cpp/ut/concurrent/CountdownLatchTest.cpp | 49 -
src/test/cpp/ut/logger/LoggerTest.cpp | 109 --
src/test/cpp/ut/remoting/BUILD.bazel | 73 --
src/test/cpp/ut/remoting/BrokerDataTest.cpp | 44 -
src/test/cpp/ut/remoting/QueueDataTest.cpp | 38 -
src/test/cpp/ut/remoting/RemotingCommandTest.cpp | 62 --
src/test/cpp/ut/remoting/TopicRouteDataTest.cpp | 36 -
src/test/cpp/ut/rocketmq/AwaitPullCallbackTest.cpp | 87 --
src/test/cpp/ut/rocketmq/BUILD.bazel | 264 -----
src/test/cpp/ut/rocketmq/ClientImplTest.cpp | 126 ---
.../rocketmq/ConsumeStandardMessageServiceTest.cpp | 117 ---
.../cpp/ut/rocketmq/CredentialsProviderTest.cpp | 68 --
src/test/cpp/ut/rocketmq/DefaultMQProducerTest.cpp | 212 ----
.../cpp/ut/rocketmq/DefaultMQPushConsumerTest.cpp | 37 -
.../ut/rocketmq/DynamicNameServerResolverTest.cpp | 75 --
src/test/cpp/ut/rocketmq/ExecutorTest.cpp | 157 ---
.../ut/rocketmq/MessageGroupQueueSelectorTest.cpp | 41 -
src/test/cpp/ut/rocketmq/MessageTest.cpp | 26 -
src/test/cpp/ut/rocketmq/NamingSchemeTest.cpp | 50 -
src/test/cpp/ut/rocketmq/ProcessQueueTest.cpp | 365 -------
src/test/cpp/ut/rocketmq/ProducerImplTest.cpp | 273 -----
src/test/cpp/ut/rocketmq/PullConsumerImplTest.cpp | 423 --------
src/test/cpp/ut/rocketmq/PushConsumerImplTest.cpp | 205 ----
src/test/cpp/ut/rocketmq/SendCallbacksTest.cpp | 43 -
.../ut/rocketmq/StaticNameServerResolverTest.cpp | 51 -
.../ut/rocketmq/StsCredentialsProviderImplTest.cpp | 76 --
src/test/cpp/ut/rocketmq/include/MQClientTest.h | 105 --
src/test/cpp/ut/scheduler/SchedulerTest.cpp | 149 ---
src/test/cpp/ut/tracing/exporters/BUILD.bazel | 40 -
.../cpp/ut/tracing/exporters/OtlpExportersTest.cpp | 70 --
.../cpp/ut/tracing/exporters/SpanContextTest.cpp | 25 -
tools/trouble_shooting.sh | 2 +
tools/use_clang.sh | 2 +
262 files changed, 6429 insertions(+), 15223 deletions(-)
diff --git a/.bazelversion b/.bazelversion
index 6aba2b2..af8c8ec 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-4.2.0
+4.2.2
diff --git a/.clang-format b/.clang-format
index 6345fe1..fb63bcf 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,11 +1,14 @@
---
+BasedOnStyle: Google
+IndentWidth: 2
+---
Language: Cpp
AccessModifierOffset: -2
+BinPackParameters: false
ColumnLimit: 120
DerivePointerAlignment: false
PointerAlignment: Left
SortIncludes: true
-IndentWidth: 2
NamespaceIndentation: Inner
AlwaysBreakTemplateDeclarations: true
AllowShortCaseLabelsOnASingleLine: false
@@ -13,6 +16,7 @@ AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
IndentCaseBlocks: false
IndentCaseLabels: true
+ReflowComments: true
...
---
diff --git a/.gitignore b/.gitignore
index f3ec0b2..23e0e93 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,6 @@ bazel-testlogs
cmake-build-debug
.clwb
compile_commands.json
-.vscode
logs
_build
cmake-build-debug-coverage
@@ -15,3 +14,7 @@ cmake-build-debug-coverage
external
bazel-apache_rocketmq_client_cpp
bazel-rocketmq-client-cpp
+/external
+/bazel-*
+/compile_commands.json
+/.cache/
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..cb613f9
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,13 @@
+{
+ "C_Cpp.intelliSenseEngine": "Disabled",
+ "C_Cpp.autocomplete": "Disabled", // So you don't get autocomplete from both extensions.
+ "C_Cpp.errorSquiggles": "Disabled", // So you don't get error squiggles from both extensions (clangd's seem to be more reliable anyway).
+ "clangd.arguments": [
+ "-log=verbose",
+ "-pretty",
+ "--background-index",
+ "--header-insertion=never",
+ "--compile-commands-dir=${workspaceFolder}/",
+ "--query-driver=/**/*",
+ ]
+}
\ No newline at end of file
diff --git a/WORKSPACE b/WORKSPACE
index 8648444..644b5d7 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,4 +14,7 @@ rules_proto_grpc_repos()
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
rules_proto_dependencies()
-rules_proto_toolchains()
\ No newline at end of file
+rules_proto_toolchains()
+
+load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
+hedron_compile_commands_setup()
\ No newline at end of file
diff --git a/api/BUILD.bazel b/api/BUILD.bazel
index b7eb594..f5d75d5 100644
--- a/api/BUILD.bazel
+++ b/api/BUILD.bazel
@@ -23,5 +23,6 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
"@com_google_absl//absl/strings",
+ "@io_opencensus_cpp//opencensus/trace",
],
)
\ No newline at end of file
diff --git a/api/rocketmq/AsyncCallback.h b/api/rocketmq/AsyncCallback.h
deleted file mode 100644
index 8004ba0..0000000
--- a/api/rocketmq/AsyncCallback.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <system_error>
-
-#include "MQClientException.h"
-#include "PullResult.h"
-#include "SendResult.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class AsyncCallback {
-public:
- virtual ~AsyncCallback() = default;
-};
-
-class SendCallback : public AsyncCallback {
-public:
- ~SendCallback() override = default;
-
- virtual void onSuccess(SendResult& send_result) noexcept = 0;
-
- virtual void onFailure(const std::error_code& ec) noexcept = 0;
-};
-
-class PullCallback : public AsyncCallback {
-public:
- ~PullCallback() override = default;
-
- virtual void onSuccess(const PullResult& pull_result) noexcept = 0;
-
- virtual void onFailure(const std::error_code& ec) noexcept = 0;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/BackoffPolicy.h b/api/rocketmq/BackoffPolicy.h
new file mode 100644
index 0000000..89aa7d1
--- /dev/null
+++ b/api/rocketmq/BackoffPolicy.h
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "RocketMQ.h"
+#include <chrono>
+#include <cmath>
+#include <cstddef>
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class BackoffPolicy {
+public:
+ virtual ~BackoffPolicy() = default;
+
+ virtual std::size_t maxAttempts() const = 0;
+
+ virtual std::chrono::milliseconds backoff(std::size_t attempt) const = 0;
+};
+
+class ExponentialBackoffPolicy : public BackoffPolicy {
+public:
+ ExponentialBackoffPolicy(std::size_t max_attempts, std::chrono::milliseconds initial_backoff,
+ std::chrono::milliseconds max_backoff, std::size_t multiplier)
+ : max_attempts_(max_attempts), initial_backoff_(initial_backoff), max_backoff_(max_backoff),
+ multiplier_(multiplier) {
+ }
+
+ std::size_t maxAttempts() const override {
+ return max_attempts_;
+ }
+
+ std::chrono::milliseconds backoff(std::size_t attempt) const override {
+ if (attempt <= 1) {
+ return initial_backoff_;
+ }
+
+ if (attempt >= max_attempts_) {
+ return max_backoff_;
+ }
+
+ auto duration = initial_backoff_ * static_cast<std::size_t>(std::pow(multiplier_, attempt));
+ if (duration > max_backoff_) {
+ return max_backoff_;
+ }
+ return duration;
+ }
+
+private:
+ std::size_t max_attempts_;
+ std::chrono::milliseconds initial_backoff_;
+ std::chrono::milliseconds max_backoff_;
+ std::size_t multiplier_;
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/Configuration.h b/api/rocketmq/Configuration.h
new file mode 100644
index 0000000..90cdf7d
--- /dev/null
+++ b/api/rocketmq/Configuration.h
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <chrono>
+#include <memory>
+#include <string>
+
+#include "ConfigurationDefaults.h"
+#include "CredentialsProvider.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class ConfigurationBuilder;
+
+class Configuration {
+public:
+ static ConfigurationBuilder newBuilder();
+
+ const std::string& endpoints() const {
+ return endpoints_;
+ }
+
+ CredentialsProviderPtr credentialsProvider() const {
+ return credentials_provider_;
+ }
+
+ std::chrono::milliseconds requestTimeout() const {
+ return request_timeout_;
+ }
+
+protected:
+ friend class ConfigurationBuilder;
+
+ Configuration() = default;
+
+private:
+ std::string endpoints_;
+ CredentialsProviderPtr credentials_provider_;
+ std::chrono::milliseconds request_timeout_{ConfigurationDefaults::RequestTimeout};
+};
+
+class ConfigurationBuilder {
+public:
+ ConfigurationBuilder& withEndpoints(std::string endpoints);
+
+ ConfigurationBuilder& withCredentialsProvider(std::shared_ptr<CredentialsProvider> provider);
+
+ ConfigurationBuilder& withRequestTimeout(std::chrono::milliseconds request_timeout);
+
+ Configuration build();
+
+private:
+ Configuration configuration_;
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/include/OrphanTransactionCallback.h b/api/rocketmq/ConfigurationDefaults.h
similarity index 79%
rename from src/main/cpp/client/include/OrphanTransactionCallback.h
rename to api/rocketmq/ConfigurationDefaults.h
index 0e78db1..08a2567 100644
--- a/src/main/cpp/client/include/OrphanTransactionCallback.h
+++ b/api/rocketmq/ConfigurationDefaults.h
@@ -16,15 +16,19 @@
*/
#pragma once
-#include "rocketmq/MQMessage.h"
+#include <chrono>
+
+#include "RocketMQ.h"
ROCKETMQ_NAMESPACE_BEGIN
-class OrphanTransactionCallback {
+class ConfigurationDefaults {
public:
- virtual ~OrphanTransactionCallback() = default;
-
- virtual void onOrphanTransaction(const MQMessage& message) = 0;
+ /**
+ * @brief Default request-timeout: 3.0 seconds.
+ *
+ */
+ static const std::chrono::milliseconds RequestTimeout;
};
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageModel.h b/api/rocketmq/ConsumeResult.h
similarity index 90%
copy from api/rocketmq/MessageModel.h
copy to api/rocketmq/ConsumeResult.h
index 2422d32..5dcdf77 100644
--- a/api/rocketmq/MessageModel.h
+++ b/api/rocketmq/ConsumeResult.h
@@ -16,16 +16,15 @@
*/
#pragma once
-#include "RocketMQ.h"
-
#include <cstdint>
+#include "RocketMQ.h"
+
ROCKETMQ_NAMESPACE_BEGIN
-enum class MessageModel : int8_t
-{
- BROADCASTING,
- CLUSTERING,
+enum class ConsumeResult : uint8_t {
+ SUCCESS = 0,
+ FAILURE = 1
};
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/ConsumeType.h b/api/rocketmq/ConsumeType.h
deleted file mode 100644
index 4cbf5a2..0000000
--- a/api/rocketmq/ConsumeType.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <chrono>
-#include <cstdlib>
-#include <functional>
-
-#include "MQMessageQueue.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-enum ConsumeType
-{
- CONSUME_ACTIVELY,
- CONSUME_PASSIVELY,
-};
-
-enum ConsumeFromWhere
-{
- CONSUME_FROM_LAST_OFFSET,
- CONSUME_FROM_LAST_OFFSET_AND_FROM_MIN_WHEN_BOOT_FIRST,
- CONSUME_FROM_MIN_OFFSET,
- CONSUME_FROM_MAX_OFFSET,
- CONSUME_FROM_FIRST_OFFSET,
- CONSUME_FROM_TIMESTAMP,
-};
-
-enum ConsumeInitialMode
-{
- MIN,
- MAX,
-};
-
-enum QueryOffsetPolicy : uint8_t
-{
- BEGINNING = 0,
- END = 1,
- TIME_POINT = 2,
-};
-
-struct OffsetQuery {
- MQMessageQueue message_queue;
- QueryOffsetPolicy policy;
- std::chrono::system_clock::time_point time_point;
-};
-
-struct PullMessageQuery {
- MQMessageQueue message_queue;
- int64_t offset;
- int32_t batch_size;
- std::chrono::system_clock::duration await_time;
- std::chrono::system_clock::duration timeout;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/DefaultMQProducer.h b/api/rocketmq/DefaultMQProducer.h
deleted file mode 100644
index 97306d5..0000000
--- a/api/rocketmq/DefaultMQProducer.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <chrono>
-#include <memory>
-#include <system_error>
-#include <vector>
-
-#include "AsyncCallback.h"
-#include "CredentialsProvider.h"
-#include "ErrorCode.h"
-#include "LocalTransactionStateChecker.h"
-#include "Logger.h"
-#include "MQMessage.h"
-#include "MQSelector.h"
-#include "SendResult.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-/**
- * This class employs pointer-to-implementation paradigm to achieve the goal of stable ABI.
- * Refer https://en.cppreference.com/w/cpp/language/pimpl for an explanation.
- */
-class ProducerImpl;
-
-class DefaultMQProducer {
-public:
- explicit DefaultMQProducer(const std::string& group_name);
-
- ~DefaultMQProducer() = default;
-
- void start();
-
- void shutdown();
-
- /**
- * Acquire previous send timeout in milliseconds.
- * @return Send timeout in milliseconds
- */
- std::chrono::milliseconds getSendMsgTimeout() const;
-
- /**
- * Set default send message timeout in milliseconds.
- * @param timeout_millis Timeout used when sending messages.
- */
- void setSendMsgTimeout(std::chrono::milliseconds timeout);
-
- SendResult send(MQMessage& message, const std::string& message_group);
-
- /**
- * Send message in synchronous manner.
- * @param message Message to send.
- * @param filter_active_broker Do NOT rely on this parameter. it has been deprecated.
- */
- SendResult send(const MQMessage& message, bool filter_active_broker = true);
-
- SendResult send(const MQMessage& message, std::error_code& ec) noexcept;
-
- SendResult send(MQMessage& message, const MQMessageQueue& message_queue);
- SendResult send(MQMessage& message, MessageQueueSelector* selector, void* arg);
-
- /**
- * @brief This function is deprecated.
- *
- * @param message
- * @param selector
- * @param arg
- * @param retry_times retry_times is ignored with respect to member retry_times setting.
- * @param select_active_broker
- * @return SendResult
- */
- SendResult send(MQMessage& message, MessageQueueSelector* selector, void* arg, int retry_times,
- bool select_active_broker = false);
-
- /**
- * Send message in asynchronous manner.
- * @param message Message to send.
- * @param send_callback Callback to execute on completion of message sending.
- * @param select_active_broker Do NOT rely on this parameter. it has been deprecated.
- */
- void send(const MQMessage& message, SendCallback* send_callback, bool select_active_broker = false);
- void send(MQMessage& message, const MQMessageQueue& message_queue, SendCallback* send_callback);
- void send(MQMessage& message, MessageQueueSelector* selector, void* arg, SendCallback* send_callback);
-
- /**
- * send message in Oneway(The implementation is simply ignore the result of send message in synchronous).
- * @param message Message to send.
- * @param select_active_broker Do NOT rely on this parameter. it has been deprecated.
- */
- void sendOneway(const MQMessage& message, bool select_active_broker = false);
- void sendOneway(MQMessage& message, const MQMessageQueue& message_queue);
- void sendOneway(MQMessage& message, MessageQueueSelector* selector, void* arg);
-
- void setLocalTransactionStateChecker(LocalTransactionStateCheckerPtr checker);
-
- void setNamesrvAddr(const std::string& name_server_address_list);
-
- void setNameServerListDiscoveryEndpoint(const std::string& discovery_endpoint);
-
- void setGroupName(const std::string& group_name);
-
- void setInstanceName(const std::string& instance_name);
-
- void enableTracing(bool enabled);
-
- bool isTracingEnabled();
-
- /**
- * Number of attempts before claiming a send action as failure. By default, 3 attempts will be performed for sync and
- * async send methods.
- *
- * @return
- */
- int getMaxAttemptTimes() const;
-
- void setMaxAttemptTimes(int max_attempt_times);
-
- std::vector<MQMessageQueue> getTopicMessageQueueInfo(const std::string& topic);
-
- void setUnitName(std::string unit_name);
-
- const std::string& getUnitName();
-
- uint32_t compressBodyThreshold() const;
- void compressBodyThreshold(uint32_t threshold);
-
- void setResourceNamespace(const std::string& resource_namespace);
-
- void setCredentialsProvider(CredentialsProviderPtr credentials_provider);
-
- void setRegion(const std::string& region);
-
- TransactionPtr prepare(MQMessage& message);
-
-private:
- std::shared_ptr<ProducerImpl> impl_;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/DefaultMQPullConsumer.h b/api/rocketmq/DefaultMQPullConsumer.h
deleted file mode 100644
index 9bbfc60..0000000
--- a/api/rocketmq/DefaultMQPullConsumer.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <chrono>
-#include <future>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "AsyncCallback.h"
-#include "ConsumeType.h"
-#include "CredentialsProvider.h"
-#include "MQMessageExt.h"
-#include "MQMessageQueue.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class PullConsumerImpl;
-
-class DefaultMQPullConsumer {
-public:
- explicit DefaultMQPullConsumer(const std::string& group_name);
-
- void start();
-
- void shutdown();
-
- std::future<std::vector<MQMessageQueue>> queuesFor(const std::string& topic);
-
- std::future<int64_t> queryOffset(const OffsetQuery& query);
-
- bool pull(const PullMessageQuery& request, PullResult& pull_result);
-
- void pull(const PullMessageQuery& request, PullCallback* callback);
-
- void setResourceNamespace(const std::string& resource_namespace);
-
- void setNamesrvAddr(const std::string& name_srv);
-
- void setNameServerListDiscoveryEndpoint(const std::string& discovery_endpoint);
-
- void setCredentialsProvider(std::shared_ptr<CredentialsProvider> credentials_provider);
-
-private:
- std::shared_ptr<PullConsumerImpl> impl_;
-};
-
-ROCKETMQ_NAMESPACE_END
diff --git a/api/rocketmq/DefaultMQPushConsumer.h b/api/rocketmq/DefaultMQPushConsumer.h
deleted file mode 100644
index 0693b8d..0000000
--- a/api/rocketmq/DefaultMQPushConsumer.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include "AsyncCallback.h"
-#include "ConsumeType.h"
-#include "CredentialsProvider.h"
-#include "ExpressionType.h"
-#include "Logger.h"
-#include "MQMessageQueue.h"
-#include "MessageListener.h"
-#include "rocketmq/Executor.h"
-#include "rocketmq/MessageModel.h"
-#include "rocketmq/OffsetStore.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class PushConsumerImpl;
-
-class DefaultMQPushConsumer {
-public:
- explicit DefaultMQPushConsumer(const std::string& group_name);
-
- ~DefaultMQPushConsumer() = default;
-
- void start();
-
- void shutdown();
-
- void subscribe(const std::string& topic, const std::string& expression,
- ExpressionType expression_type = ExpressionType::TAG);
-
- void setConsumeFromWhere(ConsumeFromWhere policy);
-
- void registerMessageListener(MessageListener* listener);
-
- void setNamesrvAddr(const std::string& name_srv);
-
- void setNameServerListDiscoveryEndpoint(const std::string& discovery_endpoint);
-
- void setGroupName(const std::string& group_name);
-
- void setConsumeThreadCount(int thread_count);
-
- void setInstanceName(const std::string& instance_name);
-
- int getProcessQueueTableSize();
-
- void setUnitName(std::string unit_name);
-
- const std::string& getUnitName() const;
-
- void enableTracing(bool enabled);
-
- bool isTracingEnabled();
-
- /**
- * SDK of this version always uses asynchronous IO operation. As such, this
- * function is no-op to keep backward compatibility.
- */
- void setAsyncPull(bool);
-
- /**
- * Maximum number of messages passed to each callback.
- * @param batch_size Batch size
- */
- void setConsumeMessageBatchMaxSize(int batch_size);
-
- /**
- * Lifecycle of executor is managed by external application. Passed-in
- * executor should remain valid after consumer start and before stopping.
- * @param executor Executor pool used to invoke consume callback.
- */
- void setCustomExecutor(const Executor& executor);
-
- /**
- * This function sets maximum number of message that may be consumed per
- * second.
- * @param topic Topic to control
- * @param threshold Threshold before throttling is enforced.
- */
- void setThrottle(const std::string& topic, uint32_t threshold);
-
- /**
- * Set abstract-resource-namespace, in which canonical name of topic, group
- * remains unique.
- * @param resource_namespace Abstract resource namespace.
- */
- void setResourceNamespace(const std::string& resource_namespace);
-
- void setCredentialsProvider(CredentialsProviderPtr credentials_provider);
-
- void setMessageModel(MessageModel message_model);
-
- std::string groupName() const;
-
- void setOffsetStore(std::unique_ptr<OffsetStore> offset_store);
-
-private:
- std::shared_ptr<PushConsumerImpl> impl_;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/ErrorCode.h b/api/rocketmq/ErrorCode.h
index c3ebb7a..5068c83 100644
--- a/api/rocketmq/ErrorCode.h
+++ b/api/rocketmq/ErrorCode.h
@@ -24,8 +24,7 @@
ROCKETMQ_NAMESPACE_BEGIN
-enum class ErrorCode : int
-{
+enum class ErrorCode : int {
Success = 0,
/**
@@ -34,6 +33,11 @@ enum class ErrorCode : int
*/
IllegalState = 1,
+ /**
+ * @brief Broker has processed the request but is not going to return any content.
+ */
+ NoContent = 204,
+
/**
* @brief Bad configuration. For example, negative max-attempt-times.
*
@@ -48,6 +52,11 @@ enum class ErrorCode : int
*/
BadRequest = 400,
+ /**
+ * @brief To publish FIFO messages, only synchronous API is supported.
+ */
+ BadRequestAsyncPubFifoMessage = 40001,
+
/**
* @brief Authentication failed. Possibly caused by invalid credentials.
*
@@ -68,6 +77,10 @@ enum class ErrorCode : int
*/
NotFound = 404,
+ TopicNotFound = 404001,
+
+ GroupNotFound = 404002,
+
/**
* @brief Timeout when connecting, reading from or writing to brokers.
*
diff --git a/src/main/cpp/rocketmq/include/FilterExpression.h b/api/rocketmq/FilterExpression.h
similarity index 84%
rename from src/main/cpp/rocketmq/include/FilterExpression.h
rename to api/rocketmq/FilterExpression.h
index 51cd89a..19e910a 100644
--- a/src/main/cpp/rocketmq/include/FilterExpression.h
+++ b/api/rocketmq/FilterExpression.h
@@ -18,8 +18,8 @@
#include <string>
-#include "rocketmq/ExpressionType.h"
-#include "rocketmq/MQMessageExt.h"
+#include "ExpressionType.h"
+#include "Message.h"
ROCKETMQ_NAMESPACE_BEGIN
@@ -27,14 +27,14 @@ ROCKETMQ_NAMESPACE_BEGIN
* Server supported message filtering expression. At present, two types are supported: tag and SQL92.
*/
struct FilterExpression {
- explicit FilterExpression(std::string expression, ExpressionType expression_type = ExpressionType::TAG)
+ FilterExpression(std::string expression, ExpressionType expression_type = ExpressionType::TAG)
: content_(std::move(expression)), type_(expression_type), version_(std::chrono::steady_clock::now()) {
if (ExpressionType::TAG == type_ && content_.empty()) {
content_ = WILD_CARD_TAG;
}
}
- bool accept(const MQMessageExt& message) const;
+ bool accept(const Message& message) const;
std::string content_;
ExpressionType type_;
diff --git a/api/rocketmq/MQMessage.h b/api/rocketmq/MQMessage.h
deleted file mode 100644
index e5d27fa..0000000
--- a/api/rocketmq/MQMessage.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <chrono>
-#include <map>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "absl/strings/string_view.h"
-
-#include "MQMessageQueue.h"
-#include "MessageType.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class MessageImpl;
-
-class MessageAccessor;
-
-class MQMessage {
-public:
- MQMessage();
- MQMessage(const std::string& topic, const std::string& body);
- MQMessage(const std::string& topic, const std::string& tags, const std::string& body);
- MQMessage(const std::string& topic, const std::string& tags, const std::string& keys, const std::string& body);
-
- virtual ~MQMessage();
-
- MQMessage(const MQMessage& other);
- MQMessage& operator=(const MQMessage& other);
-
- const std::string& getMsgId() const;
-
- void setProperty(const std::string& name, const std::string& value);
- std::string getProperty(const std::string& name) const;
-
- const std::string& getTopic() const;
- void setTopic(const std::string& topic);
- void setTopic(const char* data, int len);
-
- std::string getTags() const;
- void setTags(const std::string& tags);
-
- const std::vector<std::string>& getKeys() const;
-
- /**
- * @brief Add a unique key for the message
- * TODO: a message may be associated with multiple keys. setKey, actually mean
- * attach the given key to the message. Better rename it.
- * @param key Unique key in perspective of bussiness logic.
- */
- void setKey(const std::string& key);
- void setKeys(const std::vector<std::string>& keys);
-
- int getDelayTimeLevel() const;
- void setDelayTimeLevel(int level);
-
- const std::string& traceContext() const;
- void traceContext(const std::string& trace_context);
-
- std::string getBornHost() const;
-
- std::chrono::system_clock::time_point deliveryTimestamp() const;
-
- const std::string& getBody() const;
- void setBody(const char* data, int len);
- void setBody(const std::string& body);
-
- uint32_t bodyLength() const;
-
- const std::map<std::string, std::string>& getProperties() const;
- void setProperties(const std::map<std::string, std::string>& properties);
-
- void messageType(MessageType message_type);
- MessageType messageType() const;
-
- void bindMessageGroup(absl::string_view message_group);
-
- void bindMessageQueue(const MQMessageQueue& message_queue) {
- message_queue_ = message_queue;
- }
-
- const std::string& messageGroup() const;
-
- const MQMessageQueue& messageQueue() const {
- return message_queue_;
- }
-
-protected:
- MessageImpl* impl_;
-
- friend class MessageAccessor;
-
-private:
- MQMessageQueue message_queue_;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MQMessageExt.h b/api/rocketmq/MQMessageExt.h
deleted file mode 100644
index ed95484..0000000
--- a/api/rocketmq/MQMessageExt.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <chrono>
-
-#include "MQMessage.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class MessageAccessor;
-
-class MQMessageExt : public MQMessage {
-public:
- MQMessageExt();
-
- MQMessageExt(const MQMessageExt& other);
-
- MQMessageExt& operator=(const MQMessageExt& other);
-
- int32_t getQueueId() const;
-
- /**
- * @return Milli-seconds since epoch in perspective of system_clock.
- */
- int64_t getBornTimestamp() const;
-
- std::chrono::system_clock::time_point bornTimestamp() const;
-
- std::chrono::system_clock::time_point storeTimestamp() const;
- int64_t getStoreTimestamp() const;
-
- std::string getStoreHost() const;
-
- int64_t getQueueOffset() const;
-
- int32_t getDeliveryAttempt() const;
-
- const std::string& receiptHandle() const;
-
- bool operator==(const MQMessageExt& other);
-
- friend class MessageAccessor;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MQMessageQueue.h b/api/rocketmq/MQMessageQueue.h
deleted file mode 100644
index ec62b3d..0000000
--- a/api/rocketmq/MQMessageQueue.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <functional>
-#include <sstream>
-#include <string>
-
-#include "RocketMQ.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class MQMessageQueue {
-public:
- MQMessageQueue() = default;
-
- MQMessageQueue(std::string topic, std::string broker_name, int queue_id)
- : topic_(std::move(topic)), broker_name_(std::move(broker_name)), queue_id_(queue_id) {
- }
-
- MQMessageQueue(const MQMessageQueue& other) {
- this->operator=(other);
- }
-
- MQMessageQueue(MQMessageQueue&& other) noexcept {
- topic_ = std::move(other.topic_);
- broker_name_ = std::move(other.broker_name_);
- queue_id_ = other.queue_id_;
- service_address_ = other.service_address_;
- }
-
- MQMessageQueue& operator=(const MQMessageQueue& other) {
- if (this == &other) {
- return *this;
- }
-
- topic_ = other.topic_;
- broker_name_ = other.broker_name_;
- queue_id_ = other.queue_id_;
- service_address_ = other.service_address_;
- return *this;
- }
-
- const std::string& getTopic() const {
- return topic_;
- }
-
- void setTopic(const std::string& topic) {
- topic_ = topic;
- }
-
- const std::string& getBrokerName() const {
- return broker_name_;
- }
-
- void setBrokerName(const std::string& broker_name) {
- broker_name_ = broker_name;
- }
-
- int getQueueId() const {
- return queue_id_;
- }
-
- void setQueueId(int queue_id) {
- queue_id_ = queue_id;
- }
-
- bool operator!=(const MQMessageQueue& rhs) const {
- return topic_ != rhs.topic_ || broker_name_ != rhs.broker_name_ || queue_id_ != rhs.queue_id_;
- }
-
- bool operator==(const MQMessageQueue& mq) const {
- return topic_ == mq.topic_ && broker_name_ == mq.broker_name_ && queue_id_ == mq.queue_id_;
- }
-
- bool operator<(const MQMessageQueue& mq) const {
- if (topic_ != mq.topic_) {
- return topic_ < mq.topic_;
- }
-
- if (broker_name_ != mq.broker_name_) {
- return broker_name_ < mq.broker_name_;
- }
-
- return queue_id_ < mq.queue_id_;
- }
-
- operator bool() const {
- return !topic_.empty() && !broker_name_.empty() && queue_id_ >= 0;
- }
-
- int compareTo(const MQMessageQueue& mq) const {
- if (this == &mq) {
- return 0;
- }
-
- if (this->operator<(mq)) {
- return -1;
- }
-
- if (mq.operator<(*this)) {
- return 1;
- }
-
- return 0;
- }
-
- std::string simpleName() const {
- return topic_ + "_" + broker_name_ + "_" + std::to_string(queue_id_);
- }
-
- std::string toString() const {
- std::stringstream ss;
- ss << "MessageQueue [topic=" << topic_ << ", brokerName=" << broker_name_ << ", queueId=" << queue_id_ << "]";
- return ss.str();
- }
-
- template <typename H>
- friend H AbslHashValue(H h, const MQMessageQueue& mq) {
- return H::combine(std::move(h), mq.topic_, mq.broker_name_, mq.queue_id_);
- }
-
- const std::string& serviceAddress() const {
- return service_address_;
- }
-
- void serviceAddress(std::string service_address) {
- service_address_ = std::move(service_address);
- }
-
-private:
- std::string topic_;
- std::string broker_name_;
- int queue_id_{0};
-
- std::string service_address_;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/Message.h b/api/rocketmq/Message.h
new file mode 100644
index 0000000..0537fa4
--- /dev/null
+++ b/api/rocketmq/Message.h
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <cassert>
+#include <chrono>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "RocketMQ.h"
+#include "absl/types/optional.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class MessageBuilder;
+
+/**
+ * @brief Extension is intended for internal use only, which is subject to change without notice.
+ */
+struct Extension {
+ std::chrono::system_clock::time_point store_time{std::chrono::system_clock::now()};
+ std::string store_host;
+ std::chrono::system_clock::time_point delivery_timepoint{std::chrono::system_clock::now()};
+ std::uint16_t delivery_attempt{0};
+ std::chrono::system_clock::time_point decode_time{std::chrono::system_clock::now()};
+ std::chrono::system_clock::duration invisible_period{0};
+ std::string receipt_handle;
+ std::string target_endpoint;
+ std::int32_t queue_id{0};
+ std::int64_t offset{0};
+ std::string nonce;
+ std::string transaction_id;
+};
+
+class Message {
+public:
+ const std::string& id() const {
+ return id_;
+ }
+
+ const std::string& topic() const {
+ return topic_;
+ }
+
+ absl::optional<std::string> tag() const {
+ if (tag_.empty()) {
+ return {};
+ }
+ return absl::make_optional(tag_);
+ }
+
+ const std::vector<std::string>& keys() const {
+ return keys_;
+ }
+
+ absl::optional<std::string> traceContext() const {
+ if (trace_context_.empty()) {
+ return {};
+ }
+ return absl::make_optional(trace_context_);
+ }
+
+ const std::string& bornHost() const {
+ return born_host_;
+ }
+
+ const std::chrono::system_clock::time_point& bornTime() const {
+ return born_time_;
+ }
+
+ absl::optional<std::chrono::system_clock::time_point> deliveryTimestamp() const {
+ return delivery_timestamp_;
+ }
+
+ const std::string& body() const {
+ return body_;
+ }
+
+ const std::unordered_map<std::string, std::string>& properties() const {
+ return properties_;
+ }
+
+ absl::optional<std::string> group() const {
+ if (group_.empty()) {
+ return {};
+ }
+ return absl::make_optional(group_);
+ }
+
+ const Extension& extension() const {
+ return extension_;
+ }
+
+ Extension& mutableExtension() {
+ return extension_;
+ }
+
+ static MessageBuilder newBuilder();
+
+protected:
+ friend std::unique_ptr<Message> absl::make_unique<Message>();
+ friend class MessageBuilder;
+
+ Message();
+
+private:
+ std::string id_;
+ std::string topic_;
+ std::string tag_;
+ std::vector<std::string> keys_;
+ std::string trace_context_;
+ std::string born_host_;
+ std::chrono::system_clock::time_point born_time_{std::chrono::system_clock::now()};
+ absl::optional<std::chrono::system_clock::time_point> delivery_timestamp_;
+ std::string body_;
+ std::unordered_map<std::string, std::string> properties_;
+ std::string group_;
+ Extension extension_;
+};
+
+using MessagePtr = std::unique_ptr<Message>;
+using MessageConstPtr = std::unique_ptr<const Message>;
+using MessageConstSharedPtr = std::shared_ptr<const Message>;
+using MessageSharedPtr = std::shared_ptr<Message>;
+
+class MessageBuilder {
+public:
+ MessageBuilder();
+
+ MessageBuilder& withTopic(std::string topic);
+
+ MessageBuilder& withTag(std::string tag);
+
+ MessageBuilder& withKeys(std::vector<std::string> keys);
+
+ MessageBuilder& withTraceContext(std::string trace_context);
+
+ MessageBuilder& withBody(std::string body);
+
+ MessageBuilder& withGroup(std::string group);
+
+ MessageBuilder& withProperties(std::unordered_map<std::string, std::string> properties);
+
+ MessageConstPtr build();
+
+private:
+ friend class ClientManagerImpl;
+
+ MessageBuilder& withId(std::string id);
+
+ MessageBuilder& withBornTime(std::chrono::system_clock::time_point born_time);
+
+ MessageBuilder& withBornHost(std::string born_host);
+
+ MessagePtr message_;
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageListener.h b/api/rocketmq/MessageListener.h
index 5fdf59d..cd5ef05 100644
--- a/api/rocketmq/MessageListener.h
+++ b/api/rocketmq/MessageListener.h
@@ -16,46 +16,13 @@
*/
#pragma once
-#include "MQMessageExt.h"
-#include "MQMessageQueue.h"
+#include <functional>
-ROCKETMQ_NAMESPACE_BEGIN
-
-enum class ConsumeMessageResult : uint8_t
-{
- SUCCESS = 0,
- FAILURE = 1
-};
-
-enum class MessageListenerType : uint8_t
-{
- STANDARD = 0,
- FIFO = 1
-};
-
-class MessageListener {
-public:
- virtual ~MessageListener() = default;
+#include "ConsumeResult.h"
+#include "Message.h"
- virtual MessageListenerType listenerType() = 0;
-};
-
-class StandardMessageListener : public MessageListener {
-public:
- virtual ConsumeMessageResult consumeMessage(const std::vector<MQMessageExt>& msgs) = 0;
-
- MessageListenerType listenerType() override {
- return MessageListenerType::STANDARD;
- }
-};
-
-class FifoMessageListener : public MessageListener {
-public:
- MessageListenerType listenerType() override {
- return MessageListenerType::FIFO;
- }
+ROCKETMQ_NAMESPACE_BEGIN
- virtual ConsumeMessageResult consumeMessage(const MQMessageExt& msgs) = 0;
-};
+using MessageListener = std::function<ConsumeResult(const Message&)>;
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/OffsetStore.h b/api/rocketmq/OffsetStore.h
deleted file mode 100644
index 514d5da..0000000
--- a/api/rocketmq/OffsetStore.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include "MQMessageQueue.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class OffsetStore {
-public:
- virtual ~OffsetStore() = default;
-
- virtual void load() = 0;
-
- virtual void updateOffset(const MQMessageQueue& message_queue, int64_t offset) = 0;
-
- virtual bool readOffset(const MQMessageQueue& message_queue, int64_t& offset) = 0;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/Producer.h b/api/rocketmq/Producer.h
new file mode 100644
index 0000000..cb70065
--- /dev/null
+++ b/api/rocketmq/Producer.h
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <system_error>
+#include <vector>
+
+#include "Configuration.h"
+#include "ErrorCode.h"
+#include "Logger.h"
+#include "Message.h"
+#include "SendCallback.h"
+#include "SendReceipt.h"
+#include "TransactionChecker.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+/**
+ * This class employs pointer-to-implementation paradigm to achieve the goal of stable ABI.
+ * Refer https://en.cppreference.com/w/cpp/language/pimpl for an explanation.
+ */
+class ProducerImpl;
+
+class ProducerBuilder;
+
+/**
+ * @brief
+ *
+ */
+class Producer {
+public:
+ static ProducerBuilder newBuilder();
+
+ /**
+ * @brief Send message synchronously.
+ *
+ * @param message Message to publish. Note the pointer, std::unique_ptr<const Message>, is 'moved' into.
+ * @param ec Error code and message
+ * @return SendReceipt Receipt of the pub action if successful, which holds an identifier for the message.
+ */
+ SendReceipt send(MessageConstPtr message, std::error_code& ec) noexcept;
+
+ /**
+ * @brief Send message in asynchronous manner.
+ *
+ * @param message Message to send. Note the pointer, std::unique_ptr<const Message>, is 'moved' into.
+ * @param callback Callback to execute on completion.
+ */
+ void send(MessageConstPtr message, const SendCallback& callback) noexcept;
+
+private:
+ explicit Producer(std::shared_ptr<ProducerImpl> impl) : impl_(std::move(impl)) {
+ }
+
+ void start();
+
+ std::shared_ptr<ProducerImpl> impl_;
+
+ friend class ProducerBuilder;
+};
+
+class ProducerBuilder {
+public:
+ ProducerBuilder();
+
+ ProducerBuilder& withConfiguration(Configuration configuration);
+
+ ProducerBuilder& withTopics(const std::vector<std::string>& topics);
+
+ ProducerBuilder& withTransactionChecker(const TransactionChecker& checker);
+
+ Producer build();
+
+private:
+ std::shared_ptr<ProducerImpl> impl_;
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/PullResult.h b/api/rocketmq/PullResult.h
deleted file mode 100644
index 2e91ec4..0000000
--- a/api/rocketmq/PullResult.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <cstdlib>
-#include <vector>
-
-#include "MQMessageExt.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class PullResult {
-public:
- PullResult(int64_t min, int64_t max, int64_t next, std::vector<MQMessageExt> messages)
- : min_(min), max_(max), next_(next), messages_(std::move(messages)) {
- }
-
- int64_t min() const {
- return min_;
- }
-
- int64_t max() const {
- return max_;
- }
-
- int64_t next() const {
- return next_;
- }
-
- const std::vector<MQMessageExt>& messages() const {
- return messages_;
- }
-
-private:
- int64_t min_;
- int64_t max_;
- int64_t next_;
- std::vector<MQMessageExt> messages_;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/PushConsumer.h b/api/rocketmq/PushConsumer.h
new file mode 100644
index 0000000..500c34b
--- /dev/null
+++ b/api/rocketmq/PushConsumer.h
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "Configuration.h"
+#include "CredentialsProvider.h"
+#include "Executor.h"
+#include "ExpressionType.h"
+#include "FilterExpression.h"
+#include "Logger.h"
+#include "MessageListener.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class PushConsumerImpl;
+class PushConsumerBuilder;
+
+class PushConsumer {
+public:
+ static PushConsumerBuilder newBuilder();
+
+ void subscribe(std::string topic, FilterExpression filter_expression);
+
+ void unsubscribe(const std::string& topic);
+
+private:
+ friend class PushConsumerBuilder;
+
+ PushConsumer(std::shared_ptr<PushConsumerImpl> impl)
+ : impl_(std::move(impl)) {
+ }
+
+ std::shared_ptr<PushConsumerImpl> impl_;
+};
+
+class PushConsumerBuilder {
+public:
+ PushConsumerBuilder() : configuration_(Configuration::newBuilder().build()) {}
+
+ PushConsumerBuilder &withConfiguration(Configuration configuration) {
+ configuration_ = std::move(configuration);
+ return *this;
+ }
+
+ PushConsumerBuilder &withGroup(std::string group) {
+ group_ = std::move(group);
+ return *this;
+ }
+
+ PushConsumerBuilder &withConsumeThreads(std::size_t consume_thread) {
+ consume_thread_ = consume_thread;
+ return *this;
+ }
+
+ PushConsumerBuilder &withListener(MessageListener listener) {
+ listener_ = std::move(listener);
+ return *this;
+ }
+
+ PushConsumerBuilder &subscribe(std::string topic,
+ FilterExpression filter_expression) {
+ subscriptions_.insert({topic, filter_expression});
+ return *this;
+ }
+
+ PushConsumer build();
+
+private:
+ std::string group_;
+ Configuration configuration_;
+ std::size_t consume_thread_;
+ MessageListener listener_;
+
+ std::unordered_map<std::string, FilterExpression> subscriptions_;
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageModel.h b/api/rocketmq/SendCallback.h
similarity index 82%
copy from api/rocketmq/MessageModel.h
copy to api/rocketmq/SendCallback.h
index 2422d32..8468f63 100644
--- a/api/rocketmq/MessageModel.h
+++ b/api/rocketmq/SendCallback.h
@@ -16,16 +16,14 @@
*/
#pragma once
-#include "RocketMQ.h"
+#include <functional>
+#include <system_error>
-#include <cstdint>
+#include "RocketMQ.h"
+#include "SendReceipt.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class MessageModel : int8_t
-{
- BROADCASTING,
- CLUSTERING,
-};
+using SendCallback = std::function<void(const std::error_code&, const SendReceipt&)>;
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageModel.h b/api/rocketmq/SendReceipt.h
similarity index 86%
copy from api/rocketmq/MessageModel.h
copy to api/rocketmq/SendReceipt.h
index 2422d32..06a01cc 100644
--- a/api/rocketmq/MessageModel.h
+++ b/api/rocketmq/SendReceipt.h
@@ -16,16 +16,18 @@
*/
#pragma once
-#include "RocketMQ.h"
-
#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "RocketMQ.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class MessageModel : int8_t
-{
- BROADCASTING,
- CLUSTERING,
+struct SendReceipt {
+ std::string message_id;
+
+ std::string transaction_id;
};
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/SendResult.h b/api/rocketmq/SendResult.h
deleted file mode 100644
index b491cc6..0000000
--- a/api/rocketmq/SendResult.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <utility>
-
-#include "MQMessageQueue.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-enum class SendStatus : int8_t
-{
- SEND_OK,
-
- // Deprecated. Remove in the next release.
- SEND_FLUSH_DISK_TIMEOUT,
-
- // Deprecated. Remove in the next release.
- SEND_FLUSH_SLAVE_TIMEOUT,
-
- // Deprecated. Remove in the next release.
- SEND_SLAVE_NOT_AVAILABLE
-};
-
-class SendResult {
-public:
- SendResult() = default;
-
- SendResult(const SendStatus& send_status, std::string msg_id, MQMessageQueue message_queue, long long queue_offset,
- std::string region_id)
- : send_status_(send_status), message_id_(std::move(msg_id)), message_queue_(std::move(message_queue)),
- queue_offset_(queue_offset), region_id_(std::move(region_id)) {
- }
-
- SendResult(const SendResult& other) {
- this->operator=(other);
- }
-
- SendResult& operator=(const SendResult& other) {
- if (this == &other) {
- return *this;
- }
-
- send_status_ = other.send_status_;
- message_id_ = other.message_id_;
- message_queue_ = other.message_queue_;
- queue_offset_ = other.queue_offset_;
- transaction_id_ = other.transaction_id_;
- region_id_ = other.region_id_;
- return *this;
- }
-
- const std::string& getMsgId() const {
- return message_id_;
- }
-
- void setMsgId(const std::string& msg_id) {
- message_id_ = msg_id;
- }
-
- const std::string& getRegionId() const {
- return region_id_;
- }
-
- void setRegionId(const std::string& region_id) {
- region_id_ = region_id;
- }
-
- SendStatus getSendStatus() const {
- return send_status_;
- }
-
- void setSendStatus(const SendStatus& send_status) {
- send_status_ = send_status;
- }
-
- MQMessageQueue& getMessageQueue() const {
- return message_queue_;
- }
-
- void setMessageQueue(const MQMessageQueue& message_queue) {
- message_queue_ = message_queue;
- }
-
- long long getQueueOffset() const {
- return queue_offset_;
- }
-
- void setQueueOffset(long long queue_offset) {
- queue_offset_ = queue_offset;
- }
-
- const std::string& getTransactionId() const {
- return transaction_id_;
- }
-
- void setTransactionId(const std::string& transaction_id) {
- transaction_id_ = transaction_id;
- }
-
- const std::string& traceContext() const {
- return trace_context_;
- }
-
- void traceContext(std::string trace_context) {
- trace_context_ = std::move(trace_context);
- }
-
- operator bool() {
- return !message_id_.empty();
- }
-
-private:
- SendStatus send_status_{SendStatus::SEND_OK};
- std::string message_id_;
- mutable MQMessageQueue message_queue_;
- long long queue_offset_{0};
- std::string transaction_id_;
- std::string region_id_;
- std::string trace_context_;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/SimpleConsumer.h b/api/rocketmq/SimpleConsumer.h
new file mode 100644
index 0000000..0f7030f
--- /dev/null
+++ b/api/rocketmq/SimpleConsumer.h
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <unordered_map>
+#include <vector>
+
+#include "Configuration.h"
+#include "FilterExpression.h"
+#include "Message.h"
+#include "RocketMQ.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+using ReceiveCallback = std::function<void(const std::error_code&, const std::vector<MessageConstSharedPtr>&)>;
+
+using AckCallback = std::function<void(const std::error_code&)>;
+
+using ChangeInvisibleDurationCallback = std::function<void(const std::error_code&)>;
+
+class SimpleConsumerImpl;
+
+class SimpleConsumerBuilder;
+
+class SimpleConsumer {
+public:
+ ~SimpleConsumer();
+
+ static SimpleConsumerBuilder newBuilder();
+
+ void subscribe(std::string topic, FilterExpression filter_expression);
+
+ void unsubscribe(const std::string& topic);
+
+ void receive(std::size_t limit,
+ std::chrono::milliseconds invisible_duration,
+ std::error_code& ec,
+ std::vector<MessageConstSharedPtr>& messages);
+
+ void asyncReceive(std::size_t limit, std::chrono::milliseconds invisible_duration, ReceiveCallback callback);
+
+ void ack(const Message& message, std::error_code& ec);
+
+ void asyncAck(const Message& message, AckCallback callback);
+
+ void changeInvisibleDuration(const Message& message, std::chrono::milliseconds duration, std::error_code& ec);
+
+ void asyncChangeInvisibleDuration(const Message& message,
+ std::chrono::milliseconds duration,
+ ChangeInvisibleDurationCallback callback);
+
+private:
+ std::shared_ptr<SimpleConsumerImpl> impl_;
+
+ SimpleConsumer(std::string group);
+
+ void start();
+
+ friend class SimpleConsumerBuilder;
+};
+
+class SimpleConsumerBuilder {
+public:
+ SimpleConsumerBuilder();
+
+ SimpleConsumerBuilder& withGroup(std::string group) {
+ group_ = std::move(group);
+ return *this;
+ }
+
+ SimpleConsumerBuilder& subscribe(std::string topic, FilterExpression expression) {
+ subscriptions_.insert({std::move(topic), std::move(expression)});
+ return *this;
+ }
+
+ SimpleConsumerBuilder& withConfiguration(Configuration configuration) {
+ configuration_ = std::move(configuration);
+ return *this;
+ }
+
+ SimpleConsumer build();
+
+private:
+ // Group name the consumer belongs to
+ std::string group_;
+
+ Configuration configuration_;
+
+ std::unordered_map<std::string, FilterExpression> subscriptions_;
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageModel.h b/api/rocketmq/Tracing.h
similarity index 87%
copy from api/rocketmq/MessageModel.h
copy to api/rocketmq/Tracing.h
index 2422d32..bc12362 100644
--- a/api/rocketmq/MessageModel.h
+++ b/api/rocketmq/Tracing.h
@@ -16,16 +16,12 @@
*/
#pragma once
-#include "RocketMQ.h"
+#include "opencensus/trace/sampler.h"
-#include <cstdint>
+#include "RocketMQ.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class MessageModel : int8_t
-{
- BROADCASTING,
- CLUSTERING,
-};
+opencensus::trace::Sampler* traceSampler() __attribute__((weak));
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
+ROCKETMQ_NAMESPACE_END
diff --git a/api/rocketmq/Transaction.h b/api/rocketmq/Transaction.h
index 9a135a6..2728d12 100644
--- a/api/rocketmq/Transaction.h
+++ b/api/rocketmq/Transaction.h
@@ -34,17 +34,18 @@ public:
virtual bool rollback() = 0;
- virtual std::string messageId() const = 0;
+ virtual const std::string& topic() const = 0;
- virtual std::string transactionId() const = 0;
-};
+ virtual const std::string& messageId() const = 0;
-using TransactionPtr = std::unique_ptr<Transaction>;
+ virtual const std::string& transactionId() const = 0;
+
+ virtual const std::string& traceContext() const = 0;
-enum class TransactionState : int8_t
-{
- COMMIT = 0,
- ROLLBACK = 1,
+ virtual const std::string& endpoint() const = 0;
};
+using TransactionPtr = std::unique_ptr<Transaction>;
+using TransactionConstPtr = std::unique_ptr<const Transaction>;
+
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/include/DigestType.h b/api/rocketmq/TransactionChecker.h
similarity index 83%
copy from src/main/cpp/base/include/DigestType.h
copy to api/rocketmq/TransactionChecker.h
index e255d82..604e7bd 100644
--- a/src/main/cpp/base/include/DigestType.h
+++ b/api/rocketmq/TransactionChecker.h
@@ -16,17 +16,13 @@
*/
#pragma once
-#include <cstdint>
+#include <functional>
-#include "rocketmq/RocketMQ.h"
+#include "Message.h"
+#include "TransactionState.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class DigestType : int8_t
-{
- CRC32 = 0,
- MD5 = 1,
- SHA1 = 2,
-};
+using TransactionChecker = std::function<TransactionState(const Message&)>;
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageType.h b/api/rocketmq/TransactionState.h
similarity index 88%
rename from api/rocketmq/MessageType.h
rename to api/rocketmq/TransactionState.h
index 8d4ea26..decdf21 100644
--- a/api/rocketmq/MessageType.h
+++ b/api/rocketmq/TransactionState.h
@@ -22,12 +22,9 @@
ROCKETMQ_NAMESPACE_BEGIN
-enum class MessageType : int8_t
-{
- NORMAL = 0,
- FIFO = 1,
- DELAY = 2,
- TRANSACTION = 3,
+enum class TransactionState : int8_t {
+ COMMIT = 0,
+ ROLLBACK = 1,
};
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/bazel/rocketmq_deps.bzl b/bazel/rocketmq_deps.bzl
index d593bee..7282dd7 100644
--- a/bazel/rocketmq_deps.bzl
+++ b/bazel/rocketmq_deps.bzl
@@ -9,6 +9,17 @@ def rocketmq_deps():
actual = "@com_github_opentelemetry//api:api",
)
+ if "rules_python" not in native.existing_rules():
+ http_archive(
+ name = "rules_python",
+ sha256 = "cdf6b84084aad8f10bf20b46b77cb48d83c319ebe6458a18e9d2cebf57807cdd",
+ strip_prefix = "rules_python-0.8.1",
+ urls = [
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/rules-python/rules_python-0.8.1.tar.gz",
+ "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.1.tar.gz",
+ ],
+ )
+
if "com_google_googletest" not in native.existing_rules():
http_archive(
name = "com_google_googletest",
@@ -55,60 +66,47 @@ def rocketmq_deps():
if "com_google_protobuf" not in native.existing_rules():
http_archive(
name = "com_google_protobuf",
- sha256 = "36f81e03a0702f8f935fffd5a486dac1c0fc6d4bae1cd02c7a32448ad6e63bcb",
- strip_prefix = "protobuf-3.17.2",
+ sha256 = "8b28fdd45bab62d15db232ec404248901842e5340299a57765e48abe8a80d930",
+ strip_prefix = "protobuf-3.20.1",
urls = [
- "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.17.2.tar.gz",
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/protobuf/protobuf-3.20.1.tar.gz",
+ "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.20.1.tar.gz",
],
)
if "rules_proto_grpc" not in native.existing_rules():
http_archive(
name = "rules_proto_grpc",
- sha256 = "7954abbb6898830cd10ac9714fbcacf092299fda00ed2baf781172f545120419",
- strip_prefix = "rules_proto_grpc-3.1.1",
- urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/3.1.1.tar.gz"],
+ sha256 = "507e38c8d95c7efa4f3b1c0595a8e8f139c885cb41a76cab7e20e4e67ae87731",
+ strip_prefix = "rules_proto_grpc-4.1.1",
+ urls = [
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/rules_proto_grpc/rules_proto_grpc-4.1.1.tar.gz",
+ "https://github.com/rules-proto-grpc/rules_proto_grpc/archive/refs/tags/4.1.1.tar.gz"
+ ],
)
if "com_google_absl" not in native.existing_rules():
http_archive(
name = "com_google_absl",
- sha256 = "59b862f50e710277f8ede96f083a5bb8d7c9595376146838b9580be90374ee1f",
- strip_prefix = "abseil-cpp-20210324.2",
+ sha256 = "dcf71b9cba8dc0ca9940c4b316a0c796be8fab42b070bb6b7cab62b48f0e66c4",
+ strip_prefix = "abseil-cpp-20211102.0",
urls = [
- "https://github.com/abseil/abseil-cpp/archive/refs/tags/20210324.2.tar.gz",
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/abseil/abseil-cpp-20211102.0.tar.gz",
+ "https://github.com/abseil/abseil-cpp/archive/refs/tags/20211102.0.tar.gz",
],
)
if "com_github_grpc_grpc" not in native.existing_rules():
http_archive(
name = "com_github_grpc_grpc",
- strip_prefix = "grpc-1.39.0",
- sha256 = "b16992aa1c949c10d5d5ce2a62f9d99fa7de77da2943e643fb66dcaf075826d6",
- urls = ["https://github.com/grpc/grpc/archive/v1.39.0.tar.gz"],
- )
-
- if "io_opentelemetry_cpp" not in native.existing_rules():
- http_archive(
- name = "io_opentelemetry_cpp",
- sha256 = "24ba9b83f6cb8ba717ae30ebc570f5e8d0569008aee3c8b9a7ce6e4e1a5115b7",
- strip_prefix = "opentelemetry-cpp-1.0.0-rc4",
+ strip_prefix = "grpc-1.46.0",
+ sha256 = "67423a4cd706ce16a88d1549297023f0f9f0d695a96dd684adc21e67b021f9bc",
urls = [
- "https://github.com/open-telemetry/opentelemetry-cpp/archive/refs/tags/v1.0.0-rc4.tar.gz",
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/grpc/grpc-1.46.0.tar.gz",
+ "https://github.com/grpc/grpc/archive/refs/tags/v1.46.0.tar.gz",
],
)
- maybe(
- http_archive,
- name = "com_github_opentelemetry_proto",
- build_file = "@io_opentelemetry_cpp//bazel:opentelemetry_proto.BUILD",
- sha256 = "08f090570e0a112bfae276ba37e9c45bf724b64d902a7a001db33123b840ebd6",
- strip_prefix = "opentelemetry-proto-0.6.0",
- urls = [
- "https://github.com/open-telemetry/opentelemetry-proto/archive/v0.6.0.tar.gz",
- ],
- )
-
maybe(
http_archive,
name = "asio",
@@ -137,4 +135,25 @@ def rocketmq_deps():
"https://github.com/googleapis/googleapis/archive/af7fb72df59a814221b123a4d1acb3f6c3e6cc95.zip"
],
strip_prefix = "googleapis-af7fb72df59a814221b123a4d1acb3f6c3e6cc95",
+ )
+
+ maybe(
+ http_archive,
+ name = "hedron_compile_commands",
+ sha256 = "4f69ccafa253825d93191977dcbcecee74e576aadbd21f1cfb25a19111ecdf21",
+ urls = [
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/bazel-compile-commands-extractor/bazel-compile-commands-extractor-1.0.tar.gz",
+ "https://github.com/lizhanhui/bazel-compile-commands-extractor/archive/refs/tags/v1.0.tar.gz",
+ ],
+ strip_prefix = "bazel-compile-commands-extractor-1.0",
+ )
+
+ maybe(
+ http_archive,
+ name = "rules_swift",
+ urls = [
+ "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/rules_swift/rules_swift-0.27.0.tar.gz",
+ "https://github.com/bazelbuild/rules_swift/archive/refs/tags/0.27.0.tar.gz",
+ ],
+ strip_prefix = "rules_swift-0.27.0",
)
\ No newline at end of file
diff --git a/example/rocketmq/ExampleAsyncProducer.cpp b/example/rocketmq/ExampleAsyncProducer.cpp
deleted file mode 100644
index 083cb34..0000000
--- a/example/rocketmq/ExampleAsyncProducer.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "rocketmq/DefaultMQProducer.h"
-#include "rocketmq/ErrorCode.h"
-#include <algorithm>
-#include <array>
-#include <atomic>
-#include <condition_variable>
-#include <iostream>
-#include <mutex>
-#include <random>
-#include <system_error>
-
-using namespace rocketmq;
-
-int getAndReset(std::atomic_int& counter) {
- int current;
- while (true) {
- current = counter.load(std::memory_order_relaxed);
- if (counter.compare_exchange_weak(current, 0, std::memory_order_relaxed)) {
- break;
- }
- }
- return current;
-}
-
-const std::string& alphaNumeric() {
- static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
- return alpha_numeric;
-}
-
-std::string randomString(std::string::size_type len) {
- std::string result;
- result.reserve(len);
- std::random_device rd;
- std::mt19937 generator(rd());
- std::string source(alphaNumeric());
- std::string::size_type generated = 0;
- while (generated < len) {
- std::shuffle(source.begin(), source.end(), generator);
- std::string::size_type delta = std::min({len - generated, source.length()});
- result.append(source.substr(0, delta));
- generated += delta;
- }
- return result;
-}
-
-template <int PARTITION>
-class RateLimiter {
-public:
- explicit RateLimiter(int permit) : permits_{0}, interval_(1000 / PARTITION), stopped_(false) {
- int avg = permit / PARTITION;
- for (auto& i : partition_) {
- i = avg;
- }
-
- int r = permit % PARTITION;
-
- if (r) {
- int step = PARTITION / r;
- for (int i = 0; i < r; ++i) {
- partition_[i * step]++;
- }
- }
-
- auto lambda_tick = [this]() {
- while (!stopped_) {
- tick();
- }
- };
-
- thread_tick_ = std::thread(lambda_tick);
- }
-
- ~RateLimiter() {
- stopped_.store(true, std::memory_order_relaxed);
- if (thread_tick_.joinable()) {
- thread_tick_.join();
- }
- }
-
- std::array<int, PARTITION>& partition() {
- return permits_;
- }
-
- int slot() {
- auto current = std::chrono::steady_clock::now();
- long ms = std::chrono::duration_cast<std::chrono::milliseconds>(current.time_since_epoch()).count();
- return ms / interval_ % PARTITION;
- }
-
- void acquire() {
- int idx = slot();
- {
- std::unique_lock<std::mutex> lk(mtx_);
- if (permits_[idx] > 0) {
- --permits_[idx];
- return;
- }
-
- // Reuse quota of the past half of the cycle
- for (int j = 1; j <= PARTITION / 2; ++j) {
- int index = idx - j;
- if (index < 0) {
- index += PARTITION;
- }
- if (permits_[index] > 0) {
- --permits_[index];
- return;
- }
- }
-
- cv_.wait(lk, [this]() {
- int idx = slot();
- return permits_[idx] > 0;
- });
- idx = slot();
- --permits_[idx];
- }
- }
-
- void tick() {
- std::this_thread::sleep_for(std::chrono::milliseconds(1000 / PARTITION));
- int idx = slot();
- {
- std::unique_lock<std::mutex> lk(mtx_);
- permits_[idx] = partition_[idx];
- cv_.notify_all();
- }
- }
-
-private:
- std::array<int, PARTITION> partition_;
- std::array<int, PARTITION> permits_;
- int interval_;
- std::mutex mtx_;
- std::condition_variable cv_;
-
- std::atomic_bool stopped_;
- std::thread thread_tick_;
-};
-
-class SampleSendCallback : public rocketmq::SendCallback {
-public:
- SampleSendCallback(std::atomic_int& counter, std::atomic_int& error) : counter_(counter), error_(error) {
- }
-
- void onSuccess(SendResult& send_result) noexcept override {
- counter_.fetch_add(1, std::memory_order_relaxed);
- }
-
- void onFailure(const std::error_code& ec) noexcept override {
- error_.fetch_add(1, std::memory_order_relaxed);
- }
-
-private:
- std::atomic_int& counter_;
- std::atomic_int& error_;
-};
-
-int main(int argc, char* argv[]) {
- std::string::size_type body_size = 1024;
- int duration = 300;
- int qps = 1000;
-
- if (argc > 1) {
- body_size = std::stoi(argv[1]);
- }
-
- if (argc > 2) {
- duration = std::stoi(argv[2]);
- }
-
- if (argc > 3) {
- qps = std::stoi(argv[3]);
- }
-
- Logger& logger = getLogger();
- logger.setLevel(Level::Info);
- logger.init();
-
- const char* topic = "cpp_sdk_standard";
- const char* tag = "TagA";
- DefaultMQProducer producer("TestGroup");
- producer.setNamesrvAddr("47.98.116.189:80");
- producer.compressBodyThreshold(256);
- const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7";
- producer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
- producer.setResourceNamespace(resource_namespace);
- producer.setRegion("cn-hangzhou-pre");
- MQMessage message;
- message.setTopic(topic);
- message.setTags(tag);
- message.setKey("Yuck! Why-plural?");
- message.setBody(randomString(body_size));
-
- std::cout << "Message Body: " << message.getBody() << std::endl;
-
- std::atomic_bool stopped(false);
-
- auto lambda = [&stopped, duration]() {
- std::cout << "Benchmark will stop in " << duration << " seconds!" << std::endl;
- std::this_thread::sleep_for(std::chrono::seconds(duration));
- stopped.store(true);
- };
-
- std::thread t(lambda);
-
- std::atomic_int success(0);
- std::atomic_int error(0);
-
- auto stats_lambda = [&stopped, &success, &error]() {
- while (!stopped) {
- std::this_thread::sleep_for(std::chrono::seconds(1));
- std::cout << "Success:" << getAndReset(success) << ", Error: " << getAndReset(error) << std::endl;
- }
- };
-
- std::thread stats_thread(stats_lambda);
-
- RateLimiter<10> rate_limiter(qps);
- SampleSendCallback send_callback(success, error);
-
- try {
- producer.start();
- while (!stopped) {
- rate_limiter.acquire();
- producer.send(message, &send_callback, true);
- }
- } catch (...) {
- std::cerr << "Ah...No!!!" << std::endl;
- }
-
- if (stats_thread.joinable()) {
- stats_thread.join();
- }
-
- if (t.joinable()) {
- t.join();
- }
- producer.shutdown();
- return EXIT_SUCCESS;
-}
\ No newline at end of file
diff --git a/example/rocketmq/ExampleBroadcastPushConsumer.cpp b/example/rocketmq/ExampleBroadcastPushConsumer.cpp
deleted file mode 100644
index 529f1e6..0000000
--- a/example/rocketmq/ExampleBroadcastPushConsumer.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "rocketmq/DefaultMQPushConsumer.h"
-
-#include "rocketmq/Logger.h"
-#include "spdlog/spdlog.h"
-
-#include <chrono>
-#include <iostream>
-#include <mutex>
-#include <thread>
-
-using namespace rocketmq;
-
-class SampleMQMessageListener : public StandardMessageListener {
-public:
- ConsumeMessageResult consumeMessage(const std::vector<MQMessageExt>& msgs) override {
- for (const MQMessageExt& msg : msgs) {
- SPDLOG_INFO("Receive a message. MessageId={}", msg.getMsgId());
- std::cout << "Received a message. MessageId: " << msg.getMsgId() << std::endl;
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- return ConsumeMessageResult::SUCCESS;
- }
-};
-
-int main(int argc, char* argv[]) {
- Logger& logger = getLogger();
- logger.setLevel(Level::Debug);
- logger.init();
-
- const char* cid = "GID_cpp_sdk_standard";
- const char* topic = "cpp_sdk_standard";
- const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7";
-
- DefaultMQPushConsumer push_consumer(cid);
- push_consumer.setMessageModel(MessageModel::BROADCASTING);
- push_consumer.setResourceNamespace(resource_namespace);
- push_consumer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
- push_consumer.setNamesrvAddr("121.43.42.193:80");
- MessageListener* listener = new SampleMQMessageListener;
- push_consumer.setGroupName(cid);
- push_consumer.subscribe(topic, "*");
- push_consumer.registerMessageListener(listener);
- push_consumer.start();
-
- std::this_thread::sleep_for(std::chrono::minutes(60));
-
- push_consumer.shutdown();
- return EXIT_SUCCESS;
-}
diff --git a/example/rocketmq/ExamplePullConsumer.cpp b/example/rocketmq/ExamplePullConsumer.cpp
deleted file mode 100644
index 7299633..0000000
--- a/example/rocketmq/ExamplePullConsumer.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <cstdlib>
-#include <iostream>
-
-#include "rocketmq/CredentialsProvider.h"
-#include "rocketmq/DefaultMQPullConsumer.h"
-#include "rocketmq/Logger.h"
-
-int main(int argc, char* argv[]) {
- const char* group = "GID_group003";
- const char* topic = "yc001";
- const char* resource_namespace = "MQ_INST_1973281269661160_BXmPlOA6";
- const char* name_server_list = "ipv4:11.165.223.199:9876";
-
- rocketmq::Logger& logger = rocketmq::getLogger();
- logger.setLevel(rocketmq::Level::Debug);
- logger.init();
-
- rocketmq::DefaultMQPullConsumer pull_consumer(group);
- pull_consumer.setResourceNamespace(resource_namespace);
- pull_consumer.setCredentialsProvider(std::make_shared<rocketmq::ConfigFileCredentialsProvider>());
- pull_consumer.setNamesrvAddr(name_server_list);
- pull_consumer.start();
-
- std::future<std::vector<rocketmq::MQMessageQueue>> future = pull_consumer.queuesFor(topic);
- auto queues = future.get();
-
- for (const auto& queue : queues) {
- rocketmq::OffsetQuery offset_query;
- offset_query.message_queue = queue;
- offset_query.policy = rocketmq::QueryOffsetPolicy::BEGINNING;
- auto offset_future = pull_consumer.queryOffset(offset_query);
- int64_t offset = offset_future.get();
- std::cout << "offset: " << offset << std::endl;
- }
-
- pull_consumer.shutdown();
- return EXIT_SUCCESS;
-}
\ No newline at end of file
diff --git a/example/rocketmq/ExamplePushConsumer.cpp b/example/rocketmq/ExamplePushConsumer.cpp
deleted file mode 100644
index d45e52a..0000000
--- a/example/rocketmq/ExamplePushConsumer.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <chrono>
-#include <iostream>
-#include <mutex>
-#include <thread>
-
-#include "rocketmq/Logger.h"
-
-#include "spdlog/spdlog.h"
-
-#include "rocketmq/DefaultMQPushConsumer.h"
-
-using namespace rocketmq;
-
-class SampleMQMessageListener : public StandardMessageListener {
-public:
- ConsumeMessageResult consumeMessage(const std::vector<MQMessageExt>& msgs) override {
- for (const MQMessageExt& msg : msgs) {
- SPDLOG_INFO("Consume message[Topic={}, MessageId={}] OK", msg.getTopic(), msg.getMsgId());
- std::cout << "Consume Message[MsgId=" << msg.getMsgId() << "] OK. Body Size: " << msg.getBody().size()
- << std::endl;
- // std::this_thread::sleep_for(std::chrono::seconds(1));
- }
- return ConsumeMessageResult::SUCCESS;
- }
-};
-
-int main(int argc, char* argv[]) {
-
- Logger& logger = getLogger();
- logger.setLevel(Level::Debug);
- logger.init();
-
- const char* group_id = "GID_cpp_sdk_standard";
- const char* topic = "cpp_sdk_standard";
- const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7";
- const char* name_server = "mq-inst-1080056302921134-bxuibml7.mq.cn-hangzhou.aliyuncs.com:80";
-
- DefaultMQPushConsumer push_consumer(group_id);
- push_consumer.setResourceNamespace(resource_namespace);
- push_consumer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
- push_consumer.setNamesrvAddr(name_server);
- MessageListener* listener = new SampleMQMessageListener;
- push_consumer.setInstanceName("instance_0");
- push_consumer.subscribe(topic, "*");
- push_consumer.registerMessageListener(listener);
- push_consumer.setConsumeThreadCount(4);
- push_consumer.start();
-
- std::this_thread::sleep_for(std::chrono::minutes(30));
-
- push_consumer.shutdown();
- return EXIT_SUCCESS;
-}
diff --git a/example/rocketmq/BUILD.bazel b/examples/BUILD.bazel
similarity index 51%
rename from example/rocketmq/BUILD.bazel
rename to examples/BUILD.bazel
index 9c7508a..dfa114a 100644
--- a/example/rocketmq/BUILD.bazel
+++ b/examples/BUILD.bazel
@@ -47,15 +47,25 @@ cc_binary(
)
cc_binary(
- name = "sql_producer",
+ name = "example_simple_consumer",
srcs = [
- "SqlProducer.cpp",
+ "ExampleSimpleConsumer.cpp",
],
deps = [
"//src/main/cpp/rocketmq:rocketmq_library",
],
)
+# cc_binary(
+# name = "sql_producer",
+# srcs = [
+# "SqlProducer.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
+
cc_binary(
name = "example_push_consumer",
srcs = [
@@ -66,82 +76,62 @@ cc_binary(
],
)
-cc_binary(
- name = "example_fifo_push_consumer",
- srcs = [
- "ExampleFifoPushConsumer.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
+# cc_binary(
+# name = "example_fifo_push_consumer",
+# srcs = [
+# "ExampleFifoPushConsumer.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
-cc_binary(
- name = "push_consumer_with_custom_executor",
- srcs = [
- "PushConsumerWithCustomExecutor.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
-
-cc_binary(
- name = "push_consumer_with_throttle",
- srcs = [
- "PushConsumerWithThrottle.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
-
-cc_binary(
- name = "sql_consumer",
- srcs = [
- "SqlConsumer.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
+# cc_binary(
+# name = "push_consumer_with_custom_executor",
+# srcs = [
+# "PushConsumerWithCustomExecutor.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
-cc_binary(
- name = "example_pull_consumer",
- srcs = [
- "ExamplePullConsumer.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
+# cc_binary(
+# name = "push_consumer_with_throttle",
+# srcs = [
+# "PushConsumerWithThrottle.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
-cc_binary(
- name = "benchmark_push_consumer",
- srcs = [
- "BenchmarkPushConsumer.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
+# cc_binary(
+# name = "sql_consumer",
+# srcs = [
+# "SqlConsumer.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
-cc_binary(
- name = "example_broadcast_push_consumer",
- srcs = [
- "ExampleBroadcastPushConsumer.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
+# cc_binary(
+# name = "benchmark_push_consumer",
+# srcs = [
+# "BenchmarkPushConsumer.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
-cc_binary(
- name = "example_transaction_producer",
- srcs = [
- "ExampleTransactionProducer.cpp",
- ],
- deps = [
- "//src/main/cpp/rocketmq:rocketmq_library",
- ],
-)
\ No newline at end of file
+# cc_binary(
+# name = "example_transaction_producer",
+# srcs = [
+# "ExampleTransactionProducer.cpp",
+# ],
+# deps = [
+# "//src/main/cpp/rocketmq:rocketmq_library",
+# ],
+# )
\ No newline at end of file
diff --git a/example/rocketmq/BenchmarkPushConsumer.cpp b/examples/BenchmarkPushConsumer.cpp
similarity index 100%
rename from example/rocketmq/BenchmarkPushConsumer.cpp
rename to examples/BenchmarkPushConsumer.cpp
diff --git a/example/rocketmq/ExampleProducer.cpp b/examples/ExampleAsyncProducer.cpp
similarity index 67%
copy from example/rocketmq/ExampleProducer.cpp
copy to examples/ExampleAsyncProducer.cpp
index 3e1cfc5..2d28d74 100644
--- a/example/rocketmq/ExampleProducer.cpp
+++ b/examples/ExampleAsyncProducer.cpp
@@ -14,13 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "rocketmq/DefaultMQProducer.h"
#include <algorithm>
#include <atomic>
+#include <condition_variable>
#include <iostream>
+#include <mutex>
#include <random>
+#include <system_error>
-using namespace rocketmq;
+#include "rocketmq/Message.h"
+#include "rocketmq/Producer.h"
+
+using namespace ROCKETMQ_NAMESPACE;
const std::string& alphaNumeric() {
static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -44,21 +49,11 @@ std::string randomString(std::string::size_type len) {
}
int main(int argc, char* argv[]) {
- Logger& logger = getLogger();
- logger.setLevel(Level::Debug);
- logger.init();
-
- DefaultMQProducer producer("TestGroup");
-
const char* topic = "cpp_sdk_standard";
- const char* name_server = "mq-inst-1080056302921134-bxuibml7.mq.cn-hangzhou.aliyuncs.com:80";
+ const char* name_server = "11.166.42.94:8081";
- producer.setNamesrvAddr(name_server);
- producer.compressBodyThreshold(256);
- const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7";
- producer.setRegion("cn-hangzhou-pre");
- producer.setResourceNamespace(resource_namespace);
- producer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
+ auto producer =
+ Producer::newBuilder().withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()).build();
std::atomic_bool stopped;
std::atomic_long count(0);
@@ -79,29 +74,40 @@ int main(int argc, char* argv[]) {
std::string body = randomString(1024 * 4);
std::cout << "Message body size: " << body.length() << std::endl;
+ std::size_t total = 256;
+ std::size_t completed = 0;
+ std::mutex mtx;
+ std::condition_variable cv;
+
try {
- producer.start();
- for (int i = 0; i < 16; ++i) {
- MQMessage message;
- message.setTopic(topic);
- message.setTags("TagA");
- message.setKey("Yuck! Why-plural?");
- message.setBody(body);
-
- SendResult sendResult = producer.send(message);
- std::cout << sendResult.getMessageQueue().simpleName() << ": " << sendResult.getMsgId() << std::endl;
+ auto send_callback = [&](const std::error_code& ec, const SendReceipt& receipt) {
+ std::unique_lock<std::mutex> lk(mtx);
+ completed++;
count++;
- std::this_thread::sleep_for(std::chrono::seconds(1));
+ std::cout << "Message[id=" << receipt.message_id << "] sent" << std::endl;
+ if (completed >= total) {
+ cv.notify_all();
+ }
+ };
+
+ for (std::size_t i = 0; i < total; ++i) {
+ auto message = Message::newBuilder().withTopic(topic).withTag("TagA").withKeys({"Key-0"}).withBody(body).build();
+ producer.send(std::move(message), send_callback);
+ }
+
+ {
+ std::unique_lock<std::mutex> lk(mtx);
+ cv.wait(lk, [&]() { return completed >= total; });
}
} catch (...) {
std::cerr << "Ah...No!!!" << std::endl;
}
-
stopped.store(true, std::memory_order_relaxed);
if (stats_thread.joinable()) {
stats_thread.join();
}
- producer.shutdown();
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
return EXIT_SUCCESS;
}
\ No newline at end of file
diff --git a/example/rocketmq/ExampleFifoProducer.cpp b/examples/ExampleFifoProducer.cpp
similarity index 66%
rename from example/rocketmq/ExampleFifoProducer.cpp
rename to examples/ExampleFifoProducer.cpp
index c4d9e23..947ae5d 100644
--- a/example/rocketmq/ExampleFifoProducer.cpp
+++ b/examples/ExampleFifoProducer.cpp
@@ -14,13 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "rocketmq/DefaultMQProducer.h"
#include <algorithm>
#include <atomic>
#include <iostream>
#include <random>
+#include <system_error>
-using namespace rocketmq;
+#include "rocketmq/Message.h"
+#include "rocketmq/Producer.h"
+
+using namespace ROCKETMQ_NAMESPACE;
const std::string& alphaNumeric() {
static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -44,21 +47,11 @@ std::string randomString(std::string::size_type len) {
}
int main(int argc, char* argv[]) {
- Logger& logger = getLogger();
- logger.setLevel(Level::Debug);
- logger.init();
-
- DefaultMQProducer producer("TestGroup");
-
- const char* topic = "lingchu_test_order_topic";
- const char* name_server = "120.25.100.131:8081";
+ const char* topic = "cpp_sdk_standard";
+ const char* name_server = "11.166.42.94:8081";
- producer.setNamesrvAddr(name_server);
- producer.compressBodyThreshold(256);
- const char* resource_namespace = "MQ_INST_1080056302921134_BXyTLppt";
- // producer.setRegion("cn-hangzhou-pre");
- producer.setResourceNamespace(resource_namespace);
- producer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
+ auto producer =
+ Producer::newBuilder().withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()).build();
std::atomic_bool stopped;
std::atomic_long count(0);
@@ -80,19 +73,18 @@ int main(int argc, char* argv[]) {
std::cout << "Message body size: " << body.length() << std::endl;
try {
- producer.start();
- for (int i = 0; i < 16; ++i) {
- std::string sharding_key = "sharding-key-" + std::to_string(i);
- MQMessage message;
- message.setTopic(topic);
- message.setTags("TagA");
- message.setKey("Yuck! Why-plural?");
- message.setBody(body);
-
- SendResult sendResult = producer.send(message, sharding_key);
- std::cout << sendResult.getMessageQueue().simpleName() << ": " << sendResult.getMsgId() << std::endl;
+ for (int i = 0; i < 256; ++i) {
+ auto message = Message::newBuilder()
+ .withTopic(topic)
+ .withTag("TagA")
+ .withKeys({"Key-0"})
+ .withBody(body)
+ .withGroup("message-group-0")
+ .build();
+ std::error_code ec;
+ SendReceipt send_receipt = producer.send(std::move(message), ec);
+ std::cout << "Message-ID: " << send_receipt.message_id << std::endl;
count++;
- std::this_thread::sleep_for(std::chrono::seconds(1));
}
} catch (...) {
std::cerr << "Ah...No!!!" << std::endl;
@@ -103,6 +95,5 @@ int main(int argc, char* argv[]) {
stats_thread.join();
}
- producer.shutdown();
return EXIT_SUCCESS;
}
\ No newline at end of file
diff --git a/example/rocketmq/ExampleFifoPushConsumer.cpp b/examples/ExampleFifoPushConsumer.cpp
similarity index 100%
rename from example/rocketmq/ExampleFifoPushConsumer.cpp
rename to examples/ExampleFifoPushConsumer.cpp
diff --git a/example/rocketmq/ExampleProducer.cpp b/examples/ExampleProducer.cpp
similarity index 68%
rename from example/rocketmq/ExampleProducer.cpp
rename to examples/ExampleProducer.cpp
index 3e1cfc5..fa86af7 100644
--- a/example/rocketmq/ExampleProducer.cpp
+++ b/examples/ExampleProducer.cpp
@@ -14,13 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "rocketmq/DefaultMQProducer.h"
#include <algorithm>
#include <atomic>
#include <iostream>
#include <random>
+#include <system_error>
-using namespace rocketmq;
+#include "rocketmq/Message.h"
+#include "rocketmq/Producer.h"
+
+using namespace ROCKETMQ_NAMESPACE;
const std::string& alphaNumeric() {
static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -44,21 +47,11 @@ std::string randomString(std::string::size_type len) {
}
int main(int argc, char* argv[]) {
- Logger& logger = getLogger();
- logger.setLevel(Level::Debug);
- logger.init();
-
- DefaultMQProducer producer("TestGroup");
-
const char* topic = "cpp_sdk_standard";
- const char* name_server = "mq-inst-1080056302921134-bxuibml7.mq.cn-hangzhou.aliyuncs.com:80";
+ const char* name_server = "11.166.42.94:8081";
- producer.setNamesrvAddr(name_server);
- producer.compressBodyThreshold(256);
- const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7";
- producer.setRegion("cn-hangzhou-pre");
- producer.setResourceNamespace(resource_namespace);
- producer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
+ auto producer =
+ Producer::newBuilder().withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()).build();
std::atomic_bool stopped;
std::atomic_long count(0);
@@ -80,28 +73,22 @@ int main(int argc, char* argv[]) {
std::cout << "Message body size: " << body.length() << std::endl;
try {
- producer.start();
- for (int i = 0; i < 16; ++i) {
- MQMessage message;
- message.setTopic(topic);
- message.setTags("TagA");
- message.setKey("Yuck! Why-plural?");
- message.setBody(body);
-
- SendResult sendResult = producer.send(message);
- std::cout << sendResult.getMessageQueue().simpleName() << ": " << sendResult.getMsgId() << std::endl;
+ for (int i = 0; i < 256; ++i) {
+ auto message = Message::newBuilder().withTopic(topic).withTag("TagA").withKeys({"Key-0"}).withBody(body).build();
+ std::error_code ec;
+ SendReceipt send_receipt = producer.send(std::move(message), ec);
+ std::cout << "Message-ID: " << send_receipt.message_id << std::endl;
count++;
- std::this_thread::sleep_for(std::chrono::seconds(1));
}
} catch (...) {
std::cerr << "Ah...No!!!" << std::endl;
}
-
stopped.store(true, std::memory_order_relaxed);
if (stats_thread.joinable()) {
stats_thread.join();
}
- producer.shutdown();
+ // std::this_thread::sleep_for(std::chrono::seconds(1));
+
return EXIT_SUCCESS;
}
\ No newline at end of file
diff --git a/example/rocketmq/ExampleTransactionProducer.cpp b/examples/ExamplePushConsumer.cpp
similarity index 51%
copy from example/rocketmq/ExampleTransactionProducer.cpp
copy to examples/ExamplePushConsumer.cpp
index 1041b92..00954ff 100644
--- a/example/rocketmq/ExampleTransactionProducer.cpp
+++ b/examples/ExamplePushConsumer.cpp
@@ -14,39 +14,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "rocketmq/DefaultMQProducer.h"
-#include <cstdlib>
+#include <chrono>
+#include <iostream>
+#include <mutex>
+#include <thread>
+
+#include "rocketmq/Logger.h"
+#include "rocketmq/PushConsumer.h"
+#include "spdlog/spdlog.h"
using namespace ROCKETMQ_NAMESPACE;
int main(int argc, char* argv[]) {
- DefaultMQProducer producer("TestGroup");
-
const char* topic = "cpp_sdk_standard";
- const char* name_server = "47.98.116.189:80";
-
- producer.setNamesrvAddr(name_server);
- producer.compressBodyThreshold(256);
- const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7";
- producer.setRegion("cn-hangzhou-pre");
- producer.setResourceNamespace(resource_namespace);
- producer.setCredentialsProvider(std::make_shared<ConfigFileCredentialsProvider>());
-
- MQMessage message;
- message.setTopic(topic);
- message.setTags("TagA");
- message.setKey("Yuck! Why-plural?");
- message.setBody("ABC");
-
- producer.start();
-
- auto transaction = producer.prepare(message);
-
- transaction->commit();
+ const char* name_server = "11.166.42.94:8081";
+ const char* group = "GID_cpp_sdk_standard";
+ std::string tag = "*";
+
+ auto listener = [](const Message& message) { return ConsumeResult::SUCCESS; };
+
+ auto push_consumer = PushConsumer::newBuilder()
+ .withGroup(group)
+ .withConfiguration(Configuration::newBuilder()
+ .withEndpoints(name_server)
+ .withRequestTimeout(std::chrono::seconds(3))
+ .build())
+ .withConsumeThreads(4)
+ .withListener(listener)
+ .subscribe(topic, tag)
+ .build();
std::this_thread::sleep_for(std::chrono::minutes(30));
- producer.shutdown();
-
return EXIT_SUCCESS;
-}
\ No newline at end of file
+}
diff --git a/examples/ExampleSimpleConsumer.cpp b/examples/ExampleSimpleConsumer.cpp
new file mode 100644
index 0000000..dc76718
--- /dev/null
+++ b/examples/ExampleSimpleConsumer.cpp
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <chrono>
+#include <iostream>
+#include <thread>
+
+#include "rocketmq/SimpleConsumer.h"
+
+using namespace ROCKETMQ_NAMESPACE;
+
+int main(int argc, char* argv[]) {
+ const char* group = "ExampleSimpleGroup";
+ const char* topic = "cpp_sdk_standard";
+ const char* name_server = "11.166.42.94:8081";
+ std::string tag = "*";
+
+ auto simple_consumer = SimpleConsumer::newBuilder()
+ .withGroup(group)
+ .withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build())
+ .subscribe(topic, tag)
+ .build();
+ std::vector<MessageConstSharedPtr> messages;
+ std::error_code ec;
+ simple_consumer.receive(4, std::chrono::seconds(3), ec, messages);
+
+ if (ec) {
+ std::cerr << "Failed to receive messages. Cause: " << ec.message() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "Received " << messages.size() << " messages" << std::endl;
+ std::size_t i = 0;
+ for (const auto& message : messages) {
+ std::cout << "Received a message[topic=" << message->topic() << ", message-id=" << message->id()
+ << ", receipt-handle='" << message->extension().receipt_handle << "']" << std::endl;
+
+ std::error_code ec;
+ if (++i % 2 == 0) {
+ simple_consumer.ack(*message, ec);
+ if (ec) {
+ std::cerr << "Failed to ack message. Cause: " << ec.message() << std::endl;
+ }
+ } else {
+ simple_consumer.changeInvisibleDuration(*message, std::chrono::milliseconds(100), ec);
+ if (ec) {
+ std::cerr << "Failed to change invisible duration of message. Cause: " << ec.message() << std::endl;
+ }
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
diff --git a/example/rocketmq/ExampleTransactionProducer.cpp b/examples/ExampleTransactionProducer.cpp
similarity index 100%
rename from example/rocketmq/ExampleTransactionProducer.cpp
rename to examples/ExampleTransactionProducer.cpp
diff --git a/example/rocketmq/PushConsumerWithCustomExecutor.cpp b/examples/PushConsumerWithCustomExecutor.cpp
similarity index 100%
rename from example/rocketmq/PushConsumerWithCustomExecutor.cpp
rename to examples/PushConsumerWithCustomExecutor.cpp
diff --git a/example/rocketmq/PushConsumerWithThrottle.cpp b/examples/PushConsumerWithThrottle.cpp
similarity index 100%
rename from example/rocketmq/PushConsumerWithThrottle.cpp
rename to examples/PushConsumerWithThrottle.cpp
diff --git a/example/rocketmq/SqlConsumer.cpp b/examples/SqlConsumer.cpp
similarity index 100%
rename from example/rocketmq/SqlConsumer.cpp
rename to examples/SqlConsumer.cpp
diff --git a/example/rocketmq/SqlProducer.cpp b/examples/SqlProducer.cpp
similarity index 100%
rename from example/rocketmq/SqlProducer.cpp
rename to examples/SqlProducer.cpp
diff --git a/proto/BUILD.bazel b/proto/BUILD.bazel
index 3416bf4..80a2b6d 100644
--- a/proto/BUILD.bazel
+++ b/proto/BUILD.bazel
@@ -21,7 +21,7 @@ load("@rules_proto_grpc//cpp:defs.bzl", "cpp_grpc_library", "cpp_grpc_compile")
proto_library(
name = "apache_rocketmq_definition",
srcs = [
- "apache/rocketmq/v1/definition.proto",
+ "apache/rocketmq/v2/definition.proto",
],
deps = [
"@com_google_protobuf//:empty_proto",
@@ -38,7 +38,7 @@ proto_library(
proto_library(
name = "apache_rocketmq_admin",
srcs = [
- "apache/rocketmq/v1/admin.proto",
+ "apache/rocketmq/v2/admin.proto",
],
deps = [
":apache_rocketmq_definition",
@@ -51,7 +51,7 @@ proto_library(
proto_library(
name = "apache_rocketmq_service",
srcs = [
- "apache/rocketmq/v1/service.proto",
+ "apache/rocketmq/v2/service.proto",
],
deps = [
":apache_rocketmq_definition",
diff --git a/proto/apache/rocketmq/v1/definition.proto b/proto/apache/rocketmq/v1/definition.proto
deleted file mode 100644
index b6cb24b..0000000
--- a/proto/apache/rocketmq/v1/definition.proto
+++ /dev/null
@@ -1,349 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-import "google/protobuf/timestamp.proto";
-import "google/protobuf/duration.proto";
-
-package apache.rocketmq.v1;
-
-option java_multiple_files = true;
-option java_package = "apache.rocketmq.v1";
-option java_generate_equals_and_hash = true;
-option java_string_check_utf8 = true;
-option java_outer_classname = "MQDomain";
-
-enum Permission {
- NONE = 0;
- READ = 1;
- WRITE = 2;
- READ_WRITE = 3;
-
- reserved 4 to 64;
-}
-
-enum FilterType {
- TAG = 0;
- SQL = 1;
-
- reserved 2 to 64;
-}
-
-message FilterExpression {
- FilterType type = 1;
- string expression = 2;
-
- reserved 3 to 64;
-}
-
-// Dead lettering is done on a best effort basis. The same message might be
-// dead lettered multiple times.
-//
-// If validation on any of the fields fails at subscription creation/update,
-// the create/update subscription request will fail.
-message DeadLetterPolicy {
- // The maximum number of delivery attempts for any message.
- //
- // This field will be honored on a best effort basis.
- //
- // If this parameter is 0, a default value of 16 is used.
- int32 max_delivery_attempts = 1;
-
- reserved 2 to 64;
-}
-
-message Resource {
- string resource_namespace = 1;
-
- // Resource name identifier, which remains unique within the abstract resource
- // namespace.
- string name = 2;
-
- reserved 3 to 64;
-}
-
-enum ConsumeModel {
- CLUSTERING = 0;
- BROADCASTING = 1;
-
- reserved 2 to 64;
-}
-
-message ProducerData {
- Resource group = 1;
-
- reserved 2 to 64;
-}
-
-enum ConsumePolicy {
- RESUME = 0;
- PLAYBACK = 1;
- DISCARD = 2;
- TARGET_TIMESTAMP = 3;
-
- reserved 4 to 64;
-}
-
-enum ConsumeMessageType {
- ACTIVE = 0;
- PASSIVE = 1;
-
- reserved 2 to 64;
-}
-
-message ConsumerData {
- Resource group = 1;
-
- repeated SubscriptionEntry subscriptions = 2;
-
- ConsumeModel consume_model = 3;
-
- ConsumePolicy consume_policy = 4;
-
- DeadLetterPolicy dead_letter_policy = 5;
-
- ConsumeMessageType consume_type = 6;
-
- reserved 7 to 64;
-}
-
-message SubscriptionEntry {
- Resource topic = 1;
- FilterExpression expression = 2;
-
- reserved 3 to 64;
-}
-
-enum AddressScheme {
- IPv4 = 0;
- IPv6 = 1;
- DOMAIN_NAME = 2;
-
- reserved 3 to 64;
-}
-
-message Address {
- string host = 1;
- int32 port = 2;
-
- reserved 3 to 64;
-}
-
-message Endpoints {
- AddressScheme scheme = 1;
- repeated Address addresses = 2;
-
- reserved 3 to 64;
-}
-
-message Broker {
- // Name of the broker
- string name = 1;
-
- // Broker index. Canonically, index = 0 implies that the broker is playing
- // leader role while brokers with index > 0 play follower role.
- int32 id = 2;
-
- // Address of the broker, complying with the following scheme
- // 1. dns:[//authority/]host[:port]
- // 2. ipv4:address[:port][,address[:port],...] – IPv4 addresses
- // 3. ipv6:address[:port][,address[:port],...] – IPv6 addresses
- Endpoints endpoints = 3;
-
- reserved 4 to 64;
-}
-
-message Partition {
- Resource topic = 1;
- int32 id = 2;
- Permission permission = 3;
- Broker broker = 4;
-
- reserved 5 to 64;
-}
-
-enum MessageType {
- NORMAL = 0;
-
- // Sequenced message
- FIFO = 1;
-
- // Messages that are delivered after the specified duration.
- DELAY = 2;
-
- // Messages that are transactional. Only committed messages are delivered to
- // subscribers.
- TRANSACTION = 3;
-
- reserved 4 to 64;
-}
-
-enum DigestType {
- // CRC algorithm achieves goal of detecting random data error with lowest
- // computation overhead.
- CRC32 = 0;
-
- // MD5 algorithm achieves good balance between collision rate and computation
- // overhead.
- MD5 = 1;
-
- // SHA-family has substantially fewer collision with fair amount of
- // computation.
- SHA1 = 2;
-
- reserved 3 to 64;
-}
-
-// When publishing messages to or subscribing messages from brokers, clients
-// shall include or validate digests of message body to ensure data integrity.
-//
-// For message publishment, when an invalid digest were detected, brokers need
-// respond client with BAD_REQUEST.
-//
-// For messags subscription, when an invalid digest were detected, consumers
-// need to handle this case according to message type:
-// 1) Standard messages should be negatively acknowledged instantly, causing
-// immediate re-delivery; 2) FIFO messages require special RPC, to re-fetch
-// previously acquired messages batch;
-//
-// Message consumption model also affects how invalid digest are handled. When
-// messages are consumed in broadcasting way,
-// TODO: define semantics of invalid-digest-when-broadcasting.
-message Digest {
- DigestType type = 1;
- string checksum = 2;
-
- reserved 3 to 64;
-}
-
-enum Encoding {
- IDENTITY = 0;
- GZIP = 1;
-
- reserved 2 to 64;
-}
-
-message SystemAttribute {
- // Tag
- string tag = 1;
-
- // Message keys
- repeated string keys = 2;
-
- // Message identifier, client-side generated, remains unique.
- // if message_id is empty, the send message request will be aborted with
- // status `INVALID_ARGUMENT`
- string message_id = 3;
-
- // Message body digest
- Digest body_digest = 4;
-
- // Message body encoding. Candidate options are identity, gzip, snappy etc.
- Encoding body_encoding = 5;
-
- // Message type, normal, FIFO or transactional.
- MessageType message_type = 6;
-
- // Message born time-point.
- google.protobuf.Timestamp born_timestamp = 7;
-
- // Message born host. Valid options are IPv4, IPv6 or client host domain name.
- string born_host = 8;
-
- // Time-point at which the message is stored in the broker.
- google.protobuf.Timestamp store_timestamp = 9;
-
- // The broker that stores this message. It may be name, IP or arbitrary
- // identifier that uniquely identify the broker.
- string store_host = 10;
-
- oneof timed_delivery {
- // Time-point at which broker delivers to clients.
- google.protobuf.Timestamp delivery_timestamp = 11;
-
- // Level-based delay strategy.
- int32 delay_level = 12;
- }
-
- // If a message is acquired by way of POP, this field holds the receipt.
- // Clients use the receipt to acknowledge or negatively acknowledge the
- // message.
- string receipt_handle = 13;
-
- // Partition identifier in which a message is physically stored.
- int32 partition_id = 14;
-
- // Partition offset at which a message is stored.
- int64 partition_offset = 15;
-
- // Period of time servers would remain invisible once a message is acquired.
- google.protobuf.Duration invisible_period = 16;
-
- // Business code may failed to process messages for the moment. Hence, clients
- // may request servers to deliver them again using certain back-off strategy,
- // the attempt is 1 not 0 if message is delivered first time.
- int32 delivery_attempt = 17;
-
- // Message producer load-balance group if applicable.
- Resource producer_group = 18;
-
- string message_group = 19;
-
- // Trace context.
- string trace_context = 20;
-
- // Delay time of first recover orphaned transaction request from server.
- google.protobuf.Duration orphaned_transaction_recovery_period = 21;
-
- reserved 22 to 64;
-}
-
-message Message {
-
- Resource topic = 1;
-
- // User defined key-value pairs.
- // If user_attribute contains the reserved keys by RocketMQ,
- // the send message request will be aborted with status `INVALID_ARGUMENT`.
- // See below links for the reserved keys
- // https://github.com/apache/rocketmq/blob/master/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java#L58
- map<string, string> user_attribute = 2;
-
- SystemAttribute system_attribute = 3;
-
- bytes body = 4;
-
- reserved 5 to 64;
-}
-
-message Assignment {
- Partition Partition = 1;
-
- reserved 2 to 64;
-}
-
-enum QueryOffsetPolicy {
- // Use this option if client wishes to playback all existing messages.
- BEGINNING = 0;
-
- // Use this option if client wishes to skip all existing messages.
- END = 1;
-
- // Use this option if time-based seek is targeted.
- TIME_POINT = 2;
-
- reserved 3 to 64;
-}
\ No newline at end of file
diff --git a/proto/apache/rocketmq/v1/service.proto b/proto/apache/rocketmq/v1/service.proto
deleted file mode 100644
index 9d8e3b0..0000000
--- a/proto/apache/rocketmq/v1/service.proto
+++ /dev/null
@@ -1,531 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-import "google/protobuf/duration.proto";
-import "google/protobuf/timestamp.proto";
-import "google/rpc/error_details.proto";
-import "google/rpc/status.proto";
-
-import "apache/rocketmq/v1/definition.proto";
-
-package apache.rocketmq.v1;
-
-option java_multiple_files = true;
-option java_package = "apache.rocketmq.v1";
-option java_generate_equals_and_hash = true;
-option java_string_check_utf8 = true;
-option java_outer_classname = "MQService";
-
-message ResponseCommon {
- google.rpc.Status status = 1;
- google.rpc.RequestInfo request_info = 2;
- google.rpc.Help help = 3;
- google.rpc.RetryInfo retry_info = 4;
- google.rpc.DebugInfo debug_info = 5;
- google.rpc.ErrorInfo error_info = 6;
-
- reserved 7 to 64;
-}
-
-// Topics are destination of messages to publish to or subscribe from. Similar
-// to domain names, they will be addressable after resolution through the
-// provided access point.
-//
-// Access points are usually the addresses of name servers, which fulfill
-// service discovery, load-balancing and other auxillary services. Name servers
-// receive periodic heartbeats from affiliate brokers and erase those which
-// failed to maintain alive status.
-//
-// Name servers answer queries of QueryRouteRequest, responding clients with
-// addressable partitions, which they may directly publish messages to or
-// subscribe messages from.
-//
-// QueryRouteRequest shall include source endpoints, aka, configured
-// access-point, which annotates tenant-id, instance-id or other
-// vendor-specific settings. Purpose-built name servers may respond customized
-// results based on these particular requirements.
-message QueryRouteRequest {
- Resource topic = 1;
-
- Endpoints endpoints = 2;
-
- reserved 3 to 64;
-}
-
-message QueryRouteResponse {
- ResponseCommon common = 1;
-
- repeated Partition partitions = 2;
-
- reserved 3 to 64;
-}
-
-message SendMessageRequest {
- Message message = 1;
- Partition partition = 2;
-
- reserved 3 to 64;
-}
-
-message SendMessageResponse {
- ResponseCommon common = 1;
- string message_id = 2;
- string transaction_id = 3;
-
- reserved 4 to 64;
-}
-
-message QueryAssignmentRequest {
- Resource topic = 1;
- Resource group = 2;
- string client_id = 3;
-
- // Service access point
- Endpoints endpoints = 4;
-
- reserved 5 to 64;
-}
-
-message QueryAssignmentResponse {
- ResponseCommon common = 1;
- repeated Assignment assignments = 2;
-
- reserved 3 to 64;
-}
-
-message ReceiveMessageRequest {
- Resource group = 1;
- string client_id = 2;
- Partition partition = 3;
- FilterExpression filter_expression = 4;
- ConsumePolicy consume_policy = 5;
- google.protobuf.Timestamp initialization_timestamp = 6;
- int32 batch_size = 7;
- google.protobuf.Duration invisible_duration = 8;
- google.protobuf.Duration await_time = 9;
- bool fifo_flag = 10;
-
- reserved 11 to 64;
-}
-
-message ReceiveMessageResponse {
- ResponseCommon common = 1;
- repeated Message messages = 2;
- google.protobuf.Timestamp delivery_timestamp = 3;
- google.protobuf.Duration invisible_duration = 4;
-
- reserved 5 to 64;
-}
-
-message AckMessageRequest {
- Resource group = 1;
- Resource topic = 2;
- string client_id = 3;
- oneof handle {
- string receipt_handle = 4;
- int64 offset = 5;
- }
- string message_id = 6;
-
- reserved 7 to 64;
-}
-
-message AckMessageResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message NackMessageRequest {
- Resource group = 1;
- Resource topic = 2;
- string client_id = 3;
- string receipt_handle = 4;
- string message_id = 5;
- int32 delivery_attempt = 6;
- int32 max_delivery_attempts = 7;
-
- reserved 8 to 64;
-}
-
-message NackMessageResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message ForwardMessageToDeadLetterQueueRequest {
- Resource group = 1;
- Resource topic = 2;
- string client_id = 3;
- string receipt_handle = 4;
- string message_id = 5;
- int32 delivery_attempt = 6;
- int32 max_delivery_attempts = 7;
-
- reserved 8 to 64;
-}
-
-message ForwardMessageToDeadLetterQueueResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message HeartbeatRequest {
- string client_id = 1;
- oneof client_data {
- ProducerData producer_data = 2;
- ConsumerData consumer_data = 3;
- }
- bool fifo_flag = 4;
-
- reserved 5 to 64;
-}
-
-message HeartbeatResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message HealthCheckRequest {
- Resource group = 1;
- string client_host = 2;
-
- reserved 3 to 64;
-}
-
-message HealthCheckResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message EndTransactionRequest {
- Resource group = 1;
- string message_id = 2;
- string transaction_id = 3;
- enum TransactionResolution {
- COMMIT = 0;
- ROLLBACK = 1;
- }
- TransactionResolution resolution = 4;
- enum Source {
- CLIENT = 0;
- SERVER_CHECK = 1;
- }
- Source source = 5;
- string trace_context = 6;
-
- reserved 7 to 64;
-}
-
-message EndTransactionResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message QueryOffsetRequest {
- Partition partition = 1;
- QueryOffsetPolicy policy = 2;
- google.protobuf.Timestamp time_point = 3;
-
- reserved 4 to 64;
-}
-
-message QueryOffsetResponse {
- ResponseCommon common = 1;
- int64 offset = 2;
-
- reserved 3 to 64;
-}
-
-message PullMessageRequest {
- Resource group = 1;
- Partition partition = 2;
- int64 offset = 3;
- int32 batch_size = 4;
- google.protobuf.Duration await_time = 5;
- FilterExpression filter_expression = 6;
- string client_id = 7;
-
- reserved 8 to 64;
-}
-
-message PullMessageResponse {
- ResponseCommon common = 1;
- int64 min_offset = 2;
- int64 next_offset = 3;
- int64 max_offset = 4;
- repeated Message messages = 5;
-
- reserved 6 to 64;
-}
-
-message NoopCommand {
- reserved 1 to 64;
-}
-
-message PrintThreadStackTraceCommand {
- string command_id = 1;
-
- reserved 2 to 64;
-}
-
-message ReportThreadStackTraceRequest {
- string command_id = 1;
- string thread_stack_trace = 2;
-
- reserved 3 to 64;
-}
-
-message ReportThreadStackTraceResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message VerifyMessageConsumptionCommand {
- string command_id = 1;
- Message message = 2;
-
- reserved 3 to 64;
-}
-
-message ReportMessageConsumptionResultRequest {
- string command_id = 1;
- google.rpc.Status status = 2;
-
- reserved 3 to 64;
-}
-
-message ReportMessageConsumptionResultResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-message RecoverOrphanedTransactionCommand {
- Message orphaned_transactional_message = 1;
- string transaction_id = 2;
-
- reserved 3 to 64;
-}
-
-message PollCommandRequest {
- string client_id = 1;
- repeated Resource topics = 2;
- oneof group {
- Resource producer_group = 3;
- Resource consumer_group = 4;
- }
-
- reserved 5 to 64;
-}
-
-message PollCommandResponse {
- oneof type {
- // Default command when no new command need to be delivered.
- NoopCommand noop_command = 1;
- // Request client to print thread stack trace.
- PrintThreadStackTraceCommand print_thread_stack_trace_command = 2;
- // Request client to verify the consumption of the appointed message.
- VerifyMessageConsumptionCommand verify_message_consumption_command = 3;
- // Request client to recover the orphaned transaction message.
- RecoverOrphanedTransactionCommand recover_orphaned_transaction_command = 4;
- }
-
- reserved 5 to 64;
-}
-
-message NotifyClientTerminationRequest {
- oneof group {
- Resource producer_group = 1;
- Resource consumer_group = 2;
- }
- string client_id = 3;
-
- reserved 4 to 64;
-}
-
-message NotifyClientTerminationResponse {
- ResponseCommon common = 1;
-
- reserved 2 to 64;
-}
-
-// For all the RPCs in MessagingService, the following error handling policies
-// apply:
-//
-// If the request doesn't bear a valid authentication credential, return a
-// response with common.status.code == `UNAUTHENTICATED`. If the authenticated
-// user is not granted with sufficient permission to execute the requested
-// operation, return a response with common.status.code == `PERMISSION_DENIED`.
-// If the per-user-resource-based quota is exhausted, return a response with
-// common.status.code == `RESOURCE_EXHAUSTED`. If any unexpected server-side
-// errors raise, return a response with common.status.code == `INTERNAL`.
-service MessagingService {
-
- // Querys the route entries of the requested topic in the perspective of the
- // given endpoints. On success, servers should return a collection of
- // addressable partitions. Note servers may return customized route entries
- // based on endpoints provided.
- //
- // If the requested topic doesn't exist, returns `NOT_FOUND`.
- // If the specific endpoints is emtpy, returns `INVALID_ARGUMENT`.
- rpc QueryRoute(QueryRouteRequest) returns (QueryRouteResponse) {
- }
-
- // Producer or consumer sends HeartbeatRequest to servers periodically to
- // keep-alive. Additionally, it also reports client-side configuration,
- // including topic subscription, load-balancing group name, etc.
- //
- // Returns `OK` if success.
- //
- // If a client specifies a language that is not yet supported by servers,
- // returns `INVALID_ARGUMENT`
- rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {
- }
-
- // Checks the health status of message server, returns `OK` if services are
- // online and serving. Clients may use this RPC to detect availability of
- // messaging service, and take isolation actions when necessary.
- rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse) {
- }
-
- // Delivers messages to brokers.
- // Clients may further:
- // 1. Refine a message destination to topic partition which fulfills parts of
- // FIFO semantic;
- // 2. Flag a message as transactional, which keeps it invisible to consumers
- // until it commits;
- // 3. Time a message, making it invisible to consumers till specified
- // time-point;
- // 4. And more...
- //
- // Returns message-id or transaction-id with status `OK` on success.
- //
- // If the destination topic doesn't exist, returns `NOT_FOUND`.
- rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) {
- }
-
- // Querys the assigned partition route info of a topic for current consumer,
- // the returned assignment result is descided by server-side load balacner.
- //
- // If the corresponding topic doesn't exist, returns `NOT_FOUND`.
- // If the specific endpoints is emtpy, returns `INVALID_ARGUMENT`.
- rpc QueryAssignment(QueryAssignmentRequest) returns (QueryAssignmentResponse) {
- }
-
- // Receives messages from the server in batch manner, returns a set of
- // messages if success. The received messages should be acked or uacked after
- // processed.
- //
- // If the pending concurrent receive requests exceed the quota of the given
- // consumer group, returns `UNAVAILABLE`. If the upstream store server hangs,
- // return `DEADLINE_EXCEEDED` in a timely manner. If the corresponding topic
- // or consumer group doesn't exist, returns `NOT_FOUND`. If there is no new
- // message in the specific topic, returns `OK` with an empty message set.
- // Please note that client may suffer from false empty responses.
- rpc ReceiveMessage(ReceiveMessageRequest) returns (ReceiveMessageResponse) {
- }
-
- // Acknowledges the message associated with the `receipt_handle` or `offset`
- // in the `AckMessageRequest`, it means the message has been successfully
- // processed. Returns `OK` if the message server remove the relevant message
- // successfully.
- //
- // If the given receipt_handle is illegal or out of date, returns
- // `INVALID_ARGUMENT`.
- rpc AckMessage(AckMessageRequest) returns (AckMessageResponse) {
- }
-
- // Signals that the message has not been successfully processed. The message
- // server should resend the message follow the retry policy defined at
- // server-side.
- //
- // If the corresponding topic or consumer group doesn't exist, returns
- // `NOT_FOUND`.
- rpc NackMessage(NackMessageRequest) returns (NackMessageResponse) {
- }
-
- // Forwards one message to dead letter queue if the DeadLetterPolicy is
- // triggered by this message at client-side, return `OK` if success.
- rpc ForwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest)
- returns (ForwardMessageToDeadLetterQueueResponse) {
- }
-
- // Commits or rollback one transactional message.
- rpc EndTransaction(EndTransactionRequest) returns (EndTransactionResponse) {
- }
-
- // Querys the offset of the specific partition, returns the offset with `OK`
- // if success. The message server should maintain a numerical offset for each
- // message in a parition.
- rpc QueryOffset(QueryOffsetRequest) returns (QueryOffsetResponse) {
- }
-
- // Pulls messages from the specific partition, returns a set of messages with
- // next pull offset. The pulled messages can't be acked or nacked, while the
- // client is responsible for manage offesets for consumer, typically update
- // consume offset to local memory or a third-party storage service.
- //
- // If the pending concurrent receive requests exceed the quota of the given
- // consumer group, returns `UNAVAILABLE`. If the upstream store server hangs,
- // return `DEADLINE_EXCEEDED` in a timely manner. If the corresponding topic
- // or consumer group doesn't exist, returns `NOT_FOUND`. If there is no new
- // message in the specific topic, returns `OK` with an empty message set.
- // Please note that client may suffer from false empty responses.
- rpc PullMessage(PullMessageRequest) returns (PullMessageResponse) {
- }
-
- // Multiplexing RPC(s) for various polling requests, which issue different
- // commands to client.
- //
- // Sometimes client may need to receive and process the command from server.
- // To prevent the complexity of streaming RPC(s), a unary RPC using
- // long-polling is another solution.
- //
- // To mark the request-response of corresponding command, `command_id` in
- // message is recorded in the subsequent RPC(s). For example, after receiving
- // command of printing thread stack trace, client would send
- // `ReportMessageConsumptionResultRequest` to server, which contain both of
- // the stack trace and `command_id`.
- //
- // At same time, `NoopCommand` is delivered from server when no new command is
- // needed, it is essential for client to maintain the ping-pong.
- //
- rpc PollCommand(PollCommandRequest) returns (PollCommandResponse) {
- }
-
- // After receiving the corresponding polling command, the thread stack trace
- // is reported to the server.
- rpc ReportThreadStackTrace(ReportThreadStackTraceRequest) returns (ReportThreadStackTraceResponse) {
- }
-
- // After receiving the corresponding polling command, the consumption result
- // of appointed message is reported to the server.
- rpc ReportMessageConsumptionResult(ReportMessageConsumptionResultRequest)
- returns (ReportMessageConsumptionResultResponse) {
- }
-
- // Notify the server that the client is terminated.
- rpc NotifyClientTermination(NotifyClientTerminationRequest) returns (NotifyClientTerminationResponse) {
- }
-}
\ No newline at end of file
diff --git a/proto/apache/rocketmq/v1/admin.proto b/proto/apache/rocketmq/v2/admin.proto
similarity index 86%
rename from proto/apache/rocketmq/v1/admin.proto
rename to proto/apache/rocketmq/v2/admin.proto
index 554207b..7dbb702 100644
--- a/proto/apache/rocketmq/v1/admin.proto
+++ b/proto/apache/rocketmq/v2/admin.proto
@@ -15,11 +15,12 @@
syntax = "proto3";
-package apache.rocketmq.v1;
+package apache.rocketmq.v2;
option cc_enable_arenas = true;
+option csharp_namespace = "Apache.Rocketmq.V2";
option java_multiple_files = true;
-option java_package = "apache.rocketmq.v1";
+option java_package = "apache.rocketmq.v2";
option java_generate_equals_and_hash = true;
option java_string_check_utf8 = true;
option java_outer_classname = "MQAdmin";
@@ -35,11 +36,8 @@ message ChangeLogLevelRequest {
Level level = 1;
}
-message ChangeLogLevelResponse {
- string remark = 1;
-}
+message ChangeLogLevelResponse { string remark = 1; }
service Admin {
- rpc ChangeLogLevel(ChangeLogLevelRequest) returns (ChangeLogLevelResponse) {
- }
+ rpc ChangeLogLevel(ChangeLogLevelRequest) returns (ChangeLogLevelResponse) {}
}
\ No newline at end of file
diff --git a/proto/apache/rocketmq/v2/definition.proto b/proto/apache/rocketmq/v2/definition.proto
new file mode 100644
index 0000000..6565a21
--- /dev/null
+++ b/proto/apache/rocketmq/v2/definition.proto
@@ -0,0 +1,447 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/duration.proto";
+
+package apache.rocketmq.v2;
+
+option csharp_namespace = "Apache.Rocketmq.V2";
+option java_multiple_files = true;
+option java_package = "apache.rocketmq.v2";
+option java_generate_equals_and_hash = true;
+option java_string_check_utf8 = true;
+option java_outer_classname = "MQDomain";
+
+enum TransactionResolution {
+ TRANSACTION_RESOLUTION_UNSPECIFIED = 0;
+ COMMIT = 1;
+ ROLLBACK = 2;
+}
+
+enum TransactionSource {
+ SOURCE_UNSPECIFIED = 0;
+ SOURCE_CLIENT = 1;
+ SOURCE_SERVER_CHECK = 2;
+}
+
+enum Permission {
+ PERMISSION_UNSPECIFIED = 0;
+ NONE = 1;
+ READ = 2;
+ WRITE = 3;
+ READ_WRITE = 4;
+}
+
+enum FilterType {
+ FILTER_TYPE_UNSPECIFIED = 0;
+ TAG = 1;
+ SQL = 2;
+}
+
+message FilterExpression {
+ FilterType type = 1;
+ string expression = 2;
+}
+
+message RetryPolicy {
+ int32 max_attempts = 1;
+ oneof strategy {
+ ExponentialBackoff exponential_backoff = 2;
+ CustomizedBackoff customized_backoff = 3;
+ }
+}
+
+// https://en.wikipedia.org/wiki/Exponential_backoff
+message ExponentialBackoff {
+ google.protobuf.Duration initial = 1;
+ google.protobuf.Duration max = 2;
+ float multiplier = 3;
+}
+
+message CustomizedBackoff {
+ // To support classic backoff strategy which is arbitary defined by end users.
+ // Typical values are: `1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h`
+ repeated google.protobuf.Duration next = 1;
+}
+
+message Resource {
+ string resource_namespace = 1;
+
+ // Resource name identifier, which remains unique within the abstract resource
+ // namespace.
+ string name = 2;
+}
+
+message SubscriptionEntry {
+ Resource topic = 1;
+ FilterExpression expression = 2;
+}
+
+enum AddressScheme {
+ ADDRESS_SCHEME_UNSPECIFIED = 0;
+ IPv4 = 1;
+ IPv6 = 2;
+ DOMAIN_NAME = 3;
+}
+
+message Address {
+ string host = 1;
+ int32 port = 2;
+}
+
+message Endpoints {
+ AddressScheme scheme = 1;
+ repeated Address addresses = 2;
+}
+
+message Broker {
+ // Name of the broker
+ string name = 1;
+
+ // Broker index. Canonically, index = 0 implies that the broker is playing
+ // leader role while brokers with index > 0 play follower role.
+ int32 id = 2;
+
+ // Address of the broker, complying with the following scheme
+ // 1. dns:[//authority/]host[:port]
+ // 2. ipv4:address[:port][,address[:port],...] – IPv4 addresses
+ // 3. ipv6:address[:port][,address[:port],...] – IPv6 addresses
+ Endpoints endpoints = 3;
+}
+
+message MessageQueue {
+ Resource topic = 1;
+ int32 id = 2;
+ Permission permission = 3;
+ Broker broker = 4;
+ repeated MessageType accept_message_types = 5;
+}
+
+enum MessageType {
+ MESSAGE_TYPE_UNSPECIFIED = 0;
+
+ NORMAL = 1;
+
+ // Sequenced message
+ FIFO = 2;
+
+ // Messages that are delivered after the specified duration.
+ DELAY = 3;
+
+ // Messages that are transactional. Only committed messages are delivered to
+ // subscribers.
+ TRANSACTION = 4;
+}
+
+enum DigestType {
+ DIGEST_TYPE_UNSPECIFIED = 0;
+
+ // CRC algorithm achieves goal of detecting random data error with lowest
+ // computation overhead.
+ CRC32 = 1;
+
+ // MD5 algorithm achieves good balance between collision rate and computation
+ // overhead.
+ MD5 = 2;
+
+ // SHA-family has substantially fewer collision with fair amount of
+ // computation.
+ SHA1 = 3;
+}
+
+// When publishing messages to or subscribing messages from brokers, clients
+// shall include or validate digests of message body to ensure data integrity.
+//
+// For message publishing, when an invalid digest were detected, brokers need
+// respond client with BAD_REQUEST.
+//
+// For messages subscription, when an invalid digest were detected, consumers
+// need to handle this case according to message type:
+// 1) Standard messages should be negatively acknowledged instantly, causing
+// immediate re-delivery; 2) FIFO messages require special RPC, to re-fetch
+// previously acquired messages batch;
+//
+// Message consumption model also affects how invalid digest are handled. When
+// messages are consumed in broadcasting way,
+// TODO: define semantics of invalid-digest-when-broadcasting.
+message Digest {
+ DigestType type = 1;
+ string checksum = 2;
+}
+
+enum ClientType {
+ CLIENT_TYPE_UNSPECIFIED = 0;
+ PRODUCER = 1;
+ PUSH_CONSUMER = 2;
+ SIMPLE_CONSUMER = 3;
+}
+
+enum Encoding {
+ ENCODING_UNSPECIFIED = 0;
+
+ IDENTITY = 1;
+
+ GZIP = 2;
+}
+
+message SystemProperties {
+ // Tag, which is optional.
+ optional string tag = 1;
+
+ // Message keys
+ repeated string keys = 2;
+
+ // Message identifier, client-side generated, remains unique.
+ // if message_id is empty, the send message request will be aborted with
+ // status `INVALID_ARGUMENT`
+ string message_id = 3;
+
+ // Message body digest
+ Digest body_digest = 4;
+
+ // Message body encoding. Candidate options are identity, gzip, snappy etc.
+ Encoding body_encoding = 5;
+
+ // Message type, normal, FIFO or transactional.
+ MessageType message_type = 6;
+
+ // Message born time-point.
+ google.protobuf.Timestamp born_timestamp = 7;
+
+ // Message born host. Valid options are IPv4, IPv6 or client host domain name.
+ string born_host = 8;
+
+ // Time-point at which the message is stored in the broker, which is absent
+ // for message publishing.
+ optional google.protobuf.Timestamp store_timestamp = 9;
+
+ // The broker that stores this message. It may be broker name, IP or arbitrary
+ // identifier that uniquely identify the server.
+ string store_host = 10;
+
+ // Time-point at which broker delivers to clients, which is optional.
+ optional google.protobuf.Timestamp delivery_timestamp = 11;
+
+ // If a message is acquired by way of POP, this field holds the receipt,
+ // which is absent for message publishing.
+ // Clients use the receipt to acknowledge or negatively acknowledge the
+ // message.
+ optional string receipt_handle = 12;
+
+ // Message queue identifier in which a message is physically stored.
+ int32 queue_id = 13;
+
+ // Message-queue offset at which a message is stored, which is absent for
+ // message publishing.
+ optional int64 queue_offset = 14;
+
+ // Period of time servers would remain invisible once a message is acquired.
+ optional google.protobuf.Duration invisible_duration = 15;
+
+ // Business code may failed to process messages for the moment. Hence, clients
+ // may request servers to deliver them again using certain back-off strategy,
+ // the attempt is 1 not 0 if message is delivered first time, and it is absent
+ // for message publishing.
+ optional int32 delivery_attempt = 16;
+
+ // Define the group name of message in the same topic, which is optional.
+ optional string message_group = 17;
+
+ // Trace context for each message, which is optional.
+ optional string trace_context = 18;
+
+ // If a transactional message stay unresolved for more than
+ // `transaction_orphan_threshold`, it would be regarded as an
+ // orphan. Servers that manages orphan messages would pick up
+ // a capable publisher to resolve
+ optional google.protobuf.Duration orphaned_transaction_recovery_duration = 19;
+}
+
+message Message {
+ Resource topic = 1;
+
+ // User defined key-value pairs.
+ // If user_properties contain the reserved keys by RocketMQ,
+ // the send message request will be aborted with status `INVALID_ARGUMENT`.
+ // See below links for the reserved keys
+ // https://github.com/apache/rocketmq/blob/master/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java#L58
+ map<string, string> user_properties = 2;
+
+ SystemProperties system_properties = 3;
+
+ bytes body = 4;
+}
+
+message Assignment {
+ MessageQueue message_queue = 1;
+}
+
+message SendReceipt {
+ string message_id = 1;
+ string transaction_id = 2;
+ int64 offset = 3;
+}
+
+enum Code {
+ // Success.
+ OK = 0;
+ // Format of access point is illegal.
+ ILLEGAL_ACCESS_POINT = 1;
+ // Format of topic is illegal.
+ ILLEGAL_TOPIC = 2;
+ // Format of consumer group is illegal.
+ ILLEGAL_CONSUMER_GROUP = 3;
+ // Format of message tag is illegal.
+ ILLEGAL_MESSAGE_TAG = 4;
+ // Format of message key is illegal.
+ ILLEGAL_MESSAGE_KEY = 5;
+ // Size of message keys exceeds the threshold.
+ MESSAGE_KEYS_TOO_LARGE = 6;
+ // Format of message group is illegal.
+ ILLEGAL_MESSAGE_GROUP = 7;
+ // Format of message property key is illegal.
+ ILLEGAL_MESSAGE_PROPERTY_KEY = 8;
+ // Message properties total size exceeds the threshold.
+ MESSAGE_PROPERTIES_TOO_LARGE = 9;
+ // Message body size exceeds the threshold.
+ MESSAGE_BODY_TOO_LARGE = 10;
+
+ // User does not have the permission to operate.
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403
+ FORBIDDEN = 403;
+
+ // Code indicates that the client request has not been completed
+ // because it lacks valid authentication credentials for the
+ // requested resource.
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401
+ UNAUTHORIZED = 401;
+
+ // Topic resource does not exist.
+ TOPIC_NOT_FOUND = 13;
+
+ // Consumer group resource does not exist.
+ CONSUMER_GROUP_NOT_FOUND = 14;
+
+ // Not allowed to verify message. Chances are that you are verifying
+ // a FIFO message, as is violating FIFO semantics.
+ VERIFY_MESSAGE_FORBIDDEN = 15;
+
+ // Failed to consume message.
+ FAILED_TO_CONSUME_MESSAGE = 16;
+
+ // Message is corrupted.
+ MESSAGE_CORRUPTED = 17;
+
+ // Too many requests are made in short period of duration.
+ // Requests are throttled.
+ TOO_MANY_REQUESTS = 18;
+
+ // Expired receipt-handle is used when trying to acknowledge or change
+ // invisible duration of a message
+ RECEIPT_HANDLE_EXPIRED = 19;
+
+ // Message property is not match the message type.
+ MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE = 20;
+
+ // Format of message id is illegal.
+ ILLEGAL_MESSAGE_ID = 21;
+
+ // Transaction id is invalid.
+ INVALID_TRANSACTION_ID = 22;
+
+ // Format of filter expression is illegal.
+ ILLEGAL_FILTER_EXPRESSION = 23;
+
+ // Receipt handle of message is invalid.
+ INVALID_RECEIPT_HANDLE = 24;
+
+ // Message persistence timeout.
+ MASTER_PERSISTENCE_TIMEOUT = 25;
+
+ // Slave persistence timeout.
+ SLAVE_PERSISTENCE_TIMEOUT = 26;
+
+ // The HA-mechanism is not working now.
+ HA_NOT_AVAILABLE = 27;
+
+ // Operation is not allowed in current version.
+ VERSION_UNSUPPORTED = 28;
+
+ // Message not found from server.
+ MESSAGE_NOT_FOUND = 29;
+
+ // Message offset is illegal.
+ ILLEGAL_MESSAGE_OFFSET = 30;
+
+ // Illegal message is for the sake of backward compatibility. In most case,
+ // more definitive code is better, e.g. `ILLEGAL_MESSAGE_TAG`.
+ ILLEGAL_MESSAGE = 31;
+
+ // Client type could not be recognized.
+ UNRECOGNIZED_CLIENT_TYPE = 32;
+
+ // Code indicates that the server encountered an unexpected condition
+ // that prevented it from fulfilling the request.
+ // This error response is a generic "catch-all" response.
+ // Usually, this indicates the server cannot find a better alternative
+ // error code to response. Sometimes, server administrators log error
+ // responses like the 500 status code with more details about the request
+ // to prevent the error from happening again in the future.
+ //
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500
+ INTERNAL_SERVER_ERROR = 500;
+
+ // Code means that the server or client does not support the functionality
+ // required to fulfill the request.
+ NOT_IMPLEMENTED = 501;
+
+ // Code indicates that the server, while acting as a gateway or proxy,
+ // did not get a response in time from the upstream server that
+ // it needed in order to complete the request.
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504
+ GATEWAY_TIMEOUT = 504;
+}
+
+message Status {
+ Code code = 1;
+ string message = 2;
+}
+
+enum Language {
+ LANGUAGE_UNSPECIFIED = 0;
+ JAVA = 1;
+ CPP = 2;
+ DOT_NET = 3;
+ GOLANG = 4;
+ RUST = 5;
+}
+
+// User Agent
+message UA {
+ // SDK language
+ Language language = 1;
+
+ // SDK version
+ string version = 2;
+
+ // Platform details, including OS name, version, arch etc.
+ string platform = 3;
+
+ // Hostname of the node
+ string hostname = 4;
+}
\ No newline at end of file
diff --git a/proto/apache/rocketmq/v2/service.proto b/proto/apache/rocketmq/v2/service.proto
new file mode 100644
index 0000000..aa688b4
--- /dev/null
+++ b/proto/apache/rocketmq/v2/service.proto
@@ -0,0 +1,436 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+import "google/protobuf/duration.proto";
+
+import "apache/rocketmq/v2/definition.proto";
+
+package apache.rocketmq.v2;
+
+option csharp_namespace = "Apache.Rocketmq.V2";
+option java_multiple_files = true;
+option java_package = "apache.rocketmq.v2";
+option java_generate_equals_and_hash = true;
+option java_string_check_utf8 = true;
+option java_outer_classname = "MQService";
+
+// Topics are destination of messages to publish to or subscribe from. Similar
+// to domain names, they will be addressable after resolution through the
+// provided access point.
+//
+// Access points are usually the addresses of name servers, which fulfill
+// service discovery, load-balancing and other auxiliary services. Name servers
+// receive periodic heartbeats from affiliate brokers and erase those which
+// failed to maintain alive status.
+//
+// Name servers answer queries of QueryRouteRequest, responding clients with
+// addressable message-queues, which they may directly publish messages to or
+// subscribe messages from.
+//
+// QueryRouteRequest shall include source endpoints, aka, configured
+// access-point, which annotates tenant-id, instance-id or other
+// vendor-specific settings. Purpose-built name servers may respond customized
+// results based on these particular requirements.
+message QueryRouteRequest {
+ Resource topic = 1;
+ Endpoints endpoints = 2;
+}
+
+message QueryRouteResponse {
+ Status status = 1;
+
+ repeated MessageQueue message_queues = 2;
+}
+
+message SendMessageRequest {
+ repeated Message messages = 1;
+}
+
+message SendMessageResponse {
+ Status status = 1;
+ repeated SendReceipt receipts = 2;
+}
+
+message QueryAssignmentRequest {
+ Resource topic = 1;
+ Resource group = 2;
+ Endpoints endpoints = 3;
+}
+
+message QueryAssignmentResponse {
+ Status status = 1;
+ repeated Assignment assignments = 2;
+}
+
+message ReceiveMessageRequest {
+ Resource group = 1;
+ MessageQueue message_queue = 2;
+ FilterExpression filter_expression = 3;
+ int32 batch_size = 4;
+ // Required if client type is simple consumer.
+ optional google.protobuf.Duration invisible_duration = 5;
+ // For message auto renew and clean
+ bool auto_renew = 6;
+}
+
+message ReceiveMessageResponse {
+ oneof content {
+ Status status = 1;
+ Message message = 2;
+ }
+}
+
+message AckMessageEntry {
+ string message_id = 1;
+ string receipt_handle = 2;
+}
+
+message AckMessageRequest {
+ Resource group = 1;
+ Resource topic = 2;
+ repeated AckMessageEntry entries = 3;
+}
+
+message AckMessageResultEntry {
+ string message_id = 1;
+ string receipt_handle = 2;
+
+ // Acknowledge result may be acquired through inspecting
+ // `status.code`; In case acknowledgement failed, `status.message`
+ // is the explanation of the failure.
+ Status status = 3;
+}
+
+message AckMessageResponse {
+ // RPC tier status, which is used to represent RPC-level errors including
+ // authentication, authorization, throttling and other general failures.
+ Status status = 1;
+
+ repeated AckMessageResultEntry entries = 2;
+}
+
+message ForwardMessageToDeadLetterQueueRequest {
+ Resource group = 1;
+ Resource topic = 2;
+ string receipt_handle = 3;
+ string message_id = 4;
+ int32 delivery_attempt = 5;
+ int32 max_delivery_attempts = 6;
+}
+
+message ForwardMessageToDeadLetterQueueResponse {
+ Status status = 1;
+}
+
+message HeartbeatRequest {
+ optional Resource group = 1;
+ ClientType client_type = 2;
+}
+
+message HeartbeatResponse {
+ Status status = 1;
+}
+
+message EndTransactionRequest {
+ Resource topic = 1;
+ string message_id = 2;
+ string transaction_id = 3;
+ TransactionResolution resolution = 4;
+ TransactionSource source = 5;
+ string trace_context = 6;
+}
+
+message EndTransactionResponse {
+ Status status = 1;
+}
+
+message PrintThreadStackTraceCommand {
+ string nonce = 1;
+}
+
+message ThreadStackTrace {
+ string nonce = 1;
+ optional string thread_stack_trace = 2;
+}
+
+message VerifyMessageCommand {
+ string nonce = 1;
+ Message message = 2;
+}
+
+message VerifyMessageResult {
+ string nonce = 1;
+}
+
+message RecoverOrphanedTransactionCommand {
+ MessageQueue message_queue = 1;
+ Message orphaned_transactional_message = 2;
+ string transaction_id = 3;
+}
+
+message Publishing {
+ // Publishing settings below here is appointed by client, thus it is
+ // unnecessary for server to push at present.
+ //
+ // List of topics to which messages will publish to.
+ repeated Resource topics = 1;
+
+ // Publishing settings below here are from server, it is essential for
+ // server to push.
+ //
+ // Body of message will be deflated if its size in bytes exceeds the
+ // threshold.
+ int32 compress_body_threshold = 2;
+
+ // If the message body size exceeds `max_body_size`, broker servers would
+ // reject the request. As a result, it is advisable that Producer performs
+ // client-side check validation.
+ int32 max_body_size = 3;
+}
+
+message Subscription {
+ // Subscription settings below here is appointed by client, thus it is
+ // unnecessary for server to push at present.
+ //
+ // Consumer group.
+ optional Resource group = 1;
+
+ // Subscription for consumer.
+ repeated SubscriptionEntry subscriptions = 2;
+
+ // Subscription settings below here are from server, it is essential for
+ // server to push.
+ //
+ // When FIFO flag is `true`, messages of the same message group are processed
+ // in first-in-first-out manner.
+ //
+ // Brokers will not deliver further messages of the same group utill prior
+ // ones are completely acknowledged.
+ optional bool fifo = 3;
+
+ // Message receive batch size here is essential for push consumer.
+ optional int32 receive_batch_size = 4;
+
+ // Long-polling timeout for `ReceiveMessageRequest`, which is essential for
+ // push consumer.
+ optional google.protobuf.Duration long_polling_timeout = 5;
+}
+
+message Settings {
+ // Configurations for all clients.
+ optional ClientType client_type = 1;
+
+ optional Endpoints access_point = 2;
+
+ // If publishing of messages encounters throttling or server internal errors,
+ // publishers should implement automatic retries after progressive longer
+ // back-offs for consecutive errors.
+ //
+ // When processing message fails, `backoff_policy` describes an interval
+ // after which the message should be available to consume again.
+ //
+ // For FIFO messages, the interval should be relatively small because
+ // messages of the same message group would not be readily available utill
+ // the prior one depletes its lifecycle.
+ optional RetryPolicy backoff_policy = 3;
+
+ // Request timeout for RPCs excluding long-polling.
+ optional google.protobuf.Duration request_timeout = 4;
+
+ oneof pub_sub {
+ Publishing publishing = 5;
+
+ Subscription subscription = 6;
+ }
+
+ // User agent details
+ UA user_agent = 7;
+}
+
+message TelemetryCommand {
+ optional Status status = 1;
+
+ oneof command {
+ // Client settings
+ Settings settings = 2;
+
+ // These messages are from client.
+ //
+ // Report thread stack trace to server.
+ ThreadStackTrace thread_stack_trace = 3;
+
+ // Report message verify result to server.
+ VerifyMessageResult verify_message_result = 4;
+
+ // There messages are from server.
+ //
+ // Request client to recover the orphaned transaction message.
+ RecoverOrphanedTransactionCommand recover_orphaned_transaction_command = 5;
+
+ // Request client to print thread stack trace.
+ PrintThreadStackTraceCommand print_thread_stack_trace_command = 6;
+
+ // Request client to verify the consumption of the appointed message.
+ VerifyMessageCommand verify_message_command = 7;
+ }
+}
+
+message NotifyClientTerminationRequest {
+ // Consumer group, which is absent for producer.
+ optional Resource group = 1;
+}
+
+message NotifyClientTerminationResponse {
+ Status status = 1;
+}
+
+message ChangeInvisibleDurationRequest {
+ Resource group = 1;
+ Resource topic = 2;
+
+ // Unique receipt handle to identify message to change
+ string receipt_handle = 3;
+
+ // New invisible duration
+ google.protobuf.Duration invisible_duration = 4;
+
+ // For message tracing
+ string message_id = 5;
+}
+
+message ChangeInvisibleDurationResponse {
+ Status status = 1;
+
+ // Server may generate a new receipt handle for the message.
+ string receipt_handle = 2;
+}
+
+// For all the RPCs in MessagingService, the following error handling policies
+// apply:
+//
+// If the request doesn't bear a valid authentication credential, return a
+// response with common.status.code == `UNAUTHENTICATED`. If the authenticated
+// user is not granted with sufficient permission to execute the requested
+// operation, return a response with common.status.code == `PERMISSION_DENIED`.
+// If the per-user-resource-based quota is exhausted, return a response with
+// common.status.code == `RESOURCE_EXHAUSTED`. If any unexpected server-side
+// errors raise, return a response with common.status.code == `INTERNAL`.
+service MessagingService {
+ // Queries the route entries of the requested topic in the perspective of the
+ // given endpoints. On success, servers should return a collection of
+ // addressable message-queues. Note servers may return customized route
+ // entries based on endpoints provided.
+ //
+ // If the requested topic doesn't exist, returns `NOT_FOUND`.
+ // If the specific endpoints is empty, returns `INVALID_ARGUMENT`.
+ rpc QueryRoute(QueryRouteRequest) returns (QueryRouteResponse) {
+ }
+
+ // Producer or consumer sends HeartbeatRequest to servers periodically to
+ // keep-alive. Additionally, it also reports client-side configuration,
+ // including topic subscription, load-balancing group name, etc.
+ //
+ // Returns `OK` if success.
+ //
+ // If a client specifies a language that is not yet supported by servers,
+ // returns `INVALID_ARGUMENT`
+ rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {
+ }
+
+ // Delivers messages to brokers.
+ // Clients may further:
+ // 1. Refine a message destination to message-queues which fulfills parts of
+ // FIFO semantic;
+ // 2. Flag a message as transactional, which keeps it invisible to consumers
+ // until it commits;
+ // 3. Time a message, making it invisible to consumers till specified
+ // time-point;
+ // 4. And more...
+ //
+ // Returns message-id or transaction-id with status `OK` on success.
+ //
+ // If the destination topic doesn't exist, returns `NOT_FOUND`.
+ rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) {
+ }
+
+ // Queries the assigned route info of a topic for current consumer,
+ // the returned assignment result is decided by server-side load balancer.
+ //
+ // If the corresponding topic doesn't exist, returns `NOT_FOUND`.
+ // If the specific endpoints is empty, returns `INVALID_ARGUMENT`.
+ rpc QueryAssignment(QueryAssignmentRequest) returns (QueryAssignmentResponse) {
+ }
+
+ // Receives messages from the server in batch manner, returns a set of
+ // messages if success. The received messages should be acked or redelivered
+ // after processed.
+ //
+ // If the pending concurrent receive requests exceed the quota of the given
+ // consumer group, returns `UNAVAILABLE`. If the upstream store server hangs,
+ // return `DEADLINE_EXCEEDED` in a timely manner. If the corresponding topic
+ // or consumer group doesn't exist, returns `NOT_FOUND`. If there is no new
+ // message in the specific topic, returns `OK` with an empty message set.
+ // Please note that client may suffer from false empty responses.
+ //
+ // If failed to receive message from remote, server must return only one
+ // `ReceiveMessageResponse` as the reply to the request, whose `Status` indicates
+ // the specific reason of failure, otherwise, the reply is considered successful.
+ rpc ReceiveMessage(ReceiveMessageRequest) returns (stream ReceiveMessageResponse) {
+ }
+
+ // Acknowledges the message associated with the `receipt_handle` or `offset`
+ // in the `AckMessageRequest`, it means the message has been successfully
+ // processed. Returns `OK` if the message server remove the relevant message
+ // successfully.
+ //
+ // If the given receipt_handle is illegal or out of date, returns
+ // `INVALID_ARGUMENT`.
+ rpc AckMessage(AckMessageRequest) returns (AckMessageResponse) {
+ }
+
+ // Forwards one message to dead letter queue if the max delivery attempts is
+ // exceeded by this message at client-side, return `OK` if success.
+ rpc ForwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest)
+ returns (ForwardMessageToDeadLetterQueueResponse) {
+ }
+
+ // Commits or rollback one transactional message.
+ rpc EndTransaction(EndTransactionRequest) returns (EndTransactionResponse) {
+ }
+
+ // Once a client starts, it would immediately establishes bi-lateral stream
+ // RPCs with brokers, reporting its settings as the initiative command.
+ //
+ // When servers have need of inspecting client status, they would issue
+ // telemetry commands to clients. After executing received instructions,
+ // clients shall report command execution results through client-side streams.
+ rpc Telemetry(stream TelemetryCommand) returns (stream TelemetryCommand) {
+ }
+
+ // Notify the server that the client is terminated.
+ rpc NotifyClientTermination(NotifyClientTerminationRequest) returns (NotifyClientTerminationResponse) {
+ }
+
+ // Once a message is retrieved from consume queue on behalf of the group, it
+ // will be kept invisible to other clients of the same group for a period of
+ // time. The message is supposed to be processed within the invisible
+ // duration. If the client, which is in charge of the invisible message, is
+ // not capable of processing the message timely, it may use
+ // ChangeInvisibleDuration to lengthen invisible duration.
+ rpc ChangeInvisibleDuration(ChangeInvisibleDurationRequest) returns (ChangeInvisibleDurationResponse) {
+ }
+}
\ No newline at end of file
diff --git a/src/main/cpp/admin/include/AdminClient.h b/src/main/cpp/admin/include/AdminClient.h
index 968d837..9e6e7c7 100644
--- a/src/main/cpp/admin/include/AdminClient.h
+++ b/src/main/cpp/admin/include/AdminClient.h
@@ -15,12 +15,12 @@
* limitations under the License.
*/
#pragma once
-#include "apache/rocketmq/v1/admin.grpc.pb.h"
+#include "apache/rocketmq/v2/admin.grpc.pb.h"
#include "rocketmq/RocketMQ.h"
#include <grpcpp/grpcpp.h>
#include <memory>
-namespace rmq = apache::rocketmq::v1;
+namespace rmq = apache::rocketmq::v2;
ROCKETMQ_NAMESPACE_BEGIN
diff --git a/src/main/cpp/admin/include/AdminServerImpl.h b/src/main/cpp/admin/include/AdminServerImpl.h
index b605635..5ef88ab 100644
--- a/src/main/cpp/admin/include/AdminServerImpl.h
+++ b/src/main/cpp/admin/include/AdminServerImpl.h
@@ -16,15 +16,17 @@
*/
#pragma once
-#include "AdminServiceImpl.h"
-#include "rocketmq/AdminServer.h"
#include <atomic>
#include <condition_variable>
-#include <grpcpp/grpcpp.h>
#include <memory>
#include <mutex>
#include <thread>
+#include "AdminServiceImpl.h"
+#include "rocketmq/AdminServer.h"
+
+#include "grpcpp/grpcpp.h"
+
using grpc::Server;
ROCKETMQ_NAMESPACE_BEGIN
diff --git a/src/main/cpp/admin/include/AdminServiceImpl.h b/src/main/cpp/admin/include/AdminServiceImpl.h
index 58933ab..e2d750c 100644
--- a/src/main/cpp/admin/include/AdminServiceImpl.h
+++ b/src/main/cpp/admin/include/AdminServiceImpl.h
@@ -15,13 +15,14 @@
* limitations under the License.
*/
#pragma once
-#include "apache/rocketmq/v1/admin.grpc.pb.h"
+#include "apache/rocketmq/v2/admin.grpc.pb.h"
+#include "grpcpp/grpcpp.h"
#include "rocketmq/RocketMQ.h"
-#include <grpcpp/grpcpp.h>
using grpc::ServerContext;
using grpc::Status;
-namespace rmq = apache::rocketmq::v1;
+
+namespace rmq = apache::rocketmq::v2;
ROCKETMQ_NAMESPACE_BEGIN
diff --git a/src/main/cpp/admin/include/ServerCall.h b/src/main/cpp/admin/include/ServerCall.h
index 138d433..66f3246 100644
--- a/src/main/cpp/admin/include/ServerCall.h
+++ b/src/main/cpp/admin/include/ServerCall.h
@@ -18,11 +18,11 @@
#include <cassert>
-#include "apache/rocketmq/v1/admin.grpc.pb.h"
+#include "apache/rocketmq/v2/admin.grpc.pb.h"
#include "rocketmq/RocketMQ.h"
-namespace rmq = apache::rocketmq::v1;
+namespace rmq = apache::rocketmq::v2;
ROCKETMQ_NAMESPACE_BEGIN
diff --git a/src/main/cpp/base/BUILD.bazel b/src/main/cpp/base/BUILD.bazel
index 5c7ab81..959bba5 100644
--- a/src/main/cpp/base/BUILD.bazel
+++ b/src/main/cpp/base/BUILD.bazel
@@ -25,6 +25,7 @@ cc_library(
strip_include_prefix = "//src/main/cpp/base/include",
deps = [
"//src/main/cpp/log:log_library",
+ "//proto:rocketmq_grpc_library",
"@com_github_fmtlib_fmt//:fmtlib",
"@com_google_absl//absl/base",
"@com_google_absl//absl/container:flat_hash_map",
diff --git a/src/test/cpp/ut/rocketmq/FilterExpressionTest.cpp b/src/main/cpp/base/Configuration.cpp
similarity index 53%
rename from src/test/cpp/ut/rocketmq/FilterExpressionTest.cpp
rename to src/main/cpp/base/Configuration.cpp
index f7df8ce..cf0f4bd 100644
--- a/src/test/cpp/ut/rocketmq/FilterExpressionTest.cpp
+++ b/src/main/cpp/base/Configuration.cpp
@@ -14,34 +14,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "FilterExpression.h"
-#include "gtest/gtest.h"
-ROCKETMQ_NAMESPACE_BEGIN
+#include "rocketmq/Configuration.h"
-class FilterExpressionTest : public testing::Test {
-public:
- FilterExpressionTest() : filter_expression_("TagA") {
- }
+ROCKETMQ_NAMESPACE_BEGIN
- void SetUp() override {
- }
+ConfigurationBuilder Configuration::newBuilder() {
+ return {};
+}
- void TearDown() override {
- }
+ConfigurationBuilder& ConfigurationBuilder::withEndpoints(std::string endpoints) {
+ configuration_.endpoints_ = std::move(endpoints);
+ return *this;
+}
-protected:
- FilterExpression filter_expression_;
-};
+ConfigurationBuilder& ConfigurationBuilder::withCredentialsProvider(std::shared_ptr<CredentialsProvider> provider) {
+ configuration_.credentials_provider_ = std::move(provider);
+ return *this;
+}
-TEST_F(FilterExpressionTest, testAccept) {
- MQMessageExt message;
- message.setTags("TagA");
- EXPECT_TRUE(filter_expression_.accept(message));
+ConfigurationBuilder& ConfigurationBuilder::withRequestTimeout(std::chrono::milliseconds request_timeout) {
+ configuration_.request_timeout_ = request_timeout;
+ return *this;
+}
- MQMessageExt message2;
- message2.setTags("TagB");
- EXPECT_FALSE(filter_expression_.accept(message2));
+Configuration ConfigurationBuilder::build() {
+ return std::move(configuration_);
}
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/include/DigestType.h b/src/main/cpp/base/ConfigurationDefaults.cpp
similarity index 82%
copy from src/main/cpp/base/include/DigestType.h
copy to src/main/cpp/base/ConfigurationDefaults.cpp
index e255d82..b11a6e6 100644
--- a/src/main/cpp/base/include/DigestType.h
+++ b/src/main/cpp/base/ConfigurationDefaults.cpp
@@ -14,19 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#pragma once
+#include <chrono>
-#include <cstdint>
-
-#include "rocketmq/RocketMQ.h"
+#include "rocketmq/ConfigurationDefaults.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class DigestType : int8_t
-{
- CRC32 = 0,
- MD5 = 1,
- SHA1 = 2,
-};
+const std::chrono::milliseconds ConfigurationDefaults::RequestTimeout = std::chrono::seconds(3);
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
+ROCKETMQ_NAMESPACE_END
diff --git a/src/main/cpp/rocketmq/CredentialsProvider.cpp b/src/main/cpp/base/CredentialsProvider.cpp
similarity index 100%
rename from src/main/cpp/rocketmq/CredentialsProvider.cpp
rename to src/main/cpp/base/CredentialsProvider.cpp
diff --git a/src/main/cpp/base/ErrorCategory.cpp b/src/main/cpp/base/ErrorCategory.cpp
index 166f632..4fe2ea0 100644
--- a/src/main/cpp/base/ErrorCategory.cpp
+++ b/src/main/cpp/base/ErrorCategory.cpp
@@ -24,6 +24,9 @@ std::string ErrorCategory::message(int code) const {
case ErrorCode::Success:
return "Success";
+ case ErrorCode::NoContent:
+ return "Broker has processed the request but is not going to return any content.";
+
case ErrorCode::IllegalState:
return "Client state illegal. Forgot to call start()?";
@@ -34,6 +37,9 @@ std::string ErrorCategory::message(int code) const {
return "Message is ill-formed. Check validity of your topic, tag, "
"etc";
+ case ErrorCode::BadRequestAsyncPubFifoMessage:
+ return "Publishing of FIFO messages is only allowed synchronously";
+
case ErrorCode::Unauthorized:
return "Authentication failed. Possibly caused by invalid credentials.";
@@ -42,8 +48,13 @@ std::string ErrorCategory::message(int code) const {
"requested action";
case ErrorCode::NotFound:
- return "Topic not found, which should be created through console or "
+ return "Request resource not found, which should be created through console or "
"administration API before hand.";
+ case ErrorCode::TopicNotFound:
+ return "Topic is not found. Verify the request topic has already been created through console or management API";
+
+ case ErrorCode::GroupNotFound:
+ return "Group is not found. Verify the request group has already been created through console or management API";
case ErrorCode::RequestTimeout:
return "Timeout when connecting, reading from or writing to brokers.";
diff --git a/src/main/cpp/rocketmq/FilterExpression.cpp b/src/main/cpp/base/FilterExpression.cpp
similarity index 87%
rename from src/main/cpp/rocketmq/FilterExpression.cpp
rename to src/main/cpp/base/FilterExpression.cpp
index a60290b..b187994 100644
--- a/src/main/cpp/rocketmq/FilterExpression.cpp
+++ b/src/main/cpp/base/FilterExpression.cpp
@@ -14,18 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "FilterExpression.h"
+#include "rocketmq/FilterExpression.h"
ROCKETMQ_NAMESPACE_BEGIN
-bool FilterExpression::accept(const MQMessageExt& message) const {
-
+bool FilterExpression::accept(const Message& message) const {
switch (type_) {
case ExpressionType::TAG: {
if (WILD_CARD_TAG == content_) {
return true;
} else {
- return message.getTags() == content_;
+ return message.tag() == content_;
}
}
diff --git a/src/main/cpp/base/MQMessage.cpp b/src/main/cpp/base/MQMessage.cpp
deleted file mode 100644
index 2015a61..0000000
--- a/src/main/cpp/base/MQMessage.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "rocketmq/MQMessage.h"
-#include "MessageAccessor.h"
-#include "MessageImpl.h"
-#include "MixAll.h"
-#include "Protocol.h"
-#include "UniqueIdGenerator.h"
-#include "UtilAll.h"
-#include "rocketmq/MQMessageExt.h"
-#include <chrono>
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-MQMessage::MQMessage() : MQMessage("", "", "", "") {
-}
-
-MQMessage::MQMessage(const std::string& topic, const std::string& body) : MQMessage(topic, "", "", body) {
-}
-
-MQMessage::MQMessage(const std::string& topic, const std::string& tags, const std::string& body)
- : MQMessage(topic, tags, "", body) {
-}
-
-MQMessage::MQMessage(const std::string& topic, const std::string& tags, const std::string& keys,
- const std::string& body)
- : impl_(new MessageImpl) {
- impl_->topic_.name = topic;
- impl_->system_attribute_.tag = tags;
- if (!keys.empty()) {
- impl_->system_attribute_.keys.emplace_back(keys);
- }
-
- impl_->system_attribute_.born_host = UtilAll::hostname();
- impl_->system_attribute_.born_timestamp = absl::Now();
- impl_->system_attribute_.message_id = UniqueIdGenerator::instance().next();
-
- impl_->body_.clear();
- impl_->body_.reserve(body.length());
- impl_->body_.append(body.data(), body.length());
-}
-
-MQMessage::~MQMessage() {
- delete impl_;
-}
-
-MQMessage::MQMessage(const MQMessage& other) {
- impl_ = new MessageImpl(*other.impl_);
-}
-
-MQMessage& MQMessage::operator=(const MQMessage& other) {
- if (this == &other) {
- return *this;
- }
- *impl_ = *(other.impl_);
- return *this;
-}
-
-const std::string& MQMessage::getMsgId() const {
- return impl_->system_attribute_.message_id;
-}
-
-std::string MQMessage::getBornHost() const {
- return impl_->system_attribute_.born_host;
-}
-
-std::chrono::system_clock::time_point MQMessage::deliveryTimestamp() const {
- return absl::ToChronoTime(impl_->system_attribute_.delivery_timestamp);
-}
-
-void MQMessage::setProperty(const std::string& name, const std::string& value) {
- impl_->user_attribute_map_[name] = value;
-}
-
-std::string MQMessage::getProperty(const std::string& name) const {
- auto it = impl_->user_attribute_map_.find(name);
- if (impl_->user_attribute_map_.end() == it) {
- return "";
- }
- return it->second;
-}
-
-const std::string& MQMessage::getTopic() const {
- return impl_->topic_.name;
-}
-
-void MQMessage::setTopic(const std::string& topic) {
- impl_->topic_.name = topic;
-}
-
-void MQMessage::setTopic(const char* data, int len) {
- impl_->topic_.name = std::string(data, len);
-}
-
-std::string MQMessage::getTags() const {
- return impl_->system_attribute_.tag;
-}
-
-void MQMessage::setTags(const std::string& tags) {
- impl_->system_attribute_.tag = tags;
-}
-
-const std::vector<std::string>& MQMessage::getKeys() const {
- return impl_->system_attribute_.keys;
-}
-
-void MQMessage::setKey(const std::string& key) {
- impl_->system_attribute_.keys.push_back(key);
-}
-
-void MQMessage::setKeys(const std::vector<std::string>& keys) {
- impl_->system_attribute_.keys = keys;
-}
-
-int MQMessage::getDelayTimeLevel() const {
- return impl_->system_attribute_.delay_level;
-}
-
-void MQMessage::setDelayTimeLevel(int level) {
- impl_->system_attribute_.delay_level = level;
-}
-
-const std::string& MQMessage::traceContext() const {
- return impl_->system_attribute_.trace_context;
-}
-
-void MQMessage::traceContext(const std::string& trace_context) {
- impl_->system_attribute_.trace_context = trace_context;
-}
-
-const std::string& MQMessage::getBody() const {
- return impl_->body_;
-}
-
-void MQMessage::setBody(const char* body, int len) {
- impl_->body_.clear();
- impl_->body_.reserve(len);
- impl_->body_.append(body, len);
-}
-
-void MQMessage::setBody(const std::string& body) {
- impl_->body_ = body;
-}
-
-uint32_t MQMessage::bodyLength() const {
- return impl_->body_.length();
-}
-
-const std::map<std::string, std::string>& MQMessage::getProperties() const {
- return impl_->user_attribute_map_;
-}
-
-void MQMessage::setProperties(const std::map<std::string, std::string>& properties) {
- for (const auto& it : properties) {
- impl_->user_attribute_map_.insert({it.first, it.second});
- }
-}
-
-void MQMessage::messageType(MessageType message_type) {
- impl_->system_attribute_.message_type = message_type;
-}
-
-MessageType MQMessage::messageType() const {
- return impl_->system_attribute_.message_type;
-}
-
-void MQMessage::bindMessageGroup(absl::string_view message_group) {
- impl_->system_attribute_.message_group.append(message_group.data(), message_group.length());
- messageType(MessageType::FIFO);
-}
-
-const std::string& MQMessage::messageGroup() const {
- return impl_->system_attribute_.message_group;
-}
-
-ROCKETMQ_NAMESPACE_END
diff --git a/src/main/cpp/base/MQMessageExt.cpp b/src/main/cpp/base/MQMessageExt.cpp
deleted file mode 100644
index 21a9476..0000000
--- a/src/main/cpp/base/MQMessageExt.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "rocketmq/MQMessageExt.h"
-#include "MessageImpl.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-MQMessageExt::MQMessageExt() : MQMessage() {
-}
-
-MQMessageExt::MQMessageExt(const MQMessageExt& other) : MQMessage(other) {
-}
-
-MQMessageExt& MQMessageExt::operator=(const MQMessageExt& other) {
- if (this == &other) {
- return *this;
- }
-
- *impl_ = *(other.impl_);
- return *this;
-}
-
-int32_t MQMessageExt::getQueueId() const {
- return impl_->system_attribute_.partition_id;
-}
-
-std::chrono::system_clock::time_point MQMessageExt::bornTimestamp() const {
- return absl::ToChronoTime(impl_->system_attribute_.born_timestamp);
-}
-
-int64_t MQMessageExt::getBornTimestamp() const {
- return absl::ToUnixMillis(impl_->system_attribute_.born_timestamp);
-}
-
-std::chrono::system_clock::time_point MQMessageExt::storeTimestamp() const {
- return absl::ToChronoTime(impl_->system_attribute_.store_timestamp);
-}
-
-int64_t MQMessageExt::getStoreTimestamp() const {
- return absl::ToUnixMillis(impl_->system_attribute_.store_timestamp);
-}
-
-std::string MQMessageExt::getStoreHost() const {
- return impl_->system_attribute_.store_host;
-}
-
-int64_t MQMessageExt::getQueueOffset() const {
- return impl_->system_attribute_.partition_offset;
-}
-
-int32_t MQMessageExt::getDeliveryAttempt() const {
- return impl_->system_attribute_.attempt_times;
-}
-
-const std::string& MQMessageExt::receiptHandle() const {
- return impl_->system_attribute_.receipt_handle;
-}
-
-bool MQMessageExt::operator==(const MQMessageExt& other) {
- return impl_->system_attribute_.message_id == other.impl_->system_attribute_.message_id;
-}
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/Message.cpp b/src/main/cpp/base/Message.cpp
new file mode 100644
index 0000000..f20b4cd
--- /dev/null
+++ b/src/main/cpp/base/Message.cpp
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "rocketmq/Message.h"
+
+#include "UniqueIdGenerator.h"
+#include "absl/memory/memory.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+Message::Message() {
+ id_ = UniqueIdGenerator::instance().next();
+}
+
+MessageBuilder Message::newBuilder() {
+ return {};
+}
+
+MessageBuilder::MessageBuilder() : message_(absl::make_unique<Message>()) {
+}
+
+MessageBuilder& MessageBuilder::withTopic(std::string topic) {
+ message_->topic_.swap(topic);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withTag(std::string tag) {
+ message_->tag_.swap(tag);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withKeys(std::vector<std::string> keys) {
+ message_->keys_.swap(keys);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withTraceContext(std::string trace_context) {
+ message_->trace_context_.swap(trace_context);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withBody(std::string body) {
+ message_->body_.swap(body);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withGroup(std::string group) {
+ message_->group_.swap(group);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withProperties(std::unordered_map<std::string, std::string> properties) {
+ message_->properties_ = std::move(properties);
+ return *this;
+}
+
+MessageConstPtr MessageBuilder::build() {
+ return std::move(message_);
+}
+
+MessageBuilder& MessageBuilder::withId(std::string id) {
+ message_->id_ = std::move(id);
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withBornTime(std::chrono::system_clock::time_point born_time) {
+ message_->born_time_ = born_time;
+ return *this;
+}
+
+MessageBuilder& MessageBuilder::withBornHost(std::string born_host) {
+ message_->born_host_ = std::move(born_host);
+ return *this;
+}
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/MessageAccessor.cpp b/src/main/cpp/base/MessageAccessor.cpp
deleted file mode 100644
index 957f076..0000000
--- a/src/main/cpp/base/MessageAccessor.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "MessageAccessor.h"
-#include "MessageImpl.h"
-#include "rocketmq/MQMessage.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-void MessageAccessor::setMessageId(MQMessageExt& message, std::string message_id) {
- message.impl_->system_attribute_.message_id = std::move(message_id);
-}
-
-void MessageAccessor::setBornTimestamp(MQMessageExt& message, absl::Time born_timestamp) {
- message.impl_->system_attribute_.born_timestamp = born_timestamp;
-}
-
-void MessageAccessor::setStoreTimestamp(MQMessageExt& message, absl::Time store_timestamp) {
- message.impl_->system_attribute_.store_timestamp = store_timestamp;
-}
-
-void MessageAccessor::setQueueId(MQMessageExt& message, int32_t queue_id) {
- message.impl_->system_attribute_.partition_id = queue_id;
-}
-
-void MessageAccessor::setQueueOffset(MQMessageExt& message, int64_t queue_offset) {
- message.impl_->system_attribute_.partition_offset = queue_offset;
-}
-
-void MessageAccessor::setBornHost(MQMessageExt& message, std::string born_host) {
- message.impl_->system_attribute_.born_host = std::move(born_host);
-}
-
-void MessageAccessor::setStoreHost(MQMessageExt& message, std::string store_host) {
- message.impl_->system_attribute_.store_host = std::move(store_host);
-}
-
-void MessageAccessor::setDeliveryTimestamp(MQMessageExt& message, absl::Time delivery_timestamp) {
- message.impl_->system_attribute_.delivery_timestamp = delivery_timestamp;
-}
-
-void MessageAccessor::setDeliveryAttempt(MQMessageExt& message, int32_t attempt_times) {
- message.impl_->system_attribute_.attempt_times = attempt_times;
-}
-
-void MessageAccessor::setDecodedTimestamp(MQMessageExt& message, absl::Time decode_timestamp) {
- message.impl_->system_attribute_.decode_timestamp = decode_timestamp;
-}
-
-absl::Time MessageAccessor::decodedTimestamp(const MQMessageExt& message) {
- return message.impl_->system_attribute_.decode_timestamp;
-}
-
-void MessageAccessor::setInvisiblePeriod(MQMessageExt& message, absl::Duration invisible_period) {
- message.impl_->system_attribute_.invisible_period = invisible_period;
-}
-
-void MessageAccessor::setReceiptHandle(MQMessageExt& message, std::string receipt_handle) {
- message.impl_->system_attribute_.receipt_handle = std::move(receipt_handle);
-}
-
-void MessageAccessor::setTraceContext(MQMessageExt& message, std::string trace_context) {
- message.impl_->system_attribute_.trace_context = std::move(trace_context);
-}
-
-void MessageAccessor::setMessageType(MQMessage& message, MessageType message_type) {
- message.impl_->system_attribute_.message_type = message_type;
-}
-
-void MessageAccessor::setTargetEndpoint(MQMessage& message, const std::string& target_endpoint) {
- message.impl_->system_attribute_.target_endpoint = target_endpoint;
-}
-
-const std::string& MessageAccessor::targetEndpoint(const MQMessage& message) {
- return message.impl_->system_attribute_.target_endpoint;
-}
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/test/cpp/ut/api/ErrorCodeTest.cpp b/src/main/cpp/base/MessageExt.cpp
similarity index 73%
rename from src/test/cpp/ut/api/ErrorCodeTest.cpp
rename to src/main/cpp/base/MessageExt.cpp
index c63df2f..5477df7 100644
--- a/src/test/cpp/ut/api/ErrorCodeTest.cpp
+++ b/src/main/cpp/base/MessageExt.cpp
@@ -14,17 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "rocketmq/ErrorCode.h"
-#include "gtest/gtest.h"
-#include <system_error>
+#include "MessageExt.h"
ROCKETMQ_NAMESPACE_BEGIN
-TEST(ErrorCodeTest, testErrorCode) {
- std::error_code ec = ErrorCode::BadRequest;
- if (ec) {
- std::cout << ec.message() << std::endl;
+rmq::MessageType typeOf(const Message& message) {
+ if (message.group().has_value()) {
+ return rmq::MessageType::FIFO;
}
+
+ if (message.deliveryTimestamp().has_value()) {
+ return rmq::MessageType::DELAY;
+ }
+
+ return rmq::MessageType::NORMAL;
}
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/MetadataConstants.cpp b/src/main/cpp/base/MetadataConstants.cpp
index 0aa8d93..71e3da9 100644
--- a/src/main/cpp/base/MetadataConstants.cpp
+++ b/src/main/cpp/base/MetadataConstants.cpp
@@ -18,19 +18,35 @@
ROCKETMQ_NAMESPACE_BEGIN
-const char* MetadataConstants::TENANT_ID_KEY = "x-mq-tenant-id";
-const char* MetadataConstants::NAMESPACE_KEY = "x-mq-namespace";
-const char* MetadataConstants::AUTHORIZATION = "authorization";
-const char* MetadataConstants::STS_SESSION_TOKEN = "x-mq-session-token";
-const char* MetadataConstants::DATE_TIME_KEY = "x-mq-date-time";
-const char* MetadataConstants::ALGORITHM_KEY = "MQv2-HMAC-SHA1";
-const char* MetadataConstants::CREDENTIAL_KEY = "Credential";
-const char* MetadataConstants::SIGNED_HEADERS_KEY = "SignedHeaders";
-const char* MetadataConstants::SIGNATURE_KEY = "Signature";
-const char* MetadataConstants::DATE_TIME_FORMAT = "%Y%m%dT%H%M%SZ";
-const char* MetadataConstants::LANGUAGE_KEY = "x-mq-language";
-const char* MetadataConstants::CLIENT_VERSION_KEY = "x-mq-client-version";
+#ifndef CLIENT_VERSION_MAJOR
+#define CLIENT_VERSION_MAJOR "5"
+#endif
+
+#ifndef CLIENT_VERSION_MINOR
+#define CLIENT_VERSION_MINOR "0"
+#endif
+
+#ifndef CLIENT_VERSION_PATCH
+#define CLIENT_VERSION_PATCH "0"
+#endif
+
+const char* MetadataConstants::CLIENT_VERSION = CLIENT_VERSION_MAJOR "." CLIENT_VERSION_MINOR "." CLIENT_VERSION_PATCH;
+
+const char* MetadataConstants::TENANT_ID_KEY = "x-mq-tenant-id";
+const char* MetadataConstants::CLIENT_ID_KEY = "x-mq-client-id";
+const char* MetadataConstants::NAMESPACE_KEY = "x-mq-namespace";
+const char* MetadataConstants::AUTHORIZATION = "authorization";
+const char* MetadataConstants::STS_SESSION_TOKEN = "x-mq-session-token";
+const char* MetadataConstants::DATE_TIME_KEY = "x-mq-date-time";
+const char* MetadataConstants::ALGORITHM_KEY = "MQv2-HMAC-SHA1";
+const char* MetadataConstants::CREDENTIAL_KEY = "Credential";
+const char* MetadataConstants::SIGNED_HEADERS_KEY = "SignedHeaders";
+const char* MetadataConstants::SIGNATURE_KEY = "Signature";
+const char* MetadataConstants::DATE_TIME_FORMAT = "%Y%m%dT%H%M%SZ";
+const char* MetadataConstants::LANGUAGE_KEY = "x-mq-language";
+const char* MetadataConstants::CLIENT_VERSION_KEY = "x-mq-client-version";
const char* MetadataConstants::PROTOCOL_VERSION_KEY = "x-mq-protocol-version";
-const char* MetadataConstants::REQUEST_ID_KEY = "x-mq-request-id";
+const char* MetadataConstants::REQUEST_ID_KEY = "x-mq-request-id";
+const char* MetadataConstants::SERVICE_NAME = "RocketMQ";
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/MixAll.cpp b/src/main/cpp/base/MixAll.cpp
index 0bf273a..4d244ce 100644
--- a/src/main/cpp/base/MixAll.cpp
+++ b/src/main/cpp/base/MixAll.cpp
@@ -17,6 +17,7 @@
#include "MixAll.h"
#include <chrono>
+#include <cstdint>
#include <cstdlib>
#include "absl/random/random.h"
@@ -55,7 +56,7 @@ const std::chrono::duration<long long> MixAll::DEFAULT_INVISIBLE_TIME_ = std::ch
const std::chrono::duration<long long> MixAll::PROCESS_QUEUE_EXPIRATION_THRESHOLD_ = std::chrono::seconds(120);
-const int32_t MixAll::MAX_SEND_MESSAGE_ATTEMPT_TIMES_ = 3;
+const std::size_t MixAll::MAX_SEND_MESSAGE_ATTEMPT_TIMES_ = 3;
const std::string MixAll::PROPERTY_TRANSACTION_PREPARED_ = "TRAN_MSG";
@@ -63,6 +64,8 @@ const std::string MixAll::DEFAULT_LOAD_BALANCER_STRATEGY_NAME_ = "AVG";
const uint32_t MixAll::DEFAULT_COMPRESS_BODY_THRESHOLD_ = 1024 * 1024 * 4;
+const std::chrono::milliseconds MixAll::DefaultReceiveMessageTimeout = std::chrono::seconds(30);
+
const char* MixAll::HOME_PROFILE_ENV_ = "HOME";
const char* MixAll::MESSAGE_KEY_SEPARATOR = " ";
@@ -135,11 +138,11 @@ const char* MixAll::SPAN_ANNOTATION_AWAIT_CONSUMPTION = "__await_consumption";
const char* MixAll::SPAN_ANNOTATION_MESSAGE_KEYS = "__message_keys";
const char* MixAll::SPAN_ANNOTATION_ATTR_START_TIME = "__start_time";
-bool MixAll::validate(const MQMessage& message) {
- if (message.getTopic().empty()) {
+bool MixAll::validate(const Message& message) {
+ if (message.topic().empty()) {
return false;
}
- const std::string& topic = message.getTopic();
+ const std::string& topic = message.topic();
// Topic should not start with "CID" or "GID" which are reserved prefix
if (absl::StartsWith(topic, "CID") || absl::StartsWith(topic, "GID")) {
return false;
@@ -150,7 +153,7 @@ bool MixAll::validate(const MQMessage& message) {
return false;
}
- uint32_t body_length = message.bodyLength();
+ uint32_t body_length = message.body().length();
if (!body_length || body_length > MAX_MESSAGE_BODY_SIZE) {
return false;
}
@@ -295,4 +298,28 @@ bool MixAll::isIPv4(absl::string_view host) {
return RE2::FullMatch(re2::StringPiece(host.data(), host.length()), IP_REGEX);
}
+const char* MixAll::osName() {
+#if INTPTR_MAX == INT32_MAX
+#define BITS " 32-bit"
+#elif INTPTR_MAX == INT64_MAX
+#define BITS " 64-bit"
+#else
+#define BITS ""
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+ return "Windows" BITS;
+#elif __APPLE__ || __MACH__
+ return "Mac OSX" BITS;
+#elif __linux__
+ return "Linux" BITS;
+#elif __FreeBSD__
+ return "FreeBSD" BITS;
+#elif __unix || __unix__
+ return "Unix" BITS;
+#else
+ return "Other" BITS;
+#endif
+}
+
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/Protocol.cpp b/src/main/cpp/base/Protocol.cpp
index be031e3..91a643b 100644
--- a/src/main/cpp/base/Protocol.cpp
+++ b/src/main/cpp/base/Protocol.cpp
@@ -14,14 +14,140 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include "Protocol.h"
ROCKETMQ_NAMESPACE_BEGIN
-#ifndef CLIENT_PROTOCOL_VERSION
-#define CLIENT_PROTOCOL_VERSION "v1"
-#endif
+const char* protocolVersion() {
+ static const char* protocol_version = "v2";
+ return protocol_version;
+}
+
+bool writable(rmq::Permission p) {
+ switch (p) {
+ case rmq::Permission::WRITE:
+ case rmq::Permission::READ_WRITE:
+ return true;
+ default: {
+ return false;
+ }
+ }
+}
+
+bool readable(rmq::Permission p) {
+ switch (p) {
+ case rmq::Permission::READ:
+ case rmq::Permission::READ_WRITE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool operator<(const rmq::Resource& lhs, const rmq::Resource& rhs) {
+ return lhs.resource_namespace() < rhs.resource_namespace() || lhs.name() < rhs.name();
+}
+
+bool operator==(const rmq::Resource& lhs, const rmq::Resource& rhs) {
+ return lhs.resource_namespace() == rhs.resource_namespace() && lhs.name() == rhs.name();
+}
+
+bool operator<(const rmq::Broker& lhs, const rmq::Broker& rhs) {
+ return lhs.name() < rhs.name() || lhs.id() < rhs.id();
+}
+
+bool operator==(const rmq::Broker& lhs, const rmq::Broker& rhs) {
+ return lhs.name() == rhs.name() && lhs.id() == rhs.id();
+}
+
+bool operator<(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs) {
+ return lhs.topic() < rhs.topic() || lhs.id() < rhs.id() || lhs.broker() < rhs.broker() ||
+ lhs.permission() < rhs.permission();
+}
+
+bool operator==(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs) {
+ return lhs.topic() == rhs.topic() && lhs.id() == rhs.id() && lhs.broker() == rhs.broker() &&
+ lhs.permission() == rhs.permission();
+}
+
+std::string simpleNameOf(const rmq::MessageQueue& m) {
+ return fmt::format("{}{}-{}-{}", m.topic().resource_namespace(), m.topic().name(), m.id(), m.broker().name());
+}
+
+bool operator==(const std::vector<rmq::MessageQueue>& lhs, const std::vector<rmq::MessageQueue>& rhs) {
+ if (lhs.size() != rhs.size()) {
+ return false;
+ }
+
+ for (std::size_t i = 0; i < lhs.size(); i++) {
+ if (lhs[i] == rhs[i]) {
+ continue;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool operator!=(const std::vector<rmq::MessageQueue>& lhs, const std::vector<rmq::MessageQueue>& rhs) {
+ return !(lhs == rhs);
+}
+
+std::string urlOf(const rmq::MessageQueue& message_queue) {
+ const auto& endpoints = message_queue.broker().endpoints();
+ const auto& addresses = endpoints.addresses();
+ switch (endpoints.scheme()) {
+ case rmq::AddressScheme::DOMAIN_NAME: {
+ assert(addresses.size() == 1);
+ auto first = addresses.begin();
+ return fmt::format("dns:{}:{}", first->host(), first->port());
+ }
+ case rmq::AddressScheme::IPv4: {
+ assert(!addresses.empty());
+ auto it = addresses.cbegin();
+ std::string result = fmt::format("ipv4:{}:{}", it->host(), it->port());
+ for (++it; it != addresses.cend(); ++it) {
+ result.append(fmt::format(",{}:{}", it->host(), it->port()));
+ }
+ return result;
+ }
+ case rmq::AddressScheme::IPv6: {
+ assert(!addresses.empty());
+ auto it = addresses.cbegin();
+ std::string result = fmt::format("ipv6:{}:{}", it->host(), it->port());
+ for (++it; it != addresses.cend(); ++it) {
+ result.append(fmt::format(",{}:{}", it->host(), it->port()));
+ }
+ return result;
+ }
+ default: {
+ break;
+ }
+ }
+ return {};
+}
+
+bool operator<(const rmq::Assignment& lhs, const rmq::Assignment& rhs) {
+ return lhs.message_queue() < rhs.message_queue();
+}
+
+bool operator==(const rmq::Assignment& lhs, const rmq::Assignment& rhs) {
+ return lhs.message_queue() == rhs.message_queue();
+}
+
+bool operator==(const std::vector<rmq::Assignment>& lhs, const std::vector<rmq::Assignment>& rhs) {
+ if (lhs.size() != rhs.size()) {
+ return false;
+ }
-const char* Protocol::PROTOCOL_VERSION = CLIENT_PROTOCOL_VERSION;
+ for (std::size_t i = 0; i < lhs.size(); i++) {
+ if (lhs[i] == rhs[i]) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
+ROCKETMQ_NAMESPACE_END
diff --git a/src/main/cpp/base/include/DigestType.h b/src/main/cpp/base/Tracing.cpp
similarity index 83%
copy from src/main/cpp/base/include/DigestType.h
copy to src/main/cpp/base/Tracing.cpp
index e255d82..9eb7335 100644
--- a/src/main/cpp/base/include/DigestType.h
+++ b/src/main/cpp/base/Tracing.cpp
@@ -14,19 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#pragma once
-
-#include <cstdint>
-
-#include "rocketmq/RocketMQ.h"
+#include "rocketmq/Tracing.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class DigestType : int8_t
-{
- CRC32 = 0,
- MD5 = 1,
- SHA1 = 2,
-};
+opencensus::trace::Sampler* traceSampler() {
+ static opencensus::trace::NeverSampler sampler;
+ return &sampler;
+}
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
+ROCKETMQ_NAMESPACE_END
diff --git a/src/main/cpp/base/include/InvocationContext.h b/src/main/cpp/base/include/InvocationContext.h
index cad3e06..910a65d 100644
--- a/src/main/cpp/base/include/InvocationContext.h
+++ b/src/main/cpp/base/include/InvocationContext.h
@@ -30,7 +30,6 @@
#include "LoggerImpl.h"
#include "MetadataConstants.h"
#include "UniqueIdGenerator.h"
-#include "rocketmq/RocketMQ.h"
ROCKETMQ_NAMESPACE_BEGIN
@@ -86,6 +85,7 @@ struct InvocationContext : public BaseInvocationContext {
SPDLOG_WARN("Asynchronous RPC[{}.{}] timed out, elapsing {}ms, deadline-over-due: {}ms",
absl::FormatTime(created_time, absl::UTCTimeZone()), elapsed, diff);
}
+
try {
if (callback) {
callback(this);
diff --git a/src/main/cpp/base/include/MessageAccessor.h b/src/main/cpp/base/include/MessageAccessor.h
deleted file mode 100644
index 371bd23..0000000
--- a/src/main/cpp/base/include/MessageAccessor.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include "rocketmq/MQMessageExt.h"
-
-#include "Protocol.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class MessageAccessor {
-
-public:
- static void setMessageId(MQMessageExt& message, std::string message_id);
-
- static void setBornTimestamp(MQMessageExt& message, absl::Time born_timestamp);
-
- static void setStoreTimestamp(MQMessageExt& message, absl::Time store_timestamp);
-
- static void setQueueId(MQMessageExt& message, int32_t queue_id);
-
- static void setQueueOffset(MQMessageExt& message, int64_t queue_offset);
-
- static void setBornHost(MQMessageExt& message, std::string born_host);
-
- static void setStoreHost(MQMessageExt& message, std::string store_host);
-
- static void setDeliveryTimestamp(MQMessageExt& message, absl::Time delivery_timestamp);
-
- static void setDeliveryAttempt(MQMessageExt& message, int32_t attempt_times);
-
- static void setDecodedTimestamp(MQMessageExt& message, absl::Time decode_timestamp);
- static absl::Time decodedTimestamp(const MQMessageExt& message);
-
- static void setInvisiblePeriod(MQMessageExt& message, absl::Duration invisible_period);
-
- static void setReceiptHandle(MQMessageExt& message, std::string receipt_handle);
- static void setTraceContext(MQMessageExt& message, std::string trace_context);
-
- static void setMessageType(MQMessage& message, MessageType message_type);
-
- static void setTargetEndpoint(MQMessage& message, const std::string& target_endpoint);
-
- static const std::string& targetEndpoint(const MQMessage& message);
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/api/rocketmq/MessageModel.h b/src/main/cpp/base/include/MessageExt.h
similarity index 82%
copy from api/rocketmq/MessageModel.h
copy to src/main/cpp/base/include/MessageExt.h
index 2422d32..31106bb 100644
--- a/api/rocketmq/MessageModel.h
+++ b/src/main/cpp/base/include/MessageExt.h
@@ -16,16 +16,16 @@
*/
#pragma once
-#include "RocketMQ.h"
-
+#include <chrono>
+#include <cstddef>
#include <cstdint>
+#include <string>
+
+#include "Protocol.h"
+#include "rocketmq/Message.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class MessageModel : int8_t
-{
- BROADCASTING,
- CLUSTERING,
-};
+rmq::MessageType typeOf(const Message& message);
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/include/MessageImpl.h b/src/main/cpp/base/include/MessageImpl.h
deleted file mode 100644
index 079ba33..0000000
--- a/src/main/cpp/base/include/MessageImpl.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <map>
-
-#include "Protocol.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-class MessageImpl {
-protected:
- Resource topic_;
- std::map<std::string, std::string> user_attribute_map_;
- SystemAttribute system_attribute_;
- std::string body_;
- friend class MQMessage;
- friend class MQMessageExt;
- friend class MessageAccessor;
-};
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/include/MetadataConstants.h b/src/main/cpp/base/include/MetadataConstants.h
index ac3af5b..a02fc19 100644
--- a/src/main/cpp/base/include/MetadataConstants.h
+++ b/src/main/cpp/base/include/MetadataConstants.h
@@ -24,6 +24,7 @@ class MetadataConstants {
public:
static const char* REQUEST_ID_KEY;
static const char* TENANT_ID_KEY;
+ static const char* CLIENT_ID_KEY;
static const char* NAMESPACE_KEY;
static const char* AUTHORIZATION;
static const char* STS_SESSION_TOKEN;
@@ -36,6 +37,8 @@ public:
static const char* LANGUAGE_KEY;
static const char* CLIENT_VERSION_KEY;
static const char* PROTOCOL_VERSION_KEY;
+ static const char* CLIENT_VERSION;
+ static const char* SERVICE_NAME;
};
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/include/MixAll.h b/src/main/cpp/base/include/MixAll.h
index ae272dc..1483737 100644
--- a/src/main/cpp/base/include/MixAll.h
+++ b/src/main/cpp/base/include/MixAll.h
@@ -23,7 +23,7 @@
#include "absl/strings/string_view.h"
#include "re2/re2.h"
-#include "rocketmq/MQMessage.h"
+#include "rocketmq/Message.h"
ROCKETMQ_NAMESPACE_BEGIN
@@ -49,7 +49,9 @@ public:
static const std::chrono::duration<long long> PROCESS_QUEUE_EXPIRATION_THRESHOLD_;
- static const int32_t MAX_SEND_MESSAGE_ATTEMPT_TIMES_;
+ static const std::chrono::milliseconds DefaultReceiveMessageTimeout;
+
+ static const std::size_t MAX_SEND_MESSAGE_ATTEMPT_TIMES_;
static const std::string PROPERTY_TRANSACTION_PREPARED_;
@@ -142,7 +144,7 @@ public:
* @param message
* @return
*/
- static bool validate(const MQMessage& message);
+ static bool validate(const Message& message);
static uint32_t random(uint32_t left, uint32_t right);
@@ -162,6 +164,8 @@ public:
static bool isIPv4(absl::string_view host);
+ static const char* osName();
+
private:
static bool hexCharValue(char c, uint8_t& value);
};
diff --git a/src/main/cpp/base/include/Protocol.h b/src/main/cpp/base/include/Protocol.h
index 7d52fd6..5a8e671 100644
--- a/src/main/cpp/base/include/Protocol.h
+++ b/src/main/cpp/base/include/Protocol.h
@@ -16,65 +16,77 @@
*/
#pragma once
-#include <chrono>
-#include <string>
-#include <vector>
+#include "absl/hash/hash.h"
+#include "fmt/format.h"
-#include "absl/time/clock.h"
-#include "absl/time/time.h"
+#include "apache/rocketmq/v2/definition.grpc.pb.h"
+#include "apache/rocketmq/v2/definition.pb.h"
+#include "apache/rocketmq/v2/service.grpc.pb.h"
+#include "apache/rocketmq/v2/service.pb.h"
-#include "DigestType.h"
-#include "Encoding.h"
-#include "rocketmq/MessageType.h"
+#include "rocketmq/RocketMQ.h"
ROCKETMQ_NAMESPACE_BEGIN
-class Protocol {
-public:
- static const char* PROTOCOL_VERSION;
-};
-
-struct Digest {
- DigestType digest_type{DigestType::MD5};
- std::string checksum;
- Digest() = default;
-};
-
-struct Resource {
- /**
- * Abstract resource namespace
- */
- std::string resource_namespace;
-
- /**
- * Resource name, which remains unique within given abstract resource namespace.
- */
- std::string name;
-};
-
-struct SystemAttribute {
- std::string tag;
- std::vector<std::string> keys;
- std::string message_id;
- Digest digest;
- Encoding body_encoding;
- MessageType message_type;
- absl::Time born_timestamp{absl::Now()};
- std::string born_host;
- absl::Time store_timestamp{absl::UnixEpoch()};
- std::string store_host;
- absl::Time delivery_timestamp{absl::UnixEpoch()};
- absl::Time decode_timestamp{absl::Now()};
- int32_t delay_level{0};
- std::string receipt_handle;
- int32_t partition_id{0};
- int64_t partition_offset{0};
- absl::Duration invisible_period;
- int32_t attempt_times{0};
- Resource publisher_group;
- std::string trace_context;
- std::string target_endpoint;
- std::string message_group;
-};
-
-ROCKETMQ_NAMESPACE_END
+namespace rmq = apache::rocketmq::v2;
+
+using ChangeInvisibleDurationRequest = rmq::ChangeInvisibleDurationRequest;
+using ChangeInvisibleDurationResponse = rmq::ChangeInvisibleDurationResponse;
+using QueryRouteRequest = rmq::QueryRouteRequest;
+using QueryRouteResponse = rmq::QueryRouteResponse;
+using SendMessageRequest = rmq::SendMessageRequest;
+using SendMessageResponse = rmq::SendMessageResponse;
+using QueryAssignmentRequest = rmq::QueryAssignmentRequest;
+using QueryAssignmentResponse = rmq::QueryAssignmentResponse;
+using ReceiveMessageRequest = rmq::ReceiveMessageRequest;
+using ReceiveMessageResponse = rmq::ReceiveMessageResponse;
+using AckMessageRequest = rmq::AckMessageRequest;
+using AckMessageResponse = rmq::AckMessageResponse;
+using HeartbeatRequest = rmq::HeartbeatRequest;
+using HeartbeatResponse = rmq::HeartbeatResponse;
+using EndTransactionRequest = rmq::EndTransactionRequest;
+using EndTransactionResponse = rmq::EndTransactionResponse;
+using RecoverOrphanedTransactionCommand = rmq::RecoverOrphanedTransactionCommand;
+using PrintThreadStackTraceCommand = rmq::PrintThreadStackTraceCommand;
+using ThreadStackTrace = rmq::ThreadStackTrace;
+using VerifyMessageCommand = rmq::VerifyMessageCommand;
+using VerifyMessageResult = rmq::VerifyMessageResult;
+using TelemetryCommand = rmq::TelemetryCommand;
+using ForwardMessageToDeadLetterQueueRequest = rmq::ForwardMessageToDeadLetterQueueRequest;
+using ForwardMessageToDeadLetterQueueResponse = rmq::ForwardMessageToDeadLetterQueueResponse;
+using NotifyClientTerminationRequest = rmq::NotifyClientTerminationRequest;
+using NotifyClientTerminationResponse = rmq::NotifyClientTerminationResponse;
+
+const char* protocolVersion();
+
+bool writable(rmq::Permission p);
+
+bool readable(rmq::Permission p);
+
+bool operator<(const rmq::Resource& lhs, const rmq::Resource& rhs);
+
+bool operator==(const rmq::Resource& lhs, const rmq::Resource& rhs);
+
+bool operator<(const rmq::Broker& lhs, const rmq::Broker& rhs);
+
+bool operator==(const rmq::Broker& lhs, const rmq::Broker& rhs);
+
+bool operator<(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs);
+
+bool operator==(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs);
+
+std::string simpleNameOf(const rmq::MessageQueue& m);
+
+bool operator==(const std::vector<rmq::MessageQueue>& lhs, const std::vector<rmq::MessageQueue>& rhs);
+
+bool operator!=(const std::vector<rmq::MessageQueue>& lhs, const std::vector<rmq::MessageQueue>& rhs);
+
+std::string urlOf(const rmq::MessageQueue& message_queue);
+
+bool operator<(const rmq::Assignment& lhs, const rmq::Assignment& rhs);
+
+bool operator==(const rmq::Assignment& lhs, const rmq::Assignment& rhs);
+
+bool operator==(const std::vector<rmq::Assignment>& lhs, const std::vector<rmq::Assignment>& rhs);
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/include/RetryPolicy.h b/src/main/cpp/base/include/RetryPolicy.h
new file mode 100644
index 0000000..5cc4138
--- /dev/null
+++ b/src/main/cpp/base/include/RetryPolicy.h
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <cmath>
+#include <cstdint>
+#include <vector>
+
+#include "absl/time/time.h"
+#include "rocketmq/RocketMQ.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+enum class BackoffStrategy : std::uint8_t
+{
+ Customized = 0,
+ Exponential = 1,
+};
+
+struct RetryPolicy {
+ std::uint32_t max_attempt;
+
+ BackoffStrategy strategy;
+
+ // Exponential back-off
+ absl::Duration initial;
+ absl::Duration max;
+ float multiplier;
+
+ // User defined back-off intervals.
+ std::vector<absl::Duration> next;
+
+ std::int64_t backoff(std::size_t attempt) {
+ static std::int64_t default_backoff = 1000;
+ if (!attempt) {
+ attempt = 1;
+ }
+
+ switch (strategy) {
+ case BackoffStrategy::Customized: {
+ if (next.empty()) {
+ return default_backoff;
+ }
+ if (attempt >= next.size()) {
+ return absl::ToInt64Milliseconds(next[next.size() - 1]);
+ }
+ return absl::ToInt64Milliseconds(next[attempt - 1]);
+ }
+
+ case BackoffStrategy::Exponential: {
+ if (!absl::ToInt64Milliseconds(max)) {
+ return default_backoff;
+ }
+
+ auto result = initial * pow(2, attempt);
+ if (result > max) {
+ return absl::ToInt64Milliseconds(max);
+ }
+ return absl::ToInt64Milliseconds(result);
+ }
+ default:
+ return default_backoff;
+ }
+ }
+};
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/rocketmq/include/StsCredentialsProviderImpl.h b/src/main/cpp/base/include/StsCredentialsProviderImpl.h
similarity index 100%
rename from src/main/cpp/rocketmq/include/StsCredentialsProviderImpl.h
rename to src/main/cpp/base/include/StsCredentialsProviderImpl.h
diff --git a/src/main/cpp/base/include/DigestType.h b/src/main/cpp/base/include/SubscriptionEntry.h
similarity index 84%
copy from src/main/cpp/base/include/DigestType.h
copy to src/main/cpp/base/include/SubscriptionEntry.h
index e255d82..9256242 100644
--- a/src/main/cpp/base/include/DigestType.h
+++ b/src/main/cpp/base/include/SubscriptionEntry.h
@@ -17,16 +17,17 @@
#pragma once
#include <cstdint>
+#include <string>
+#include "FilterExpression.h"
+#include "Resource.h"
#include "rocketmq/RocketMQ.h"
ROCKETMQ_NAMESPACE_BEGIN
-enum class DigestType : int8_t
-{
- CRC32 = 0,
- MD5 = 1,
- SHA1 = 2,
+struct SubscriptionEntry {
+ Resource topic;
+ FilterExpression expression;
};
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/tests/AssignmentTest.cpp b/src/main/cpp/base/tests/AssignmentTest.cpp
new file mode 100644
index 0000000..88c3c5a
--- /dev/null
+++ b/src/main/cpp/base/tests/AssignmentTest.cpp
@@ -0,0 +1,23 @@
+#include "gtest/gtest.h"
+#include <algorithm>
+
+#include "Protocol.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class AssignmentTest : public testing::Test {
+public:
+ void SetUp() override {
+ }
+
+ void TearDown() override {
+ }
+};
+
+TEST_F(AssignmentTest, testSort) {
+ std::vector<rmq::Assignment> assignments;
+ std::sort(assignments.begin(), assignments.end(),
+ [](const rmq::Assignment& lhs, const rmq::Assignment& rhs) { return lhs < rhs; });
+}
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/tests/BUILD.bazel b/src/main/cpp/base/tests/BUILD.bazel
new file mode 100644
index 0000000..054dfb5
--- /dev/null
+++ b/src/main/cpp/base/tests/BUILD.bazel
@@ -0,0 +1,54 @@
+load("@rules_cc//cc:defs.bzl", "cc_test")
+
+base_deps = [
+ "//src/main/cpp/base:base_library",
+ "@com_google_googletest//:gtest_main",
+]
+
+cc_test(
+ name = "message_builder_test",
+ srcs = [
+ "MessageBuilderTest.cpp",
+ ],
+ deps = base_deps,
+)
+
+cc_test(
+ name = "assignment_test",
+ srcs = [
+ "AssignmentTest.cpp",
+ ],
+ deps = base_deps,
+)
+
+cc_test(
+ name = "message_queue_test",
+ srcs = [
+ "MessageQueueTest.cpp",
+ ],
+ deps = base_deps,
+)
+
+cc_test(
+ name = "configuration_test",
+ srcs = [
+ "ConfigurationTest.cpp",
+ ],
+ deps = base_deps,
+)
+
+cc_test(
+ name = "mix_all_test",
+ srcs = [
+ "MixAllTest.cpp",
+ ],
+ deps = base_deps,
+)
+
+cc_test(
+ name = "retry_policy_test",
+ srcs = [
+ "RetryPolicyTest.cpp",
+ ],
+ deps = base_deps,
+)
\ No newline at end of file
diff --git a/src/main/cpp/base/tests/ConfigurationTest.cpp b/src/main/cpp/base/tests/ConfigurationTest.cpp
new file mode 100644
index 0000000..9174e39
--- /dev/null
+++ b/src/main/cpp/base/tests/ConfigurationTest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include <memory>
+
+#include "gtest/gtest.h"
+#include "rocketmq/Configuration.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class ConfigurationTest : public testing::Test {
+public:
+protected:
+ std::string endpoints_{"8.8.8.8:80;8.8.4.4:80"};
+ std::chrono::milliseconds request_timeout_{std::chrono::seconds(1)};
+};
+
+TEST_F(ConfigurationTest, testEndpoints) {
+ auto configuration = Configuration::newBuilder().withEndpoints(endpoints_).build();
+ ASSERT_EQ(endpoints_, configuration.endpoints());
+}
+
+TEST_F(ConfigurationTest, testCredentialsProvider) {
+ std::string access_key = "ak";
+ std::string access_secret = "as";
+ auto credentials_provider = std::make_shared<StaticCredentialsProvider>(access_key, access_secret);
+ auto configuration = Configuration::newBuilder().withCredentialsProvider(credentials_provider).build();
+ auto credentials = configuration.credentialsProvider()->getCredentials();
+
+ ASSERT_EQ(access_key, credentials.accessKey());
+ ASSERT_EQ(access_secret, credentials.accessSecret());
+}
+
+TEST_F(ConfigurationTest, testRequestTimeout) {
+ auto configuration = Configuration::newBuilder().withRequestTimeout(request_timeout_).build();
+ ASSERT_EQ(request_timeout_, configuration.requestTimeout());
+}
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/tests/MessageBuilderTest.cpp b/src/main/cpp/base/tests/MessageBuilderTest.cpp
new file mode 100644
index 0000000..9ad4d58
--- /dev/null
+++ b/src/main/cpp/base/tests/MessageBuilderTest.cpp
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+
+#include "MessageExt.h"
+#include "gtest/gtest.h"
+#include "rocketmq/Message.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class MessageBuilderTest : public testing::Test {
+protected:
+ std::string topic_{"TestTopic"};
+ std::string tag_{"TagA"};
+ std::vector<std::string> keys_{"k1", "k2"};
+ std::string body_{"sample body content"};
+ std::string group_{"message-group"};
+};
+
+TEST_F(MessageBuilderTest, testBuilder) {
+ MessageConstPtr message =
+ Message::newBuilder().withTopic(topic_).withTag(tag_).withKeys(keys_).withBody(body_).build();
+ ASSERT_EQ(topic_, message->topic());
+ ASSERT_EQ(tag_, message->tag());
+ ASSERT_TRUE(keys_ == message->keys());
+ ASSERT_EQ(body_, message->body());
+ ASSERT_EQ(false, message->traceContext().has_value());
+}
+
+TEST_F(MessageBuilderTest, testBuilder2) {
+ for (std::size_t i = 0; i < 128; i++) {
+ MessageConstPtr message =
+ Message::newBuilder().withTopic(topic_).withTag(tag_).withKeys(keys_).withBody(body_).build();
+ ASSERT_EQ(topic_, message->topic());
+ ASSERT_EQ(tag_, message->tag());
+ ASSERT_TRUE(keys_ == message->keys());
+ ASSERT_EQ(body_, message->body());
+ ASSERT_EQ(false, message->traceContext().has_value());
+ }
+}
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/base/tests/MessageQueueTest.cpp b/src/main/cpp/base/tests/MessageQueueTest.cpp
new file mode 100644
index 0000000..2db2c83
--- /dev/null
+++ b/src/main/cpp/base/tests/MessageQueueTest.cpp
@@ -0,0 +1,21 @@
+#include <apache/rocketmq/v2/definition.pb.h>
+#include <cstdint>
+
+#include "absl/container/flat_hash_map.h"
+#include "google/protobuf/map.h"
+#include "gtest/gtest.h"
+
+#include "Protocol.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+class MessageQueueTest : public testing::Test {
+public:
+ void SetUp() override {
+ }
+
+ void TearDown() override {
+ }
+};
+
+ROCKETMQ_NAMESPACE_END
diff --git a/src/test/cpp/ut/rocketmq/ConsumerTest.cpp b/src/main/cpp/base/tests/MixAllTest.cpp
similarity index 84%
rename from src/test/cpp/ut/rocketmq/ConsumerTest.cpp
rename to src/main/cpp/base/tests/MixAllTest.cpp
index 0c950c2..e66030e 100644
--- a/src/test/cpp/ut/rocketmq/ConsumerTest.cpp
+++ b/src/main/cpp/base/tests/MixAllTest.cpp
@@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "ConsumerMock.h"
-#include "gmock/gmock.h"
+#include "MixAll.h"
#include "gtest/gtest.h"
ROCKETMQ_NAMESPACE_BEGIN
-TEST(ConsumerMockTest, testMock) {
- testing::NiceMock<ConsumerMock> mock;
+TEST(MixAllTest, testOsName) {
+ const char* os_name = MixAll::osName();
+ std::cout << os_name << std::endl;
}
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/test/cpp/ut/remoting/QueryRouteRequestHeaderTest.cpp b/src/main/cpp/base/tests/RetryPolicyTest.cpp
similarity index 64%
rename from src/test/cpp/ut/remoting/QueryRouteRequestHeaderTest.cpp
rename to src/main/cpp/base/tests/RetryPolicyTest.cpp
index d887ba6..4a49bcc 100644
--- a/src/test/cpp/ut/remoting/QueryRouteRequestHeaderTest.cpp
+++ b/src/main/cpp/base/tests/RetryPolicyTest.cpp
@@ -14,23 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "QueryRouteRequestHeader.h"
-
+#include "RetryPolicy.h"
#include "gtest/gtest.h"
ROCKETMQ_NAMESPACE_BEGIN
-TEST(QueryRouteRequestHeaderTest, testEncode) {
- google::protobuf::Value root;
- QueryRouteRequestHeader header;
- header.topic("abc");
- header.encode(root);
-
- std::string json;
- auto status = google::protobuf::util::MessageToJsonString(root, &json);
- EXPECT_TRUE(status.ok());
- EXPECT_FALSE(json.empty());
- std::cout << json << std::endl;
+TEST(RetryPolicyTest, testBackoff) {
+ RetryPolicy policy{.max_attempt = 3,
+ .strategy = BackoffStrategy::Customized,
+ .next = {absl::Milliseconds(10), absl::Milliseconds(100), absl::Milliseconds(500)}};
+ ASSERT_EQ(policy.backoff(1), 10);
+ ASSERT_EQ(policy.backoff(2), 100);
+ ASSERT_EQ(policy.backoff(3), 500);
+ ASSERT_EQ(policy.backoff(4), 500);
+ ASSERT_EQ(policy.backoff(10000), 500);
}
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/ClientConfigImpl.cpp b/src/main/cpp/client/ClientConfigImpl.cpp
deleted file mode 100644
index 29304e0..0000000
--- a/src/main/cpp/client/ClientConfigImpl.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "ClientConfigImpl.h"
-
-#include <chrono>
-#include <sstream>
-#include <string>
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#include "UtilAll.h"
-
-ROCKETMQ_NAMESPACE_BEGIN
-
-#ifndef CLIENT_VERSION_MAJOR
-#define CLIENT_VERSION_MAJOR "5"
-#endif
-
-#ifndef CLIENT_VERSION_MINOR
-#define CLIENT_VERSION_MINOR "0"
-#endif
-
-#ifndef CLIENT_VERSION_PATCH
-#define CLIENT_VERSION_PATCH "0"
-#endif
-
-const char* ClientConfigImpl::CLIENT_VERSION = CLIENT_VERSION_MAJOR "." CLIENT_VERSION_MINOR "." CLIENT_VERSION_PATCH;
-
-std::string ClientConfigImpl::steadyName() {
- auto duration = std::chrono::steady_clock::now().time_since_epoch();
- return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count());
-}
-
-ClientConfigImpl::ClientConfigImpl(absl::string_view group_name)
- : group_name_(group_name.data(), group_name.length()), io_timeout_(absl::Seconds(3)),
- long_polling_timeout_(absl::Seconds(30)) {
-}
-
-std::string ClientConfigImpl::clientId() const {
- std::stringstream ss;
- ss << UtilAll::hostname();
- ss << "@";
- std::string processID = std::to_string(getpid());
- ss << processID << "#";
- ss << instance_name_;
- return ss.str();
-}
-
-const std::string& ClientConfigImpl::getInstanceName() const {
- return instance_name_;
-}
-
-void ClientConfigImpl::setInstanceName(std::string instance_name) {
- instance_name_ = std::move(instance_name);
-}
-
-const std::string& ClientConfigImpl::getGroupName() const {
- return group_name_;
-}
-
-void ClientConfigImpl::setGroupName(std::string group_name) {
- group_name_ = std::move(group_name);
-}
-
-void ClientConfigImpl::setIoTimeout(absl::Duration timeout) {
- io_timeout_ = timeout;
-}
-
-void ClientConfigImpl::setCredentialsProvider(CredentialsProviderPtr credentials_provider) {
- credentials_provider_ = std::move(credentials_provider);
-}
-
-CredentialsProviderPtr ClientConfigImpl::credentialsProvider() {
- return credentials_provider_;
-}
-
-absl::Duration ClientConfigImpl::getIoTimeout() const {
- return io_timeout_;
-}
-
-ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/ClientManagerFactory.cpp b/src/main/cpp/client/ClientManagerFactory.cpp
index c72aedb..3cacaae 100644
--- a/src/main/cpp/client/ClientManagerFactory.cpp
+++ b/src/main/cpp/client/ClientManagerFactory.cpp
@@ -27,20 +27,20 @@ ClientManagerFactory& ClientManagerFactory::getInstance() {
ClientManagerPtr ClientManagerFactory::getClientManager(const ClientConfig& client_config) {
{
absl::MutexLock lock(&client_manager_table_mtx_);
- auto search = client_manager_table_.find(client_config.resourceNamespace());
+ auto search = client_manager_table_.find(client_config.resource_namespace);
if (search != client_manager_table_.end()) {
ClientManagerPtr client_manager = search->second.lock();
if (client_manager) {
- SPDLOG_DEBUG("Re-use existing client_manager[resource_namespace={}]", client_config.resourceNamespace());
+ SPDLOG_DEBUG("Re-use existing client_manager[resource_namespace={}]", client_config.resource_namespace);
return client_manager;
} else {
- client_manager_table_.erase(client_config.resourceNamespace());
+ client_manager_table_.erase(client_config.resource_namespace);
}
}
- ClientManagerPtr client_manager = std::make_shared<ClientManagerImpl>(client_config.resourceNamespace());
+ ClientManagerPtr client_manager = std::make_shared<ClientManagerImpl>(client_config.resource_namespace);
std::weak_ptr<ClientManager> client_instance_weak_ptr(client_manager);
- client_manager_table_.insert_or_assign(client_config.resourceNamespace(), client_instance_weak_ptr);
- SPDLOG_INFO("Created a new client manager[resource_namespace={}]", client_config.resourceNamespace());
+ client_manager_table_.insert_or_assign(client_config.resource_namespace, client_instance_weak_ptr);
+ SPDLOG_INFO("Created a new client manager[resource_namespace={}]", client_config.resource_namespace);
return client_manager;
}
}
diff --git a/src/main/cpp/client/ClientManagerImpl.cpp b/src/main/cpp/client/ClientManagerImpl.cpp
index d8a43e5..25fc559 100644
--- a/src/main/cpp/client/ClientManagerImpl.cpp
+++ b/src/main/cpp/client/ClientManagerImpl.cpp
@@ -17,59 +17,45 @@
#include "ClientManagerImpl.h"
#include <atomic>
+#include <cassert>
#include <chrono>
#include <memory>
#include <system_error>
#include <utility>
#include <vector>
-#include "ReceiveMessageResult.h"
-#include "Scheduler.h"
-#include "google/rpc/code.pb.h"
-
#include "InvocationContext.h"
#include "LogInterceptor.h"
#include "LogInterceptorFactory.h"
#include "LoggerImpl.h"
-#include "MessageAccessor.h"
+#include "MessageExt.h"
#include "MetadataConstants.h"
#include "MixAll.h"
-#include "Partition.h"
#include "Protocol.h"
+#include "ReceiveMessageContext.h"
#include "RpcClient.h"
#include "RpcClientImpl.h"
+#include "Scheduler.h"
#include "TlsHelper.h"
#include "UtilAll.h"
+#include "google/protobuf/util/time_util.h"
#include "grpcpp/create_channel.h"
#include "rocketmq/ErrorCode.h"
-#include "rocketmq/MQMessageExt.h"
+#include "rocketmq/SendReceipt.h"
ROCKETMQ_NAMESPACE_BEGIN
ClientManagerImpl::ClientManagerImpl(std::string resource_namespace)
: scheduler_(std::make_shared<SchedulerImpl>()), resource_namespace_(std::move(resource_namespace)),
- state_(State::CREATED), completion_queue_(std::make_shared<CompletionQueue>()),
+ state_(State::CREATED),
callback_thread_pool_(absl::make_unique<ThreadPoolImpl>(std::thread::hardware_concurrency())),
latency_histogram_("Message-Latency", 11) {
spdlog::set_level(spdlog::level::trace);
assignLabels(latency_histogram_);
- server_authorization_check_config_ = std::make_shared<grpc::experimental::TlsServerAuthorizationCheckConfig>(
- std::make_shared<TlsServerAuthorizationChecker>());
-
- // Make use of encryption only at the moment.
- std::vector<grpc::experimental::IdentityKeyCertPair> identity_key_cert_list;
- grpc::experimental::IdentityKeyCertPair pair{};
- pair.private_key = TlsHelper::client_private_key;
- pair.certificate_chain = TlsHelper::client_certificate_chain;
-
- identity_key_cert_list.emplace_back(pair);
- certificate_provider_ =
- std::make_shared<grpc::experimental::StaticDataCertificateProvider>(TlsHelper::CA, identity_key_cert_list);
- tls_channel_credential_options_.set_server_verification_option(GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION);
- tls_channel_credential_options_.set_certificate_provider(certificate_provider_);
- tls_channel_credential_options_.set_server_authorization_check_config(server_authorization_check_config_);
- tls_channel_credential_options_.watch_root_certs();
- tls_channel_credential_options_.watch_identity_key_cert_pairs();
+
+ certificate_verifier_ = grpc::experimental::ExternalCertificateVerifier::Create<InsecureCertificateVerifier>();
+ tls_channel_credential_options_.set_verify_server_certs(false);
+ tls_channel_credential_options_.set_check_call_host(false);
channel_credential_ = grpc::experimental::TlsCredentials(tls_channel_credential_options_);
// Use unlimited receive message size.
@@ -97,6 +83,8 @@ ClientManagerImpl::ClientManagerImpl(std::string resource_namespace)
*/
channel_arguments_.SetInt(GRPC_ARG_ENABLE_RETRIES, 0);
+ channel_arguments_.SetSslTargetNameOverride("localhost");
+
SPDLOG_INFO("ClientManager[ResourceNamespace={}] created", resource_namespace_);
}
@@ -118,14 +106,6 @@ void ClientManagerImpl::start() {
std::weak_ptr<ClientManagerImpl> client_instance_weak_ptr = shared_from_this();
- auto health_check_functor = [client_instance_weak_ptr]() {
- auto client_instance = client_instance_weak_ptr.lock();
- if (client_instance) {
- client_instance->doHealthCheck();
- }
- };
- health_check_task_id_ = scheduler_->schedule(health_check_functor, HEALTH_CHECK_TASK_NAME, std::chrono::seconds(5),
- std::chrono::seconds(5));
auto heartbeat_functor = [client_instance_weak_ptr]() {
auto client_instance = client_instance_weak_ptr.lock();
if (client_instance) {
@@ -134,8 +114,7 @@ void ClientManagerImpl::start() {
};
heartbeat_task_id_ =
scheduler_->schedule(heartbeat_functor, HEARTBEAT_TASK_NAME, std::chrono::seconds(1), std::chrono::seconds(10));
-
- completion_queue_thread_ = std::thread(std::bind(&ClientManagerImpl::pollCompletionQueue, this));
+ SPDLOG_DEBUG("Heartbeat task-id={}", heartbeat_task_id_);
auto stats_functor_ = [client_instance_weak_ptr]() {
auto client_instance = client_instance_weak_ptr.lock();
@@ -158,10 +137,6 @@ void ClientManagerImpl::shutdown() {
callback_thread_pool_->shutdown();
- if (health_check_task_id_) {
- scheduler_->cancel(health_check_task_id_);
- }
-
if (heartbeat_task_id_) {
scheduler_->cancel(heartbeat_task_id_);
}
@@ -175,17 +150,11 @@ void ClientManagerImpl::shutdown() {
{
absl::MutexLock lk(&rpc_clients_mtx_);
rpc_clients_.clear();
- SPDLOG_DEBUG("CompletionQueue of active clients stopped");
+ SPDLOG_DEBUG("rpc_clients_ is clear");
}
- completion_queue_->Shutdown();
- if (completion_queue_thread_.joinable()) {
- completion_queue_thread_.join();
- }
- SPDLOG_DEBUG("Completion queue thread completes OK");
-
state_.store(State::STOPPED, std::memory_order_relaxed);
- SPDLOG_DEBUG("Client instance stopped");
+ SPDLOG_DEBUG("ClientManager stopped");
}
void ClientManagerImpl::assignLabels(Histogram& histogram) {
@@ -202,102 +171,6 @@ void ClientManagerImpl::assignLabels(Histogram& histogram) {
histogram.labels().emplace_back("[200ms~inf): ");
}
-void ClientManagerImpl::healthCheck(
- const std::string& target_host, const Metadata& metadata, const HealthCheckRequest& request,
- std::chrono::milliseconds timeout,
- const std::function<void(const std::error_code&, const InvocationContext<HealthCheckResponse>*)>& cb) {
- std::error_code ec;
- auto client = getRpcClient(target_host);
- if (!client) {
- ec = ErrorCode::RequestTimeout;
- cb(ec, nullptr);
- return;
- }
-
- SPDLOG_DEBUG("Prepare to send health-check to {}. Request: {}", target_host, request.DebugString());
-
- auto invocation_context = new InvocationContext<HealthCheckResponse>();
- invocation_context->task_name = fmt::format("HealthCheck to {}", target_host);
- invocation_context->remote_address = target_host;
- invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout);
-
- for (const auto& entry : metadata) {
- invocation_context->context.AddMetadata(entry.first, entry.second);
- }
-
- auto callback = [cb](const InvocationContext<HealthCheckResponse>* ctx) {
- std::error_code ec;
- if (!ctx->status.ok()) {
- ec = ErrorCode::RequestTimeout;
- cb(ec, ctx);
- return;
- }
-
- const auto& common = ctx->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
- cb(ec, ctx);
- } break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}", common.status().message());
- ec = ErrorCode::Unauthorized;
- cb(ec, ctx);
- } break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}", common.status().message());
- ec = ErrorCode::Forbidden;
- cb(ec, ctx);
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}", common.status().message());
- ec = ErrorCode::InternalServerError;
- cb(ec, ctx);
- } break;
- default: {
- SPDLOG_WARN("NotImplemented: please upgrade SDK to latest release");
- ec = ErrorCode::NotImplemented;
- cb(ec, ctx);
- } break;
- }
- };
-
- invocation_context->callback = callback;
- client->asyncHealthCheck(request, invocation_context);
-}
-
-void ClientManagerImpl::doHealthCheck() {
- SPDLOG_DEBUG("Start to perform health check for inactive clients");
- if (State::STARTED != state_.load(std::memory_order_relaxed) &&
- State::STARTING != state_.load(std::memory_order_relaxed)) {
- SPDLOG_WARN("Unexpected client instance state={}.", state_.load(std::memory_order_relaxed));
- return;
- }
-
- auto&& rpc_clients_removed = cleanOfflineRpcClients();
-
- std::vector<std::shared_ptr<Client>> clients;
- {
- absl::MutexLock lk(&clients_mtx_);
- for (auto& item : clients_) {
- auto client = item.lock();
- if (client && client->active()) {
- clients.emplace_back(std::move(client));
- }
- }
- }
-
- if (!rpc_clients_removed.empty()) {
- for (auto& client : clients) {
- client->onRemoteEndpointRemoval(rpc_clients_removed);
- }
- }
-
- for (auto& client : clients) {
- client->healthCheck();
- }
- SPDLOG_DEBUG("Health check completed");
-}
-
std::vector<std::string> ClientManagerImpl::cleanOfflineRpcClients() {
absl::flat_hash_set<std::string> hosts;
{
@@ -351,34 +224,30 @@ void ClientManagerImpl::heartbeat(const std::string& target_host, const Metadata
return;
}
- const auto& common = invocation_context->response.common();
+ auto&& status = invocation_context->response.status();
std::error_code ec;
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
+ switch (status.code()) {
+ case rmq::Code::OK: {
cb(ec, invocation_context->response);
} break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}", common.status().message());
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Unauthorized;
cb(ec, invocation_context->response);
} break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}", common.status().message());
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Forbidden;
cb(ec, invocation_context->response);
} break;
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}", common.status().message());
- ec = ErrorCode::BadRequest;
- cb(ec, invocation_context->response);
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}", common.status().message());
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::InternalServerError;
cb(ec, invocation_context->response);
} break;
default: {
- SPDLOG_WARN("NotImplemented: Please upgrade SDK to latest release");
+ SPDLOG_WARN("NotImplemented: Please upgrade SDK to latest release. Message={}, host={}", status.message(),
+ invocation_context->remote_address);
} break;
}
};
@@ -391,60 +260,35 @@ void ClientManagerImpl::heartbeat(const std::string& target_host, const Metadata
void ClientManagerImpl::doHeartbeat() {
if (State::STARTED != state_.load(std::memory_order_relaxed) &&
State::STARTING != state_.load(std::memory_order_relaxed)) {
- SPDLOG_WARN("Unexpected client instance state={}.", state_.load(std::memory_order_relaxed));
+ SPDLOG_WARN("Unexpected client manager state={}.", state_.load(std::memory_order_relaxed));
return;
}
- std::vector<std::shared_ptr<Client>> clients;
{
absl::MutexLock lk(&clients_mtx_);
for (const auto& item : clients_) {
auto client = item.lock();
if (client && client->active()) {
- clients.emplace_back(std::move(client));
- }
- }
- }
-
- for (auto& client : clients) {
- client->heartbeat();
- }
-}
-
-void ClientManagerImpl::pollCompletionQueue() {
- while (State::STARTED == state_.load(std::memory_order_relaxed) ||
- State::STARTING == state_.load(std::memory_order_relaxed)) {
- bool ok = false;
- void* opaque_invocation_context;
- while (completion_queue_->Next(&opaque_invocation_context, &ok)) {
- auto invocation_context = static_cast<BaseInvocationContext*>(opaque_invocation_context);
- if (!ok) {
- // the call is dead
- SPDLOG_WARN("CompletionQueue#Next assigned ok false, indicating the call is dead");
+ client->heartbeat();
}
- auto callback = [invocation_context, ok]() { invocation_context->onCompletion(ok); };
- callback_thread_pool_->submit(callback);
}
- SPDLOG_INFO("CompletionQueue is fully drained and shut down");
}
- SPDLOG_INFO("pollCompletionQueue completed and quit");
}
bool ClientManagerImpl::send(const std::string& target_host, const Metadata& metadata, SendMessageRequest& request,
- SendCallback* cb) {
+ SendCallback cb) {
assert(cb);
SPDLOG_DEBUG("Prepare to send message to {} asynchronously", target_host);
RpcClientSharedPtr client = getRpcClient(target_host);
// Invocation context will be deleted in its onComplete() method.
auto invocation_context = new InvocationContext<SendMessageResponse>();
- invocation_context->task_name =
- fmt::format("Send message[] to {}", request.message().system_attribute().message_id(), target_host);
+ invocation_context->task_name = fmt::format("Send message to {}", target_host);
invocation_context->remote_address = target_host;
for (const auto& entry : metadata) {
invocation_context->context.AddMetadata(entry.first, entry.second);
}
- const std::string& topic = request.message().topic().name();
+ const std::string& topic = request.messages().begin()->topic().name();
std::weak_ptr<ClientManager> client_manager(shared_from_this());
auto completion_callback = [topic, cb,
client_manager](const InvocationContext<SendMessageResponse>* invocation_context) {
@@ -458,54 +302,51 @@ bool ClientManagerImpl::send(const std::string& target_host, const Metadata& met
return;
}
- const auto& common = invocation_context->response.common();
-
+ SendReceipt send_receipt;
+ std::error_code ec;
if (!invocation_context->status.ok()) {
SPDLOG_WARN("Failed to send message to {} due to gRPC error. gRPC code: {}, gRPC error message: {}",
invocation_context->remote_address, invocation_context->status.error_code(),
invocation_context->status.error_message());
- std::error_code ec = ErrorCode::RequestTimeout;
- cb->onFailure(ec);
+ ec = ErrorCode::RequestTimeout;
+ cb(ec, send_receipt);
return;
}
- if (invocation_context->status.ok()) {
- switch (invocation_context->response.common().status().code()) {
- case google::rpc::Code::OK: {
- SendResult send_result;
- send_result.setSendStatus(SendStatus::SEND_OK);
- send_result.setMsgId(invocation_context->response.message_id());
- send_result.setTransactionId(invocation_context->response.transaction_id());
- cb->onSuccess(send_result);
- } break;
-
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}", common.status().message());
- std::error_code ec = ErrorCode::BadRequest;
- cb->onFailure(ec);
- } break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}", common.status().message());
- std::error_code ec = ErrorCode::Unauthorized;
- cb->onFailure(ec);
- } break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}", common.status().message());
- std::error_code ec = ErrorCode::Forbidden;
- cb->onFailure(ec);
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}", common.status().message());
- std::error_code ec = ErrorCode::InternalServerError;
- cb->onFailure(ec);
- } break;
- default: {
- SPDLOG_WARN("Unsupported status code. Check and upgrade SDK to the latest");
- std::error_code ec = ErrorCode::NotImplemented;
- cb->onFailure(ec);
- } break;
+ auto&& status = invocation_context->response.status();
+ switch (invocation_context->response.status().code()) {
+ case rmq::Code::OK: {
+ send_receipt.message_id = invocation_context->response.receipts().begin()->message_id();
+ break;
+ }
+ case rmq::Code::TOPIC_NOT_FOUND: {
+ SPDLOG_WARN("TopicNotFound: {}", status.message());
+ ec = ErrorCode::NotFound;
+ break;
+ }
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthenticated: {}", status.message());
+ ec = ErrorCode::Unauthorized;
+ break;
+ }
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden: {}", status.message());
+ ec = ErrorCode::Forbidden;
+ cb(ec, send_receipt);
+ break;
+ }
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}", status.message());
+ ec = ErrorCode::InternalServerError;
+ break;
+ }
+ default: {
+ SPDLOG_WARN("Unsupported status code. Check and upgrade SDK to the latest");
+ ec = ErrorCode::NotImplemented;
+ break;
}
}
+ cb(ec, send_receipt);
};
invocation_context->callback = completion_callback;
@@ -542,7 +383,8 @@ RpcClientSharedPtr ClientManagerImpl::getRpcClient(const std::string& target_hos
interceptor_factories.emplace_back(absl::make_unique<LogInterceptorFactory>());
auto channel = grpc::experimental::CreateCustomChannelWithInterceptors(
target_host, channel_credential_, channel_arguments_, std::move(interceptor_factories));
- client = std::make_shared<RpcClientImpl>(completion_queue_, channel, need_heartbeat);
+ std::weak_ptr<ClientManager> client_manager(shared_from_this());
+ client = std::make_shared<RpcClientImpl>(client_manager, channel, target_host, need_heartbeat);
rpc_clients_.insert_or_assign(target_host, client);
} else {
client = search->second;
@@ -568,18 +410,27 @@ void ClientManagerImpl::cleanRpcClients() {
rpc_clients_.clear();
}
-SendResult ClientManagerImpl::processSendResponse(const MQMessageQueue& message_queue,
- const SendMessageResponse& response) {
- if (google::rpc::Code::OK != response.common().status().code()) {
- THROW_MQ_EXCEPTION(MQClientException, response.common().DebugString(), response.common().status().code());
+SendReceipt ClientManagerImpl::processSendResponse(const rmq::MessageQueue& message_queue,
+ const SendMessageResponse& response, std::error_code& ec) {
+ SendReceipt send_receipt;
+
+ switch (response.status().code()) {
+ case rmq::Code::OK: {
+ assert(response.receipts_size() > 0);
+ send_receipt.message_id = response.receipts().begin()->message_id();
+ send_receipt.transaction_id = response.receipts().begin()->transaction_id();
+ return send_receipt;
+ }
+ case rmq::Code::ILLEGAL_TOPIC: {
+ ec = ErrorCode::BadRequest;
+ return send_receipt;
+ }
+ default: {
+ // TODO: handle other cases.
+ break;
+ }
}
- SendResult send_result;
- send_result.setSendStatus(SendStatus::SEND_OK);
- send_result.setMsgId(response.message_id());
- send_result.setQueueOffset(-1);
- send_result.setMessageQueue(message_queue);
- send_result.setTransactionId(response.transaction_id());
- return send_result;
+ return send_receipt;
}
void ClientManagerImpl::addClientObserver(std::weak_ptr<Client> client) {
@@ -618,81 +469,33 @@ void ClientManagerImpl::resolveRoute(const std::string& target_host, const Metad
}
std::error_code ec;
- const auto& common = invocation_context->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
- auto& partitions = invocation_context->response.partitions();
- std::vector<Partition> topic_partitions;
- for (const auto& partition : partitions) {
- Topic t(partition.topic().resource_namespace(), partition.topic().name());
-
- auto& broker = partition.broker();
- AddressScheme scheme = AddressScheme::IPv4;
- switch (broker.endpoints().scheme()) {
- case rmq::AddressScheme::IPv4:
- scheme = AddressScheme::IPv4;
- break;
- case rmq::AddressScheme::IPv6:
- scheme = AddressScheme::IPv6;
- break;
- case rmq::AddressScheme::DOMAIN_NAME:
- scheme = AddressScheme::DOMAIN_NAME;
- break;
- default:
- break;
- }
-
- std::vector<Address> addresses;
- for (const auto& address : broker.endpoints().addresses()) {
- addresses.emplace_back(Address{address.host(), address.port()});
- }
- ServiceAddress service_address(scheme, addresses);
- Broker b(partition.broker().name(), partition.broker().id(), service_address);
-
- Permission permission = Permission::READ_WRITE;
- switch (partition.permission()) {
- case rmq::Permission::READ:
- permission = Permission::READ;
- break;
-
- case rmq::Permission::WRITE:
- permission = Permission::WRITE;
- break;
- case rmq::Permission::READ_WRITE:
- permission = Permission::READ_WRITE;
- break;
- default:
- break;
- }
- Partition topic_partition(t, partition.id(), permission, std::move(b));
- topic_partitions.emplace_back(std::move(topic_partition));
+ auto&& status = invocation_context->response.status();
+ switch (status.code()) {
+ case rmq::Code::OK: {
+ std::vector<rmq::MessageQueue> message_queues;
+ for (const auto& item : invocation_context->response.message_queues()) {
+ message_queues.push_back(item);
}
- auto ptr =
- std::make_shared<TopicRouteData>(std::move(topic_partitions), invocation_context->response.DebugString());
+ auto ptr = std::make_shared<TopicRouteData>(std::move(message_queues));
cb(ec, ptr);
} break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}. Host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized: {}. Host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Unauthorized;
cb(ec, nullptr);
} break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}. Host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden: {}. Host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Forbidden;
cb(ec, nullptr);
} break;
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}. Host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::BadRequest;
- cb(ec, nullptr);
- } break;
- case google::rpc::Code::NOT_FOUND: {
- SPDLOG_WARN("NotFound: {}. Host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::TOPIC_NOT_FOUND: {
+ SPDLOG_WARN("TopicNotFound: {}. Host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::NotFound;
cb(ec, nullptr);
} break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}. Host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}. Host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::InternalServerError;
cb(ec, nullptr);
} break;
@@ -722,26 +525,22 @@ void ClientManagerImpl::queryAssignment(
return;
}
- const auto& common = invocation_context->response.common();
+ auto&& status = invocation_context->response.status();
std::error_code ec;
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
+ switch (status.code()) {
+ case rmq::Code::OK: {
SPDLOG_DEBUG("Query assignment OK");
} break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Unauthorized;
} break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Forbidden;
} break;
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::BadRequest;
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::InternalServerError;
} break;
default: {
@@ -766,124 +565,53 @@ void ClientManagerImpl::queryAssignment(
void ClientManagerImpl::receiveMessage(const std::string& target_host, const Metadata& metadata,
const ReceiveMessageRequest& request, std::chrono::milliseconds timeout,
- const std::shared_ptr<ReceiveMessageCallback>& cb) {
+ ReceiveMessageCallback cb) {
SPDLOG_DEBUG("Prepare to receive message from {} asynchronously. Request: {}", target_host, request.DebugString());
RpcClientSharedPtr client = getRpcClient(target_host);
-
- auto invocation_context = new InvocationContext<ReceiveMessageResponse>();
- invocation_context->task_name = fmt::format("ReceiveMessage from queue[{}-{}-{}-{}], host={}", request.group().name(),
- request.partition().topic().name(), request.partition().broker().name(),
- request.partition().id(), target_host);
- invocation_context->remote_address = target_host;
- if (!metadata.empty()) {
- for (const auto& item : metadata) {
- invocation_context->context.AddMetadata(item.first, item.second);
- }
- }
- invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout);
-
- auto callback = [this, cb](const InvocationContext<ReceiveMessageResponse>* invocation_context) {
- std::error_code ec;
- ReceiveMessageResult result;
-
- // Handle network error.
- if (!invocation_context->status.ok()) {
- SPDLOG_WARN("Failed to pop messages through gRPC from {}, gRPC code: {}, gRPC error message: {}",
- invocation_context->remote_address, invocation_context->status.error_code(),
- invocation_context->status.error_message());
- ec = ErrorCode::RequestTimeout;
- cb->onCompletion(ec, result);
- return;
- }
-
- // Handle application layer logic
- result.source_host = invocation_context->remote_address;
- const auto& common = invocation_context->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
- SPDLOG_TRACE("ReceivedMessage Resonse: {}, host={}", invocation_context->response.DebugString(),
- invocation_context->remote_address);
- for (auto& item : invocation_context->response.messages()) {
- MQMessageExt message_ext;
- MessageAccessor::setTargetEndpoint(message_ext, invocation_context->remote_address);
- if (wrapMessage(item, message_ext)) {
- result.messages.emplace_back(message_ext);
- } else {
- SPDLOG_WARN("A message fails to pass body checksum validation. Skip processing it.");
- }
- }
- break;
- }
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}. Host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::Unauthorized;
- } break;
-
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}. Host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::Forbidden;
- } break;
-
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}. Host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::BadRequest;
- } break;
-
- case google::rpc::Code::DEADLINE_EXCEEDED: {
- SPDLOG_WARN("DeadlineExceeded: {}. Host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::GatewayTimeout;
- } break;
-
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("IntervalServerError: {}. Host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::InternalServerError;
- } break;
- default: {
- SPDLOG_WARN("Unsupported code. Please upgrade to use the latest release. Host={}",
- invocation_context->remote_address);
- ec = ErrorCode::NotImplemented;
- } break;
- }
- cb->onCompletion(ec, result);
- };
- invocation_context->callback = callback;
- client->asyncReceive(request, invocation_context);
+ auto context = absl::make_unique<ReceiveMessageContext>();
+ context->callback = std::move(cb);
+ context->metadata = metadata;
+ context->timeout = timeout;
+ client->asyncReceive(request, std::move(context));
}
State ClientManagerImpl::state() const {
return state_.load(std::memory_order_relaxed);
}
-bool ClientManagerImpl::wrapMessage(const rmq::Message& item, MQMessageExt& message_ext) {
+MessageConstSharedPtr ClientManagerImpl::wrapMessage(const rmq::Message& item) {
assert(item.topic().resource_namespace() == resource_namespace_);
+ auto builder = Message::newBuilder();
// base
- message_ext.setTopic(item.topic().name());
-
- const auto& system_attributes = item.system_attribute();
+ builder.withTopic(item.topic().name());
- // Receipt-handle
- MessageAccessor::setReceiptHandle(message_ext, system_attributes.receipt_handle());
+ const auto& system_properties = item.system_properties();
// Tag
- message_ext.setTags(system_attributes.tag());
+ if (system_properties.has_tag()) {
+ builder.withTag(system_properties.tag());
+ }
// Keys
std::vector<std::string> keys;
- for (const auto& key : system_attributes.keys()) {
+ for (const auto& key : system_properties.keys()) {
keys.push_back(key);
}
- message_ext.setKeys(keys);
+ if (!keys.empty()) {
+ builder.withKeys(std::move(keys));
+ }
// Message-Id
- MessageAccessor::setMessageId(message_ext, system_attributes.message_id());
+ const auto& message_id = system_properties.message_id();
+ builder.withId(message_id);
// Validate body digest
- const rmq::Digest& digest = system_attributes.body_digest();
+ const rmq::Digest& digest = system_properties.body_digest();
bool body_digest_match = false;
if (item.body().empty()) {
SPDLOG_WARN("Body of message[topic={}, msgId={}] is empty", item.topic().name(),
- item.system_attribute().message_id());
+ item.system_properties().message_id());
body_digest_match = true;
} else {
switch (digest.type()) {
@@ -908,10 +636,10 @@ bool ClientManagerImpl::wrapMessage(const rmq::Message& item, MQMessageExt& mess
if (success) {
body_digest_match = (digest.checksum() == checksum);
if (body_digest_match) {
- SPDLOG_DEBUG("Body of message[{}] MD5 checksum validation passed.", message_ext.getMsgId());
+ SPDLOG_DEBUG("Body of message[{}] MD5 checksum validation passed.", message_id);
} else {
- SPDLOG_WARN("Body of message[{}] MD5 checksum validation failed. Expect: {}, Actual: {}",
- message_ext.getMsgId(), digest.checksum(), checksum);
+ SPDLOG_WARN("Body of message[{}] MD5 checksum validation failed. Expect: {}, Actual: {}", message_id,
+ digest.checksum(), checksum);
}
} else {
SPDLOG_WARN("Failed to calculate MD5 digest. Skip.");
@@ -925,13 +653,13 @@ bool ClientManagerImpl::wrapMessage(const rmq::Message& item, MQMessageExt& mess
if (success) {
body_digest_match = (checksum == digest.checksum());
if (body_digest_match) {
- SPDLOG_DEBUG("Body of message[{}] SHA1 checksum validation passed", message_ext.getMsgId());
+ SPDLOG_DEBUG("Body of message[{}] SHA1 checksum validation passed", message_id);
} else {
- SPDLOG_WARN("Body of message[{}] SHA1 checksum validation failed. Expect: {}, Actual: {}",
- message_ext.getMsgId(), digest.checksum(), checksum);
+ SPDLOG_WARN("Body of message[{}] SHA1 checksum validation failed. Expect: {}, Actual: {}", message_id,
+ digest.checksum(), checksum);
}
} else {
- SPDLOG_WARN("Failed to calculate SHA1 digest for message[{}]. Skip.", message_ext.getMsgId());
+ SPDLOG_WARN("Failed to calculate SHA1 digest for message[{}]. Skip.", message_id);
}
break;
}
@@ -944,21 +672,21 @@ bool ClientManagerImpl::wrapMessage(const rmq::Message& item, MQMessageExt& mess
}
if (!body_digest_match) {
- SPDLOG_WARN("Message body checksum failed. MsgId={}", system_attributes.message_id());
+ SPDLOG_WARN("Message body checksum failed. MsgId={}", system_properties.message_id());
// TODO: NACK it immediately
- return false;
+ return nullptr;
}
// Body encoding
- switch (system_attributes.body_encoding()) {
+ switch (system_properties.body_encoding()) {
case rmq::Encoding::GZIP: {
std::string uncompressed;
UtilAll::uncompress(item.body(), uncompressed);
- message_ext.setBody(uncompressed);
+ builder.withBody(uncompressed);
break;
}
case rmq::Encoding::IDENTITY: {
- message_ext.setBody(item.body());
+ builder.withBody(item.body());
break;
}
default: {
@@ -967,106 +695,82 @@ bool ClientManagerImpl::wrapMessage(const rmq::Message& item, MQMessageExt& mess
}
}
- timeval tv{};
-
- // Message-type
- MessageType message_type;
- switch (system_attributes.message_type()) {
- case rmq::MessageType::NORMAL:
- message_type = MessageType::NORMAL;
- break;
- case rmq::MessageType::FIFO:
- message_type = MessageType::FIFO;
- break;
- case rmq::MessageType::DELAY:
- message_type = MessageType::DELAY;
- break;
- case rmq::MessageType::TRANSACTION:
- message_type = MessageType::TRANSACTION;
- break;
- default:
- SPDLOG_WARN("Unknown message type. Treat it as normal message");
- message_type = MessageType::NORMAL;
- break;
+ // User-properties
+ std::unordered_map<std::string, std::string> properties;
+ for (const auto& it : item.user_properties()) {
+ properties.insert(std::make_pair(it.first, it.second));
+ }
+ if (!properties.empty()) {
+ builder.withProperties(properties);
}
- MessageAccessor::setMessageType(message_ext, message_type);
// Born-timestamp
- if (system_attributes.has_born_timestamp()) {
- tv.tv_sec = system_attributes.born_timestamp().seconds();
- tv.tv_usec = system_attributes.born_timestamp().nanos() / 1000;
- auto born_timestamp = absl::TimeFromTimeval(tv);
- MessageAccessor::setBornTimestamp(message_ext, born_timestamp);
+ if (system_properties.has_born_timestamp()) {
+ auto born_timestamp = google::protobuf::util::TimeUtil::TimestampToMilliseconds(system_properties.born_timestamp());
+ builder.withBornTime(absl::ToChronoTime(absl::FromUnixMillis(born_timestamp)));
}
// Born-host
- MessageAccessor::setBornHost(message_ext, system_attributes.born_host());
+ builder.withBornHost(system_properties.born_host());
+
+ // Trace-context
+ if (system_properties.has_trace_context()) {
+ builder.withTraceContext(system_properties.trace_context());
+ }
+
+ auto message = builder.build();
+
+ const Message* raw = message.release();
+ Message* msg = const_cast<Message*>(raw);
+ Extension& extension = msg->mutableExtension();
+
+ // Receipt-handle
+ extension.receipt_handle = system_properties.receipt_handle();
// Store-timestamp
- if (system_attributes.has_store_timestamp()) {
- tv.tv_sec = system_attributes.store_timestamp().seconds();
- tv.tv_usec = system_attributes.store_timestamp().nanos() / 1000;
- MessageAccessor::setStoreTimestamp(message_ext, absl::TimeFromTimeval(tv));
+ if (system_properties.has_store_timestamp()) {
+ auto store_timestamp =
+ google::protobuf::util::TimeUtil::TimestampToMilliseconds(system_properties.store_timestamp());
+ extension.store_time = absl::ToChronoTime(absl::FromUnixMillis(store_timestamp));
}
// Store-host
- MessageAccessor::setStoreHost(message_ext, system_attributes.store_host());
+ extension.store_host = system_properties.store_host();
// Process one-of: delivery-timestamp and delay-level.
- switch (system_attributes.timed_delivery_case()) {
- case rmq::SystemAttribute::TimedDeliveryCase::kDelayLevel: {
- message_ext.setDelayTimeLevel(system_attributes.delay_level());
- break;
- }
-
- case rmq::SystemAttribute::TimedDeliveryCase::kDeliveryTimestamp: {
- tv.tv_sec = system_attributes.delivery_timestamp().seconds();
- tv.tv_usec = system_attributes.delivery_timestamp().nanos();
- MessageAccessor::setDeliveryTimestamp(message_ext, absl::TimeFromTimeval(tv));
- break;
- }
-
- default:
- break;
+ if (system_properties.has_delivery_timestamp()) {
+ auto delivery_timestamp_ms =
+ google::protobuf::util::TimeUtil::TimestampToMilliseconds(system_properties.delivery_timestamp());
+ extension.delivery_timepoint = absl::ToChronoTime(absl::FromUnixMillis(delivery_timestamp_ms));
}
- // Partition-id
- MessageAccessor::setQueueId(message_ext, system_attributes.partition_id());
+ // Queue-id
+ extension.queue_id = system_properties.queue_id();
- // Partition-offset
- MessageAccessor::setQueueOffset(message_ext, system_attributes.partition_offset());
+ // Queue-offset
+ extension.offset = system_properties.queue_offset();
// Invisible-period
- if (system_attributes.has_invisible_period()) {
- absl::Duration invisible_period = absl::Seconds(system_attributes.invisible_period().seconds()) +
- absl::Nanoseconds(system_attributes.invisible_period().nanos());
- MessageAccessor::setInvisiblePeriod(message_ext, invisible_period);
+ if (system_properties.has_invisible_duration()) {
+ auto invisible_period = std::chrono::seconds(system_properties.invisible_duration().seconds()) +
+ std::chrono::nanoseconds(system_properties.invisible_duration().nanos());
+ extension.invisible_period = invisible_period;
}
// Delivery attempt
- MessageAccessor::setDeliveryAttempt(message_ext, system_attributes.delivery_attempt());
-
- // Trace-context
- MessageAccessor::setTraceContext(message_ext, system_attributes.trace_context());
+ extension.delivery_attempt = system_properties.delivery_attempt();
// Decoded Time-Point
- MessageAccessor::setDecodedTimestamp(message_ext, absl::Now());
-
- // User-properties
- std::map<std::string, std::string> properties;
- for (const auto& it : item.user_attribute()) {
- properties.insert(std::make_pair(it.first, it.second));
- }
- message_ext.setProperties(properties);
+ extension.decode_time = std::chrono::system_clock::now();
// Extension
{
- auto elapsed = static_cast<int32_t>(absl::ToUnixMillis(absl::Now()) - message_ext.getStoreTimestamp());
+ auto elapsed = MixAll::millisecondsOf(std::chrono::system_clock::now() - extension.store_time);
if (elapsed >= 0) {
latency_histogram_.countIn(elapsed / 20);
}
}
- return true;
+ return MessageConstSharedPtr(raw);
}
SchedulerSharedPtr ClientManagerImpl::getScheduler() {
@@ -1081,7 +785,7 @@ void ClientManagerImpl::ack(const std::string& target, const Metadata& metadata,
RpcClientSharedPtr client = getRpcClient(target_host);
auto invocation_context = new InvocationContext<AckMessageResponse>();
- invocation_context->task_name = fmt::format("Ack message[{}] against {}", request.message_id(), target);
+ invocation_context->task_name = fmt::format("Ack messages against {}", target);
invocation_context->remote_address = target_host;
invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout);
@@ -1098,25 +802,21 @@ void ClientManagerImpl::ack(const std::string& target, const Metadata& metadata,
return;
}
- const auto& common = invocation_context->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
+ auto&& status = invocation_context->response.status();
+ switch (status.code()) {
+ case rmq::Code::OK: {
SPDLOG_DEBUG("Ack OK. host={}", invocation_context->remote_address);
} break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Unauthorized;
} break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("PermissionDenied: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Forbidden;
} break;
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::BadRequest;
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::InternalServerError;
} break;
default: {
@@ -1130,13 +830,14 @@ void ClientManagerImpl::ack(const std::string& target, const Metadata& metadata,
client->asyncAck(request, invocation_context);
}
-void ClientManagerImpl::nack(const std::string& target_host, const Metadata& metadata,
- const NackMessageRequest& request, std::chrono::milliseconds timeout,
- const std::function<void(const std::error_code&)>& completion_callback) {
+void ClientManagerImpl::changeInvisibleDuration(
+ const std::string& target_host, const Metadata& metadata, const ChangeInvisibleDurationRequest& request,
+ std::chrono::milliseconds timeout, const std::function<void(const std::error_code&)>& completion_callback) {
RpcClientSharedPtr client = getRpcClient(target_host);
assert(client);
- auto invocation_context = new InvocationContext<NackMessageResponse>();
- invocation_context->task_name = fmt::format("Nack Message[{}] against {}", request.message_id(), target_host);
+ auto invocation_context = new InvocationContext<ChangeInvisibleDurationResponse>();
+ invocation_context->task_name = fmt::format("ChangeInvisibleDuration Message[receipt-handle={}] against {}",
+ request.receipt_handle(), target_host);
invocation_context->remote_address = target_host;
invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout);
@@ -1144,7 +845,7 @@ void ClientManagerImpl::nack(const std::string& target_host, const Metadata& met
invocation_context->context.AddMetadata(item.first, item.second);
}
- auto callback = [completion_callback](const InvocationContext<NackMessageResponse>* invocation_context) {
+ auto callback = [completion_callback](const InvocationContext<ChangeInvisibleDurationResponse>* invocation_context) {
if (!invocation_context->status.ok()) {
SPDLOG_WARN("Failed to write Nack request to wire. gRPC-code: {}, gRPC-message: {}",
invocation_context->status.error_code(), invocation_context->status.error_message());
@@ -1154,24 +855,24 @@ void ClientManagerImpl::nack(const std::string& target_host, const Metadata& met
}
std::error_code ec;
- const auto& common = invocation_context->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
+ auto&& status = invocation_context->response.status();
+ switch (status.code()) {
+ case rmq::Code::OK: {
SPDLOG_DEBUG("Nack to {} OK", invocation_context->remote_address);
break;
};
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Unauthorized;
break;
}
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Forbidden;
break;
}
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::InternalServerError;
break;
}
@@ -1184,7 +885,7 @@ void ClientManagerImpl::nack(const std::string& target_host, const Metadata& met
completion_callback(ec);
};
invocation_context->callback = callback;
- client->asyncNack(request, invocation_context);
+ client->asyncChangeInvisibleDuration(request, invocation_context);
}
void ClientManagerImpl::endTransaction(
@@ -1225,26 +926,26 @@ void ClientManagerImpl::endTransaction(
return;
}
- const auto& common = invocation_context->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
+ auto&& status = invocation_context->response.status();
+ switch (status.code()) {
+ case rmq::Code::OK: {
SPDLOG_DEBUG("endTransaction completed OK. Response: {}, host={}", invocation_context->response.DebugString(),
invocation_context->remote_address);
} break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Unauthorized;
} break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::Forbidden;
} break;
- case google::rpc::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}, host={}", common.status().message(), invocation_context->remote_address);
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address);
ec = ErrorCode::InternalServerError;
} break;
default: {
- SPDLOG_WARN("NotImplemented: please upgrade SDK to latest release. {}, host={}", common.status().message(),
+ SPDLOG_WARN("NotImplemented: please upgrade SDK to latest release. {}, host={}", status.message(),
invocation_context->remote_address);
ec = ErrorCode::NotImplemented;
}
@@ -1256,177 +957,6 @@ void ClientManagerImpl::endTransaction(
client->asyncEndTransaction(request, invocation_context);
}
-void ClientManagerImpl::pollCommand(const std::string& target, const Metadata& metadata,
- const PollCommandRequest& request, std::chrono::milliseconds timeout,
- const std::function<void(const InvocationContext<PollCommandResponse>*)>& cb) {
- auto client = getRpcClient(target);
-
- auto invocation_context = new InvocationContext<PollCommandResponse>();
- invocation_context->remote_address = target;
- for (const auto& item : metadata) {
- invocation_context->context.AddMetadata(item.first, item.second);
- }
- auto deadline = std::chrono::system_clock::now() + timeout;
- invocation_context->context.set_deadline(deadline);
-
- auto callback = [cb](const InvocationContext<PollCommandResponse>* invocation_context) { cb(invocation_context); };
-
- invocation_context->callback = callback;
- client->asyncPollCommand(request, invocation_context);
-}
-
-void ClientManagerImpl::queryOffset(const std::string& target_host, const Metadata& metadata,
- const QueryOffsetRequest& request, std::chrono::milliseconds timeout,
- const std::function<void(const std::error_code&, const QueryOffsetResponse&)>& cb) {
- auto client = getRpcClient(target_host);
- std::error_code ec;
- if (!client) {
- SPDLOG_WARN("Failed to get/create RPC client for {}", target_host);
- ec = ErrorCode::RequestTimeout;
- QueryOffsetResponse response;
- cb(ec, response);
- return;
- }
-
- auto invocation_context = new InvocationContext<QueryOffsetResponse>();
- invocation_context->remote_address = target_host;
- invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout);
-
- for (const auto& entry : metadata) {
- invocation_context->context.AddMetadata(entry.first, entry.second);
- }
-
- auto callback = [cb](const InvocationContext<QueryOffsetResponse>* invocation_context) {
- std::error_code ec;
-
- if (!invocation_context->status.ok()) {
- SPDLOG_WARN("Failed to write QueryOffset request to wire. gRPC-code: {}, gRPC-message: {}, host={}",
- invocation_context->status.error_code(), invocation_context->status.error_message(),
- invocation_context->remote_address);
- ec = ErrorCode::RequestTimeout;
- cb(ec, invocation_context->response);
- return;
- }
-
- const auto& common = invocation_context->response.common();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
- SPDLOG_DEBUG("Query offset from server[host={}] OK", invocation_context->remote_address);
- cb(ec, invocation_context->response);
- } break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::Unauthorized;
- cb(ec, invocation_context->response);
- } break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::Forbidden;
- cb(ec, invocation_context->response);
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::InternalServerError;
- cb(ec, invocation_context->response);
- } break;
- default: {
- SPDLOG_WARN("NotImplemented: please upgrade SDK to the latest release. host={}",
- invocation_context->remote_address);
- ec = ErrorCode::NotImplemented;
- cb(ec, invocation_context->response);
- }
- }
- };
- invocation_context->callback = callback;
- client->asyncQueryOffset(request, invocation_context);
-}
-
-void ClientManagerImpl::pullMessage(
- const std::string& target_host, const Metadata& metadata, const PullMessageRequest& request,
- std::chrono::milliseconds timeout,
- const std::function<void(const std::error_code&, const ReceiveMessageResult&)>& cb) {
- SPDLOG_DEBUG("PullMessage Request: {}, target_host={}", request.DebugString(), target_host);
- auto client = getRpcClient(target_host);
- auto invocation_context = new InvocationContext<PullMessageResponse>();
- invocation_context->task_name = fmt::format("PullMessage for queue[{}-{}-{}-{}] from {}", request.group().name(),
- request.partition().topic().name(), request.partition().broker().name(),
- request.partition().id(), target_host);
- invocation_context->remote_address = target_host;
- invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout);
- for (const auto& item : metadata) {
- invocation_context->context.AddMetadata(item.first, item.second);
- }
-
- auto callback = [cb, this](const InvocationContext<PullMessageResponse>* invocation_context) {
- std::error_code ec;
- ReceiveMessageResult result;
- result.source_host = invocation_context->remote_address;
- // Handle network issue.
- if (!invocation_context->status.ok()) {
- ec = ErrorCode::RequestTimeout;
- cb(ec, result);
- return;
- }
-
- // Handle application layer logic: map status::code to corresponding error_code.
- const auto& common = invocation_context->response.common();
- result.min_offset = invocation_context->response.min_offset();
- result.next_offset = invocation_context->response.next_offset();
- result.max_offset = invocation_context->response.max_offset();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
- SPDLOG_TRACE("Received PullMessage Response: {}, host={}", invocation_context->response.DebugString(),
- invocation_context->remote_address);
- for (const auto& item : invocation_context->response.messages()) {
- MQMessageExt message;
- if (!wrapMessage(item, message)) {
- return;
- }
- result.messages.emplace_back(message);
- }
- } break;
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::Forbidden;
- } break;
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::Unauthorized;
- } break;
- case google::rpc::Code::NOT_FOUND: {
- SPDLOG_WARN("NotFound: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::NotFound;
- break;
- }
- case google::rpc::Code::DEADLINE_EXCEEDED: {
- SPDLOG_WARN("DeadlineExceeded: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::GatewayTimeout;
- } break;
- case google::rpc::Code::INVALID_ARGUMENT: {
- SPDLOG_WARN("InvalidArgument: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::BadRequest;
- } break;
- case google::rpc::Code::FAILED_PRECONDITION: {
- SPDLOG_WARN("FailedPrecondition: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::PreconditionRequired;
- } break;
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: {}, host={}", common.status().message(), invocation_context->remote_address);
- ec = ErrorCode::InternalServerError;
- } break;
- default: {
- SPDLOG_WARN("Unimplemented: Please upgrade to use latest SDK release, host={}",
- invocation_context->remote_address);
- ec = ErrorCode::NotImplemented;
- } break;
- }
- cb(ec, result);
- };
-
- invocation_context->callback = callback;
- client->asyncPull(request, invocation_context);
-}
-
void ClientManagerImpl::forwardMessageToDeadLetterQueue(
const std::string& target_host, const Metadata& metadata, const ForwardMessageToDeadLetterQueueRequest& request,
std::chrono::milliseconds timeout,
@@ -1458,93 +988,6 @@ void ClientManagerImpl::forwardMessageToDeadLetterQueue(
client->asyncForwardMessageToDeadLetterQueue(request, invocation_context);
}
-std::error_code ClientManagerImpl::reportThreadStackTrace(const std::string& target_host, const Metadata& metadata,
- const ReportThreadStackTraceRequest& request,
- std::chrono::milliseconds timeout) {
- std::error_code ec;
- auto client = getRpcClient(target_host);
- grpc::ClientContext context;
- auto deadline = std::chrono::system_clock::now() + timeout;
- context.set_deadline(deadline);
-
- for (const auto& item : metadata) {
- context.AddMetadata(item.first, item.second);
- }
-
- ReportThreadStackTraceResponse response;
- auto status = client->reportThreadStackTrace(&context, request, &response);
- if (!status.ok()) {
- ec = ErrorCode::RequestTimeout;
- SPDLOG_WARN("Failed to report thread-stack-trace to {}. Cause: {}", target_host, status.error_message());
- return ec;
- }
-
- switch (response.common().status().code()) {
- case google::rpc::Code::OK: {
- return ec;
- }
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthorized. Host={}, Cause: {}", target_host, response.common().status().message());
- ec = ErrorCode::Unauthorized;
- break;
- }
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("Forbidden. Host={}, Cause: {}", target_host, response.common().status().message());
- ec = ErrorCode::Forbidden;
- break;
- }
- default: {
- ec = ErrorCode::NotImplemented;
- SPDLOG_WARN("Unsupported response code, please update client to latest release. Host={}", target_host);
- }
- }
- return ec;
-}
-
-std::error_code ClientManagerImpl::reportMessageConsumptionResult(const std::string& target_host,
- const Metadata& metadata,
- const ReportMessageConsumptionResultRequest& request,
- std::chrono::milliseconds timeout) {
- std::error_code ec;
- auto client = getRpcClient(target_host);
- grpc::ClientContext context;
- auto deadline = std::chrono::system_clock::now() + timeout;
- context.set_deadline(deadline);
-
- for (const auto& item : metadata) {
- context.AddMetadata(item.first, item.second);
- }
-
- ReportMessageConsumptionResultResponse response;
- auto status = client->reportMessageConsumptionResult(&context, request, &response);
- if (!status.ok()) {
- ec = ErrorCode::RequestTimeout;
- SPDLOG_WARN("Failed to report thread-stack-trace to {}. Cause: {}", target_host, status.error_message());
- return ec;
- }
-
- switch (response.common().status().code()) {
- case google::rpc::Code::OK: {
- return ec;
- }
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthorized. Host={}, Cause: {}", target_host, response.common().status().message());
- ec = ErrorCode::Unauthorized;
- break;
- }
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("Forbidden. Host={}, Cause: {}", target_host, response.common().status().message());
- ec = ErrorCode::Forbidden;
- break;
- }
- default: {
- ec = ErrorCode::NotImplemented;
- SPDLOG_WARN("Unsupported response code, please update client to latest release. Host={}", target_host);
- }
- }
- return ec;
-}
-
std::error_code ClientManagerImpl::notifyClientTermination(const std::string& target_host, const Metadata& metadata,
const NotifyClientTerminationRequest& request,
std::chrono::milliseconds timeout) {
@@ -1565,33 +1008,37 @@ std::error_code ClientManagerImpl::notifyClientTermination(const std::string& ta
SPDLOG_DEBUG("NotifyClientTermination request: {}", request.DebugString());
NotifyClientTerminationResponse response;
- grpc::Status status = client->notifyClientTermination(&context, request, &response);
- if (!status.ok()) {
- SPDLOG_WARN("NotifyClientTermination failed. gRPC-code={}, gRPC-message={}, host={}", status.error_code(),
- status.error_message(), target_host);
- ec = ErrorCode::RequestTimeout;
- return ec;
+ {
+ grpc::Status status = client->notifyClientTermination(&context, request, &response);
+ if (!status.ok()) {
+ SPDLOG_WARN("NotifyClientTermination failed. gRPC-code={}, gRPC-message={}, host={}", status.error_code(),
+ status.error_message(), target_host);
+ ec = ErrorCode::RequestTimeout;
+ return ec;
+ }
}
- const auto& common = response.common();
+ auto&& status = response.status();
- switch (common.status().code()) {
- case google::rpc::Code::OK: {
+ switch (status.code()) {
+ case rmq::Code::OK: {
SPDLOG_DEBUG("NotifyClientTermination OK. host={}", target_host);
break;
}
- case google::rpc::Code::INTERNAL: {
- SPDLOG_WARN("InternalServerError: Cause={}, host={}", common.status().message(), target_host);
+ case rmq::Code::INTERNAL_SERVER_ERROR: {
+ SPDLOG_WARN("InternalServerError: Cause={}, host={}", status.message(), target_host);
ec = ErrorCode::InternalServerError;
break;
}
- case google::rpc::Code::UNAUTHENTICATED: {
- SPDLOG_WARN("Unauthenticated: Cause={}, host={}", common.status().message(), target_host);
+ case rmq::Code::UNAUTHORIZED: {
+ SPDLOG_WARN("Unauthorized due to lack of valid authentication credentials: Cause={}, host={}", status.message(),
+ target_host);
ec = ErrorCode::Unauthorized;
break;
}
- case google::rpc::Code::PERMISSION_DENIED: {
- SPDLOG_WARN("PermissionDenied: Cause={}, host={}", common.status().message(), target_host);
+ case rmq::Code::FORBIDDEN: {
+ SPDLOG_WARN("Forbidden due to insufficient permission to the resource: Cause={}, host={}", status.message(),
+ target_host);
ec = ErrorCode::Forbidden;
break;
}
@@ -1611,11 +1058,14 @@ void ClientManagerImpl::logStats() {
}
void ClientManagerImpl::submit(std::function<void()> task) {
+ State current_state = state();
+ if (current_state == State::STOPPING || current_state == State::STOPPED) {
+ return;
+ }
callback_thread_pool_->submit(task);
}
const char* ClientManagerImpl::HEARTBEAT_TASK_NAME = "heartbeat-task";
const char* ClientManagerImpl::STATS_TASK_NAME = "stats-task";
-const char* ClientManagerImpl::HEALTH_CHECK_TASK_NAME = "health-check-task";
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/ReceiveMessageStreamReader.cpp b/src/main/cpp/client/ReceiveMessageStreamReader.cpp
new file mode 100644
index 0000000..223c879
--- /dev/null
+++ b/src/main/cpp/client/ReceiveMessageStreamReader.cpp
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReceiveMessageStreamReader.h"
+
+#include "LoggerImpl.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+ReceiveMessageStreamReader::ReceiveMessageStreamReader(std::weak_ptr<ClientManager> client_manager,
+ rmq::MessagingService::Stub* stub,
+ std::string peer_address,
+ rmq::ReceiveMessageRequest request,
+ std::unique_ptr<ReceiveMessageContext> context)
+ : client_manager_(client_manager),
+ stub_(stub),
+ peer_address_(std::move(peer_address)),
+ request_(std::move(request)),
+ context_(std::move(context)) {
+ for (const auto& entry : context_->metadata) {
+ client_context_.AddMetadata(entry.first, entry.second);
+ }
+ client_context_.set_deadline(std::chrono::system_clock::now() + context_->timeout);
+
+ stub_->async()->ReceiveMessage(&client_context_, &request_, this);
+ result_.source_host = peer_address_;
+ StartCall();
+ StartRead(&response_);
+}
+
+void ReceiveMessageStreamReader::OnReadDone(bool ok) {
+ if (ok) {
+ SPDLOG_DEBUG("ReceiveMessageStreamReader#OnReadDone: ok={}", ok);
+ } else {
+ if (result_.messages.empty() && !ec_) {
+ SPDLOG_WARN("ReceiveMessageStreamReader#OnReadDone: ok={}", ok);
+ ec_ = ErrorCode::BadGateway;
+ } else {
+ SPDLOG_DEBUG("ReceiveMessageStreamReader#OnReadDone reached end-of-stream");
+ }
+ return;
+ }
+
+ SPDLOG_DEBUG("ReceiveMessageStreamReader#OnReadDone: response={}", response_.DebugString());
+ switch (response_.content_case()) {
+ case rmq::ReceiveMessageResponse::ContentCase::kStatus: {
+ SPDLOG_DEBUG("ReceiveMessageResponse.status.message={}", response_.status().message());
+ switch (response_.status().code()) {
+ case rmq::Code::OK: {
+ break;
+ }
+ case rmq::Code::TOPIC_NOT_FOUND: {
+ ec_ = ErrorCode::TopicNotFound;
+ break;
+ }
+
+ case rmq::Code::CONSUMER_GROUP_NOT_FOUND: {
+ ec_ = ErrorCode::GroupNotFound;
+ break;
+ }
+ case rmq::Code::TOO_MANY_REQUESTS: {
+ ec_ = ErrorCode::TooManyRequest;
+ break;
+ }
+ case rmq::Code::MESSAGE_NOT_FOUND: {
+ ec_ = ErrorCode::NoContent;
+ break;
+ }
+ default:
+ SPDLOG_WARN("Unsupported code={}", response_.status().code());
+ break;
+ }
+ break;
+ }
+ case rmq::ReceiveMessageResponse::ContentCase::kMessage: {
+ auto client_manager = client_manager_.lock();
+ auto message = client_manager->wrapMessage(response_.message());
+ auto raw = const_cast<Message*>(message.get());
+ raw->mutableExtension().target_endpoint = peer_address_;
+ if (message) {
+ result_.messages.push_back(message);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ StartRead(&response_);
+}
+
+void ReceiveMessageStreamReader::OnDone(const grpc::Status& s) {
+ if (!s.ok()) {
+ SPDLOG_WARN("ReceiveMessageStreamReader#OnDone: status.ok={}, status.error_message={}", s.ok(), s.error_message());
+ } else {
+ SPDLOG_DEBUG("ReceiveMessageStreamReader#OnDone: status.ok={}", s.ok());
+ }
+
+ status_ = s;
+ context_->callback(ec_, result_);
+ delete this;
+}
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/RpcClientImpl.cpp b/src/main/cpp/client/RpcClientImpl.cpp
index 5d546b0..623547e 100644
--- a/src/main/cpp/client/RpcClientImpl.cpp
+++ b/src/main/cpp/client/RpcClientImpl.cpp
@@ -17,103 +17,115 @@
#include "RpcClientImpl.h"
#include <chrono>
+#include <functional>
+#include <sstream>
+#include <thread>
-#include "ClientConfigImpl.h"
-#include "TlsHelper.h"
#include "absl/time/time.h"
-using ClientContext = grpc::ClientContext;
+#include "ClientManager.h"
+#include "ReceiveMessageStreamReader.h"
+#include "RpcClient.h"
+#include "TelemetryBidiReactor.h"
+#include "TlsHelper.h"
+#include "include/ReceiveMessageContext.h"
ROCKETMQ_NAMESPACE_BEGIN
+using ClientContext = grpc::ClientContext;
+
+void RpcClientImpl::asyncCallback(std::weak_ptr<RpcClient> client, BaseInvocationContext* invocation_context,
+ grpc::Status status) {
+
+ invocation_context->status = std::move(status);
+ std::shared_ptr<RpcClient> stub = client.lock();
+ if (!stub) {
+ SPDLOG_WARN("RpcClient has destructed. Response Ignored");
+ // TODO: execute orphan callback in event-loop thread?
+ // invocation_context->onCompletion(false);
+ // or
+ delete invocation_context;
+ return;
+ }
+
+ std::weak_ptr<ClientManager> client_manager = stub->clientManager();
+ std::shared_ptr<ClientManager> manager = client_manager.lock();
+ if (!manager) {
+ SPDLOG_WARN("ClientManager has destructed. Response ignored");
+ // TODO: execute orphan callback in event-loop thread?
+ // invocation_context->onCompletion(false);
+ // or
+ delete invocation_context;
+ }
+
+ auto task = [invocation_context, client] {
+ auto ptr = client.lock();
+ if (!ptr) {
+ // RPC client should have destructed.
+ return;
+ }
+ invocation_context->onCompletion(invocation_context->status.ok());
+ };
+
+ // Execute business post-processing in callback thread pool.
+ manager->submit(task);
+}
+
void RpcClientImpl::asyncQueryRoute(const QueryRouteRequest& request,
InvocationContext<QueryRouteResponse>* invocation_context) {
- invocation_context->response_reader =
- stub_->PrepareAsyncQueryRoute(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->QueryRoute(&invocation_context->context, &request, &invocation_context->response, callback);
}
void RpcClientImpl::asyncSend(const SendMessageRequest& request,
InvocationContext<SendMessageResponse>* invocation_context) {
- invocation_context->response_reader =
- stub_->PrepareAsyncSendMessage(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->SendMessage(&invocation_context->context, &request, &invocation_context->response, callback);
}
void RpcClientImpl::asyncQueryAssignment(const QueryAssignmentRequest& request,
InvocationContext<QueryAssignmentResponse>* invocation_context) {
- invocation_context->response_reader =
- stub_->PrepareAsyncQueryAssignment(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
-}
-
-std::shared_ptr<grpc::CompletionQueue>& rocketmq::RpcClientImpl::completionQueue() {
- return completion_queue_;
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->QueryAssignment(&invocation_context->context, &request, &invocation_context->response, callback);
}
-void RpcClientImpl::asyncReceive(const ReceiveMessageRequest& request,
- InvocationContext<ReceiveMessageResponse>* invocation_context) {
- invocation_context->response_reader =
- stub_->PrepareAsyncReceiveMessage(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+void RpcClientImpl::asyncReceive(const ReceiveMessageRequest& request, std::unique_ptr<ReceiveMessageContext> context) {
+ new ReceiveMessageStreamReader(client_manager_, stub_.get(), peer_address_, request, std::move(context));
}
void RpcClientImpl::asyncAck(const AckMessageRequest& request,
InvocationContext<AckMessageResponse>* invocation_context) {
- assert(invocation_context);
- invocation_context->response_reader =
- stub_->PrepareAsyncAckMessage(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->AckMessage(&invocation_context->context, &request, &invocation_context->response, callback);
}
-void RpcClientImpl::asyncNack(const NackMessageRequest& request,
- InvocationContext<NackMessageResponse>* invocation_context) {
- assert(invocation_context);
- invocation_context->response_reader =
- stub_->PrepareAsyncNackMessage(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+void RpcClientImpl::asyncChangeInvisibleDuration(
+ const ChangeInvisibleDurationRequest& request,
+ InvocationContext<ChangeInvisibleDurationResponse>* invocation_context) {
+
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+
+ stub_->async()->ChangeInvisibleDuration(&invocation_context->context, &request, &invocation_context->response,
+ callback);
}
void RpcClientImpl::asyncHeartbeat(const HeartbeatRequest& request,
InvocationContext<HeartbeatResponse>* invocation_context) {
- assert(invocation_context);
- invocation_context->response_reader =
- stub_->PrepareAsyncHeartbeat(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
-}
-
-void RpcClientImpl::asyncHealthCheck(const HealthCheckRequest& request,
- InvocationContext<HealthCheckResponse>* invocation_context) {
- assert(invocation_context);
- invocation_context->response_reader =
- stub_->PrepareAsyncHealthCheck(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->Heartbeat(&invocation_context->context, &request, &invocation_context->response, callback);
}
void RpcClientImpl::asyncEndTransaction(const EndTransactionRequest& request,
InvocationContext<EndTransactionResponse>* invocation_context) {
- assert(invocation_context);
- invocation_context->response_reader =
- stub_->PrepareAsyncEndTransaction(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->EndTransaction(&invocation_context->context, &request, &invocation_context->response, callback);
}
bool RpcClientImpl::ok() const {
@@ -135,25 +147,8 @@ void RpcClientImpl::needHeartbeat(bool need_heartbeat) {
need_heartbeat_ = need_heartbeat;
}
-void RpcClientImpl::asyncPollCommand(const PollCommandRequest& request,
- InvocationContext<PollCommandResponse>* invocation_context) {
- invocation_context->response_reader =
- stub_->PrepareAsyncPollCommand(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
-}
-
-grpc::Status RpcClientImpl::reportThreadStackTrace(grpc::ClientContext* context,
- const ReportThreadStackTraceRequest& request,
- ReportThreadStackTraceResponse* response) {
- return stub_->ReportThreadStackTrace(context, request, response);
-}
-
-grpc::Status RpcClientImpl::reportMessageConsumptionResult(grpc::ClientContext* context,
- const ReportMessageConsumptionResultRequest& request,
- ReportMessageConsumptionResultResponse* response) {
- return stub_->ReportMessageConsumptionResult(context, request, response);
+std::shared_ptr<TelemetryBidiReactor> RpcClientImpl::asyncTelemetry(std::weak_ptr<Client> client) {
+ return std::make_shared<TelemetryBidiReactor>(client, stub_.get(), peer_address_);
}
grpc::Status RpcClientImpl::notifyClientTermination(grpc::ClientContext* context,
@@ -162,33 +157,17 @@ grpc::Status RpcClientImpl::notifyClientTermination(grpc::ClientContext* context
return stub_->NotifyClientTermination(context, request, response);
}
-void RpcClientImpl::asyncQueryOffset(const QueryOffsetRequest& request,
- InvocationContext<QueryOffsetResponse>* invocation_context) {
- assert(invocation_context);
- invocation_context->response_reader =
- stub_->PrepareAsyncQueryOffset(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
-}
-
-void RpcClientImpl::asyncPull(const PullMessageRequest& request,
- InvocationContext<PullMessageResponse>* invocation_context) {
- invocation_context->response_reader =
- stub_->PrepareAsyncPullMessage(&invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
-}
-
void RpcClientImpl::asyncForwardMessageToDeadLetterQueue(
const ForwardMessageToDeadLetterQueueRequest& request,
InvocationContext<ForwardMessageToDeadLetterQueueResponse>* invocation_context) {
- invocation_context->response_reader = stub_->PrepareAsyncForwardMessageToDeadLetterQueue(
- &invocation_context->context, request, completion_queue_.get());
- invocation_context->response_reader->StartCall();
- invocation_context->response_reader->Finish(&invocation_context->response, &invocation_context->status,
- invocation_context);
+ std::weak_ptr<RpcClient> rpc_client(shared_from_this());
+ auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1);
+ stub_->async()->ForwardMessageToDeadLetterQueue(&invocation_context->context, &request, &invocation_context->response,
+ callback);
+}
+
+std::weak_ptr<ClientManager> RpcClientImpl::clientManager() {
+ return client_manager_;
}
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/rocketmq/AwaitPullCallback.cpp b/src/main/cpp/client/SessionImpl.cpp
similarity index 55%
rename from src/main/cpp/rocketmq/AwaitPullCallback.cpp
rename to src/main/cpp/client/SessionImpl.cpp
index f4a5d99..5b7c085 100644
--- a/src/main/cpp/rocketmq/AwaitPullCallback.cpp
+++ b/src/main/cpp/client/SessionImpl.cpp
@@ -14,33 +14,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "AwaitPullCallback.h"
+
+#include "SessionImpl.h"
+#include "LoggerImpl.h"
ROCKETMQ_NAMESPACE_BEGIN
-void AwaitPullCallback::onSuccess(const PullResult& pull_result) noexcept {
- absl::MutexLock lk(&mtx_);
- completed_ = true;
- // TODO: optimize out messages copy here.
- pull_result_ = pull_result;
- cv_.SignalAll();
+SessionImpl::SessionImpl(std::weak_ptr<Client> client, std::shared_ptr<RpcClient> rpc_client) : client_(client), rpc_client_(rpc_client) {
+ telemetry_ = rpc_client->asyncTelemetry(client_);
+ syncSettings();
+}
+
+bool SessionImpl::await() {
+ return telemetry_->await();
}
-void AwaitPullCallback::onFailure(const std::error_code& ec) noexcept {
- absl::MutexLock lk(&mtx_);
- completed_ = true;
- ec_ = ec;
- cv_.SignalAll();
+void SessionImpl::syncSettings() {
+ auto ptr = client_.lock();
+
+ TelemetryCommand command;
+ command.mutable_settings()->CopyFrom(ptr->clientSettings());
+ telemetry_->write(command);
}
-bool AwaitPullCallback::await() {
- {
- absl::MutexLock lk(&mtx_);
- while (!completed_) {
- cv_.Wait(&mtx_);
- }
- return !hasFailure();
- }
+SessionImpl::~SessionImpl() {
+ SPDLOG_DEBUG("Session for {} destructed", rpc_client_->remoteAddress());
+ telemetry_->fireClose();
}
ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/Signature.cpp b/src/main/cpp/client/Signature.cpp
index 3364158..e25dbb5 100644
--- a/src/main/cpp/client/Signature.cpp
+++ b/src/main/cpp/client/Signature.cpp
@@ -15,7 +15,7 @@
* limitations under the License.
*/
#include "Signature.h"
-#include "ClientConfigImpl.h"
+#include "ClientConfig.h"
#include "MetadataConstants.h"
#include "Protocol.h"
#include "TlsHelper.h"
@@ -23,29 +23,21 @@
ROCKETMQ_NAMESPACE_BEGIN
-void Signature::sign(ClientConfig* client, absl::flat_hash_map<std::string, std::string>& metadata) {
- assert(client);
+void Signature::sign(const ClientConfig& client, absl::flat_hash_map<std::string, std::string>& metadata) {
metadata.insert({MetadataConstants::LANGUAGE_KEY, "CPP"});
// Add common headers
- metadata.insert({MetadataConstants::CLIENT_VERSION_KEY, ClientConfigImpl::CLIENT_VERSION});
- metadata.insert({MetadataConstants::PROTOCOL_VERSION_KEY, Protocol::PROTOCOL_VERSION});
-
- if (!client->tenantId().empty()) {
- metadata.insert({MetadataConstants::TENANT_ID_KEY, client->tenantId()});
- }
-
- if (!client->resourceNamespace().empty()) {
- metadata.insert({MetadataConstants::NAMESPACE_KEY, client->resourceNamespace()});
- }
+ metadata.insert({MetadataConstants::CLIENT_ID_KEY, client.client_id});
+ metadata.insert({MetadataConstants::CLIENT_VERSION_KEY, MetadataConstants::CLIENT_VERSION});
+ metadata.insert({MetadataConstants::PROTOCOL_VERSION_KEY, protocolVersion()});
absl::Time now = absl::Now();
absl::TimeZone utc_time_zone = absl::UTCTimeZone();
const std::string request_date_time = absl::FormatTime(MetadataConstants::DATE_TIME_FORMAT, now, utc_time_zone);
metadata.insert({MetadataConstants::DATE_TIME_KEY, request_date_time});
- if (client->credentialsProvider()) {
- Credentials&& credentials = client->credentialsProvider()->getCredentials();
+ if (client.credentials_provider) {
+ Credentials&& credentials = client.credentials_provider->getCredentials();
if (credentials.accessKey().empty() || credentials.accessSecret().empty()) {
SPDLOG_WARN("Access credential is incomplete. Check your access key/secret.");
return;
@@ -58,9 +50,9 @@ void Signature::sign(ClientConfig* client, absl::flat_hash_map<std::string, std:
.append("=")
.append(credentials.accessKey())
.append("/")
- .append(client->region())
+ .append(client.region)
.append("/")
- .append(client->serviceName())
+ .append(MetadataConstants::SERVICE_NAME)
.append(", ")
.append(MetadataConstants::SIGNED_HEADERS_KEY)
.append("=")
diff --git a/src/main/cpp/client/TelemetryBidiReactor.cpp b/src/main/cpp/client/TelemetryBidiReactor.cpp
new file mode 100644
index 0000000..f39cdec
--- /dev/null
+++ b/src/main/cpp/client/TelemetryBidiReactor.cpp
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TelemetryBidiReactor.h"
+
+#include <atomic>
+#include <memory>
+#include <utility>
+
+#include "ClientManager.h"
+#include "LoggerImpl.h"
+#include "MessageExt.h"
+#include "Metadata.h"
+#include "RpcClient.h"
+#include "Signature.h"
+#include "google/protobuf/util/time_util.h"
+
+ROCKETMQ_NAMESPACE_BEGIN
+
+TelemetryBidiReactor::TelemetryBidiReactor(std::weak_ptr<Client> client,
+ rmq::MessagingService::Stub* stub,
+ std::string peer_address)
+ : client_(client), peer_address_(std::move(peer_address)), stream_state_(StreamState::Created) {
+ auto ptr = client.lock();
+ auto deadline = std::chrono::system_clock::now() + std::chrono::hours(1);
+ context_.set_deadline(deadline);
+ Metadata metadata;
+ Signature::sign(ptr->config(), metadata);
+ for (const auto& entry : metadata) {
+ context_.AddMetadata(entry.first, entry.second);
+ }
+ stub->async()->Telemetry(&context_, this);
+ StartCall();
+}
+
+TelemetryBidiReactor::~TelemetryBidiReactor() {
+ SPDLOG_INFO("Telemetry stream for {} destructed. StreamState={}", peer_address_, stream_state_);
+}
+
+bool TelemetryBidiReactor::await() {
+ absl::MutexLock lk(&server_setting_received_mtx_);
+ if (server_setting_received_) {
+ return true;
+ }
+
+ server_setting_received_cv_.Wait(&server_setting_received_mtx_);
+ return server_setting_received_;
+}
+
+void TelemetryBidiReactor::OnWriteDone(bool ok) {
+ SPDLOG_DEBUG("OnWriteDone: {}", ok);
+
+ {
+ bool expect = true;
+ if (!command_inflight_.compare_exchange_strong(expect, false, std::memory_order_relaxed)) {
+ SPDLOG_WARN("Illegal command-inflight state");
+ }
+ }
+
+ if (!ok) {
+ SPDLOG_WARN("Failed to write telemetry command {} to {}", write_.DebugString(), peer_address_);
+ {
+ absl::MutexLock lk(&stream_state_mtx_);
+ stream_state_ = StreamState::WriteDone;
+ }
+
+ fireClose();
+ return;
+ }
+
+ {
+ absl::MutexLock lk(&stream_state_mtx_);
+ if (StreamState::Created == stream_state_) {
+ stream_state_ = StreamState::Active;
+ fireRead();
+ }
+ }
+
+ fireWrite();
+}
+
+void TelemetryBidiReactor::OnReadDone(bool ok) {
+ SPDLOG_DEBUG("OnReadDone: ok={}", ok);
+ if (!ok) {
+ SPDLOG_WARN("Failed to read telemetry command from {}", peer_address_);
+ {
+ absl::MutexLock lk(&stream_state_mtx_);
+ stream_state_ = StreamState::ReadDone;
+ }
+ fireClose();
+ return;
+ }
+
+ SPDLOG_DEBUG("Read a telemetry command from {}: {}", peer_address_, read_.DebugString());
+ auto ptr = client_.lock();
+ if (!ptr) {
+ SPDLOG_INFO("Client for {} has destructed", peer_address_);
+ return;
+ }
+
+ switch (read_.command_case()) {
+ case rmq::TelemetryCommand::kSettings: {
+ auto settings = read_.settings();
+ SPDLOG_INFO("Received settings from {}: {}", peer_address_, settings.DebugString());
+ applySettings(settings);
+ {
+ absl::MutexLock lk(&server_setting_received_mtx_);
+ if (!server_setting_received_) {
+ server_setting_received_ = true;
+ server_setting_received_cv_.SignalAll();
+ }
+ }
+ break;
+ }
+ case rmq::TelemetryCommand::kRecoverOrphanedTransactionCommand: {
+ auto client = client_.lock();
+ if (!client) {
+ fireClose();
+ return;
+ }
+
+ auto message = client->manager()->wrapMessage(read_.release_verify_message_command()->message());
+ auto raw = const_cast<Message*>(message.get());
+ raw->mutableExtension().target_endpoint = peer_address_;
+ raw->mutableExtension().transaction_id = read_.recover_orphaned_transaction_command().transaction_id();
+ client->recoverOrphanedTransaction(message);
+
+ break;
+ }
+
+ case rmq::TelemetryCommand::kPrintThreadStackTraceCommand: {
+ TelemetryCommand response;
+ response.mutable_thread_stack_trace()->set_nonce(read_.print_thread_stack_trace_command().nonce());
+ response.mutable_thread_stack_trace()->set_thread_stack_trace("PrintStackTrace is not supported");
+ {
+ absl::MutexLock lk(&writes_mtx_);
+ writes_.push_back(response);
+ }
+ fireWrite();
+ StartRead(&read_);
+ break;
+ }
+
+ case rmq::TelemetryCommand::kVerifyMessageCommand: {
+ auto client = client_.lock();
+ if (!client) {
+ fireClose();
+ return;
+ }
+
+ std::weak_ptr<TelemetryBidiReactor> ptr(shared_from_this());
+ auto cb = [ptr](TelemetryCommand command) {
+ auto reactor = ptr.lock();
+ if (!reactor) {
+ return;
+ }
+ reactor->onVerifyMessageResult(std::move(command));
+ };
+ auto message = client->manager()->wrapMessage(read_.verify_message_command().message());
+ auto raw = const_cast<Message*>(message.get());
+ raw->mutableExtension().target_endpoint = peer_address_;
+ raw->mutableExtension().nonce = read_.verify_message_command().nonce();
+ client->verify(message, cb);
+ StartRead(&read_);
+ break;
+ }
+
+ default: {
+ SPDLOG_WARN("Unsupported command");
+ break;
+ }
+ }
+}
+
+void TelemetryBidiReactor::applySettings(const rmq::Settings& settings) {
+ auto ptr = client_.lock();
+ if (!ptr) {
+ SPDLOG_INFO("Client for {} has destructed", peer_address_);
+ return;
+ }
+
+ applyBackoffPolicy(settings, ptr);
+
+ switch (settings.pub_sub_case()) {
+ case rmq::Settings::PubSubCase::kPublishing: {
+ applyPublishingConfig(settings, ptr);
+ break;
+ }
+ case rmq::Settings::PubSubCase::kSubscription: {
+ applySubscriptionConfig(settings, ptr);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void TelemetryBidiReactor::applyBackoffPolicy(const rmq::Settings& settings, std::shared_ptr<Client>& ptr) {
+ // Apply backoff policy on throttling
+ if (settings.has_backoff_policy()) {
+ const auto& backoff_policy = settings.backoff_policy();
+ ptr->config().backoff_policy.max_attempt = backoff_policy.max_attempts();
+ if (backoff_policy.has_customized_backoff()) {
+ for (const auto& item : backoff_policy.customized_backoff().next()) {
+ auto backoff = std::chrono::seconds(item.seconds()) + std::chrono::nanoseconds(item.nanos());
+ ptr->config().backoff_policy.next.push_back(absl::FromChrono(backoff));
+ }
+ }
+
+ if (backoff_policy.has_exponential_backoff()) {
+ const auto& exp_backoff = backoff_policy.exponential_backoff();
+ ptr->config().backoff_policy.initial = absl::FromChrono(std::chrono::seconds(exp_backoff.initial().seconds()) +
+ std::chrono::nanoseconds(exp_backoff.initial().nanos()));
+ ptr->config().backoff_policy.multiplier = exp_backoff.multiplier();
+ ptr->config().backoff_policy.max = absl::FromChrono(std::chrono::seconds(exp_backoff.max().seconds()) +
+ std::chrono::nanoseconds(exp_backoff.max().nanos()));
+ }
+ }
+}
+
+void TelemetryBidiReactor::applyPublishingConfig(const rmq::Settings& settings, std::shared_ptr<Client> client) {
+ client->config().publisher.max_body_size = settings.publishing().max_body_size();
+ client->config().publisher.compress_body_threshold = settings.publishing().compress_body_threshold();
+}
+
+void TelemetryBidiReactor::applySubscriptionConfig(const rmq::Settings& settings, std::shared_ptr<Client> client) {
+ client->config().subscriber.fifo = settings.subscription().fifo();
+ auto polling_timeout =
+ google::protobuf::util::TimeUtil::DurationToMilliseconds(settings.subscription().long_polling_timeout());
+ client->config().subscriber.polling_timeout = absl::Milliseconds(polling_timeout);
+ client->config().subscriber.receive_batch_size = settings.subscription().receive_batch_size();
+}
+
+void TelemetryBidiReactor::fireRead() {
+ SPDLOG_DEBUG("{}#fireRead", peer_address_);
+ StartRead(&read_);
+}
+
+void TelemetryBidiReactor::write(TelemetryCommand command) {
+ {
+ absl::MutexLock lk(&writes_mtx_);
+ writes_.push_back(command);
+ }
+ fireWrite();
+}
+
+void TelemetryBidiReactor::fireWrite() {
+ SPDLOG_DEBUG("{}#fireWrite", peer_address_);
+ {
+ absl::MutexLock lk(&writes_mtx_);
+ if (writes_.empty()) {
+ SPDLOG_DEBUG("No TelemtryCommand to write. Peer={}", peer_address_);
+ return;
+ }
+
+ bool expect = false;
+ if (command_inflight_.compare_exchange_strong(expect, true, std::memory_order_relaxed)) {
+ write_ = std::move(*writes_.begin());
+ writes_.erase(writes_.begin());
+ } else {
+ SPDLOG_DEBUG("Another command is already on the wire. Peer={}", peer_address_);
+ return;
+ }
+ }
+ SPDLOG_DEBUG("Writing telemetry command to {}: {}", peer_address_, write_.DebugString());
+ StartWrite(&write_);
+}
+
+void TelemetryBidiReactor::fireClose() {
+ SPDLOG_INFO("{}#fireClose", peer_address_);
+ if (StreamState::Active == stream_state_) {
+ StartWritesDone();
+ {
+ absl::MutexLock lk(&stream_state_mtx_);
+ if (StreamState::Active == stream_state_) {
+ stream_state_cv_.Wait(&stream_state_mtx_);
+ }
+ }
+ }
+}
+
+void TelemetryBidiReactor::OnWritesDoneDone(bool ok) {
+ SPDLOG_DEBUG("{}#OnWritesDoneDone", peer_address_);
+}
+
+void TelemetryBidiReactor::onVerifyMessageResult(TelemetryCommand command) {
+ {
+ absl::MutexLock lk(&writes_mtx_);
+ writes_.emplace_back(command);
+ }
+ fireWrite();
+}
+
+/// Notifies the application that all operations associated with this RPC
+/// have completed and all Holds have been removed. OnDone provides the RPC
+/// status outcome for both successful and failed RPCs and will be called in
+/// all cases. If it is not called, it indicates an application-level problem
+/// (like failure to remove a hold).
+///
+/// \param[in] status The status outcome of this RPC
+void TelemetryBidiReactor::OnDone(const grpc::Status& status) {
+ SPDLOG_DEBUG("{}#OnDone, status.ok={}", peer_address_, status.ok());
+ if (!status.ok()) {
+ SPDLOG_WARN("{}#OnDone, status.error_code={}, status.error_message={}, status.error_details={}", peer_address_,
+ status.error_code(), status.error_message(), status.error_details());
+ }
+
+ {
+ SPDLOG_DEBUG("{} notifies awaiting close call", peer_address_);
+ absl::MutexLock lk(&stream_state_mtx_);
+ stream_state_ = StreamState::Closed;
+ stream_state_cv_.SignalAll();
+ }
+
+ auto client = client_.lock();
+ if (!client) {
+ return;
+ }
+
+ if (client->active()) {
+ client->createSession(peer_address_, true);
+ }
+}
+
+ROCKETMQ_NAMESPACE_END
\ No newline at end of file
diff --git a/src/main/cpp/client/TlsHelper.cpp b/src/main/cpp/client/TlsHelper.cpp
index 62d3ac1..aa4970a 100644
--- a/src/main/cpp/client/TlsHelper.cpp
+++ b/src/main/cpp/client/TlsHelper.cpp
@@ -16,10 +16,11 @@
*/
#include "TlsHelper.h"
+#include <memory>
+
#include "MixAll.h"
#include "OpenSSLCompatible.h"
-#include <memory>
-#include <openssl/hmac.h>
+#include "openssl/hmac.h"
ROCKETMQ_NAMESPACE_BEGIN
@@ -37,213 +38,4 @@ std::string TlsHelper::sign(const std::string& access_secret, const std::string&
return hex_str;
}
-const char* TlsHelper::CA = R"(
------BEGIN CERTIFICATE-----
-MIIGCDCCA/CgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZwxCzAJBgNVBAYTAkNO
-MRIwEAYDVQQIDAlaaGUgSmlhbmcxEjAQBgNVBAcMCUhhbmcgWmhvdTEPMA0GA1UE
-CgwGQXBhY2hlMREwDwYDVQQLDAhSb2NrZXRNUTEcMBoGA1UEAwwTcm9ja2V0bXEu
-YXBhY2hlLm9yZzEjMCEGCSqGSIb3DQEJARYUbGl6aGFuaHVpQGFwYWNoZS5vcmcw
-HhcNMjEwNDI1MDkwMjE5WhcNMzEwNDIzMDkwMjE5WjCBiDELMAkGA1UEBhMCQ04x
-EjAQBgNVBAgMCVpoZSBKaWFuZzEPMA0GA1UECgwGQXBhY2hlMREwDwYDVQQLDAhS
-b2NrZXRNUTEcMBoGA1UEAwwTcm9ja2V0bXEuYXBhY2hlLm9yZzEjMCEGCSqGSIb3
-DQEJARYUbGl6aGFuaHVpQGFwYWNoZS5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4IC
-DwAwggIKAoICAQDLL1rQ3A6YnWwdAT3rcf7wXK2DN6AwkWfGexp5o8y+dPj49D5b
-PhEVIDEjidtWASFfCunJq9Ku48K/U8tha58JPL2CJ3773Mw7CU3LwD46Ft32+kGM
-3+rXuXi44Fs714U/jJkxA6AsJdl4VtgjfXGWhbTq7ZT//l3tECH7Q096cp4xXATx
-0RuvlaE33k8SpOPB+oHyjdFTwSW9HuZx71dLNCoZ0b52teJDVJFMACz6R5t3ZglF
-MUosUzEUKdCXqBDvjOzMI2GHr7NYKAWHnOPNcYbf8jKzQ5msW+1MOfacVX+YUmKr
-4Tf8NZHTSA4MuSNZ46gVFK7tYau2FDAkBWSb4hnuqqoGn58QtwrRBWtCmnLc4133
-6sgEGoJJR5M7WF0usl7KAgqgwy6xdU1joHO4SzvpysQ9kHWr1hcTqpeLD/svxLpZ
-3x0WrhIAQoyd4uIHv/501LgD2KE5YnBa4S10LYrZeQpoJO5YV56HJdyvqNgVh2fn
-tIRJAKq/1Wvw6izK/zOC6ZC+ug3n9vPqCgpBI0NFm3aR4AcSx70FsmlfrjUAsluL
-kIzQwuu3Ip7hUS9kBVUxmvaD2yy2HPc+UPiYm4Y2YxqTx2j11APbN32M8rj1mroE
... 17469 lines suppressed ...