├── .asf.yaml
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── LICENSE
├── NOTICE
├── README.md
├── examples
├── Program.cs
└── examples.csproj
├── rocketmq-client-csharp
├── AccessPoint.cs
├── Client.cs
├── ClientConfig.cs
├── ClientLoggerInterceptor.cs
├── ClientManager.cs
├── ClientManagerFactory.cs
├── ConfigFileCredentialsProvider.cs
├── Credentials.cs
├── ExpressionType.cs
├── FilterExpression.cs
├── IClient.cs
├── IClientConfig.cs
├── IClientManager.cs
├── IConsumer.cs
├── ICredentialsProvider.cs
├── IMessageListener.cs
├── IProducer.cs
├── IRpcClient.cs
├── Message.cs
├── MessageException.cs
├── MessageIdGenerator.cs
├── MessageType.cs
├── MetadataConstants.cs
├── MqLogManager.cs
├── ProcessQueue.cs
├── Producer.cs
├── Protos
│ ├── apache
│ │ └── rocketmq
│ │ │ └── v2
│ │ │ ├── admin.proto
│ │ │ ├── definition.proto
│ │ │ └── service.proto
│ └── google
│ │ └── rpc
│ │ ├── code.proto
│ │ ├── error_details.proto
│ │ └── status.proto
├── PublishLoadBalancer.cs
├── Publishing.cs
├── PushConsumer.cs
├── RpcClient.cs
├── SendReceipt.cs
├── SendStatus.cs
├── SequenceGenerator.cs
├── Session.cs
├── Signature.cs
├── SimpleConsumer.cs
├── StaticCredentialsProvider.cs
├── Topic.cs
├── TopicRouteData.cs
├── TopicRouteException.cs
├── Utilities.cs
├── rocketmq-client-csharp.csproj
└── rocketmq-client-csharp.nlog
├── rocketmq-client.sln
└── tests
├── ClientConfigTest.cs
├── ClientManagerTest.cs
├── ConfigFileCredentialsProviderTest.cs
├── DateTimeTest.cs
├── MessageIdGeneratorTest.cs
├── MessageTest.cs
├── MqLogManagerTest.cs
├── ProducerTest.cs
├── PushConsumerTest.cs
├── RpcClientTest.cs
├── SendResultTest.cs
├── SequenceGeneratorTest.cs
├── SignatureTest.cs
├── SimpleConsumerTest.cs
├── StaticCredentialsProviderTest.cs
├── TopicTest.cs
├── UnitTest1.cs
└── tests.csproj
/.asf.yaml:
--------------------------------------------------------------------------------
1 | github:
2 | features:
3 | # Enable wiki for documentation
4 | wiki: true
5 | # Enable issue management
6 | issues: true
7 | # Enable projects for project management boards
8 | projects: true
9 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push, pull_request]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Checkout
8 | uses: actions/checkout@v2
9 | - name: Setup dotnet
10 | uses: actions/setup-dotnet@v1
11 | with:
12 | dotnet-version: |
13 | 5.0.x
14 | 6.0.x
15 | - name: Build artifacts
16 | run: |
17 | dotnet --version
18 | dotnet build
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | .vscode/
4 | .idea
5 | *.user
6 | *DS_Store
7 | .fake
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (properties) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Apache RocketMQ
2 | Copyright 2016-2017 The Apache Software Foundation
3 |
4 | This product includes software developed at
5 | The Apache Software Foundation (http://www.apache.org/).
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/lizhanhui/rocketmq-client-csharp/actions/workflows/main.yml)
2 |
3 | Introduction
4 | --------------
5 | Project rocketmq-client-csharp is targeted to implement C# binding in native C# code. At the current moment, it is still a work-in-progress project. Do not use it in production till it grows mature enough.
6 |
7 | Architecture
8 | --------------
9 | Basically, this project would follow the same paradigm of [rocketmq-client-cpp v5.0.0](https://github.com/apache/rocketmq-client-cpp/tree/main). Namely, we would build the whole client following protocols described in [rocketmq-apis](https://github.com/apache/rocketmq-apis) on top of [gRPC-dotnet](https://github.com/grpc/grpc-dotnet), utilizing [Protocol buffers](https://developers.google.com/protocol-buffers) to serialize and deserialize data in transmission.
10 |
11 |
12 | How to build
13 | -----------------
14 | Layout of this project roughly follows [this guide](https://docs.microsoft.com/en-us/dotnet/core/tutorials/library-with-visual-studio-code?pivots=dotnet-5-0). The solution contains a class library, a unit test module and an example console module.
15 |
16 | 1. Install dotnet tool chains following instructions [here](https://dotnet.microsoft.com/en-us/download);
17 | 2. Visual Studio Code with official C# plugin is used during development;
18 |
19 | Assuming you are at the home of this repository,
20 | #### Build
21 |
22 | ```sh
23 | dotnet build
24 | ```
25 |
26 | #### Run Unit Tests
27 | ```sh
28 | dotnet test -l "console;verbosity=detailed"
29 | ```
30 |
31 | #### Run Examples
32 | ```sh
33 | dotnet run -p examples
34 | ```
35 |
36 | License
37 | ------------------
38 | This project follows [Apache License Version 2.0](./LICENSE).
39 |
40 | How to contribute
41 | ------------------
42 | Similar to other Apache RocketMQ projects, we welcome contributions in various ways, from filing a bug report, correcting type error, document writing to complete feature implementation. Any attempt to make this project better is welcome.
43 |
44 | If this project catches your attention, do not hesitate to make a pull request.
--------------------------------------------------------------------------------
/examples/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using System.Threading;
4 |
5 | namespace examples
6 | {
7 |
8 | class Foo
9 | {
10 | public int bar = 1;
11 | }
12 | class Program
13 | {
14 |
15 | static void RT(Action action, int seconds, CancellationToken token)
16 | {
17 | if (null == action)
18 | {
19 | return;
20 | }
21 |
22 | Task.Run(async () =>
23 | {
24 | while (!token.IsCancellationRequested)
25 | {
26 | action();
27 | await Task.Delay(TimeSpan.FromSeconds(seconds), token);
28 | }
29 | });
30 | }
31 |
32 | static void Main(string[] args)
33 | {
34 | Console.WriteLine("Hello World!");
35 |
36 | string accessKey = "key";
37 | string accessSecret = "secret";
38 | var credentials = new Org.Apache.Rocketmq.StaticCredentialsProvider(accessKey, accessSecret).getCredentials();
39 | bool expired = credentials.expired();
40 |
41 | int workerThreads;
42 | int completionPortThreads;
43 | ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
44 | Console.WriteLine($"Max: workerThread={workerThreads}, completionPortThreads={completionPortThreads}");
45 | ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
46 | Console.WriteLine($"Min: workerThread={workerThreads}, completionPortThreads={completionPortThreads}");
47 |
48 | ThreadPool.QueueUserWorkItem((Object stateInfo) =>
49 | {
50 | Console.WriteLine("From ThreadPool");
51 | if (stateInfo is Foo)
52 | {
53 | Console.WriteLine("Foo: bar=" + (stateInfo as Foo).bar);
54 | }
55 | }, new Foo());
56 |
57 | var cts = new CancellationTokenSource();
58 | RT(() =>
59 | {
60 | Console.WriteLine("Hello Again" + Thread.CurrentThread.Name);
61 | }, 1, cts.Token);
62 | cts.CancelAfter(3000);
63 | Console.ReadKey();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/examples/examples.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Exe
9 | net5.0
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/AccessPoint.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | namespace Org.Apache.Rocketmq
18 | {
19 | public class AccessPoint
20 | {
21 | private string _host;
22 |
23 | public string Host
24 | {
25 | get { return _host; }
26 | set { _host = value; }
27 | }
28 |
29 | private int _port;
30 |
31 | public int Port
32 | {
33 | get { return _port; }
34 | set { _port = value; }
35 | }
36 |
37 | public string TargetUrl()
38 | {
39 | return $"https://{_host}:{_port}";
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ClientConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using System.Collections.Generic;
19 | using rmq = Apache.Rocketmq.V2;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 |
24 | public class ClientConfig : IClientConfig
25 | {
26 |
27 | public ClientConfig()
28 | {
29 | var hostName = System.Net.Dns.GetHostName();
30 | var pid = System.Diagnostics.Process.GetCurrentProcess().Id;
31 | this.clientId_ = string.Format("{0}@{1}#{2}", hostName, pid, instanceName_);
32 | this._requestTimeout = TimeSpan.FromSeconds(3);
33 | this.longPollingIoTimeout_ = TimeSpan.FromSeconds(30);
34 | this.client_type_ = rmq::ClientType.Unspecified;
35 | this.access_point_ = new rmq::Endpoints();
36 | this.back_off_policy_ = new rmq::RetryPolicy();
37 | this._publishing = new Publishing();
38 | }
39 |
40 | public string region()
41 | {
42 | return _region;
43 | }
44 | public string Region
45 | {
46 | set { _region = value; }
47 | }
48 |
49 | public string serviceName()
50 | {
51 | return _serviceName;
52 | }
53 | public string ServiceName
54 | {
55 | set { _serviceName = value; }
56 | }
57 |
58 | public string resourceNamespace()
59 | {
60 | return _resourceNamespace;
61 | }
62 | public string ResourceNamespace
63 | {
64 | get { return _resourceNamespace; }
65 | set { _resourceNamespace = value; }
66 | }
67 |
68 | public ICredentialsProvider credentialsProvider()
69 | {
70 | return credentialsProvider_;
71 | }
72 |
73 | public ICredentialsProvider CredentialsProvider
74 | {
75 | set { credentialsProvider_ = value; }
76 | }
77 |
78 | public string tenantId()
79 | {
80 | return _tenantId;
81 | }
82 | public string TenantId
83 | {
84 | set { _tenantId = value; }
85 | }
86 |
87 | public TimeSpan RequestTimeout
88 | {
89 | get
90 | {
91 | return _requestTimeout;
92 | }
93 | set
94 | {
95 | _requestTimeout = value;
96 | }
97 | }
98 |
99 | public TimeSpan getLongPollingTimeout()
100 | {
101 | return longPollingIoTimeout_;
102 | }
103 | public TimeSpan LongPollingTimeout
104 | {
105 | set { longPollingIoTimeout_ = value; }
106 | }
107 |
108 | public string getGroupName()
109 | {
110 | return groupName_;
111 | }
112 | public string GroupName
113 | {
114 | set { groupName_ = value; }
115 | }
116 |
117 | public string clientId()
118 | {
119 | return clientId_;
120 | }
121 |
122 | public bool isTracingEnabled()
123 | {
124 | return tracingEnabled_;
125 | }
126 | public bool TracingEnabled
127 | {
128 | set { tracingEnabled_ = value; }
129 | }
130 |
131 | public void setInstanceName(string instanceName)
132 | {
133 | this.instanceName_ = instanceName;
134 | }
135 |
136 | private string _region = "cn-hangzhou";
137 | private string _serviceName = "ONS";
138 |
139 | protected string _resourceNamespace;
140 |
141 | private ICredentialsProvider credentialsProvider_;
142 |
143 | private string _tenantId;
144 |
145 | private TimeSpan _requestTimeout;
146 |
147 | private TimeSpan longPollingIoTimeout_;
148 |
149 | private string groupName_;
150 |
151 | private string clientId_;
152 |
153 | private bool tracingEnabled_ = false;
154 |
155 | private string instanceName_ = "default";
156 |
157 | private rmq::ClientType client_type_;
158 | public rmq::ClientType ClientType
159 | {
160 | get { return client_type_; }
161 | set { client_type_ = value; }
162 | }
163 |
164 |
165 | private rmq::Endpoints access_point_;
166 |
167 | public rmq::AddressScheme AccessPointScheme
168 | {
169 | get { return access_point_.Scheme; }
170 | set { access_point_.Scheme = value; }
171 | }
172 |
173 | public List AccessPointEndpoints
174 | {
175 | get
176 | {
177 | List addresses = new List();
178 | foreach (var item in access_point_.Addresses)
179 | {
180 | addresses.Add(item);
181 | }
182 | return addresses;
183 | }
184 |
185 | set
186 | {
187 | access_point_.Addresses.Clear();
188 | foreach (var item in value)
189 | {
190 | access_point_.Addresses.Add(item);
191 | }
192 | }
193 | }
194 |
195 | private rmq::RetryPolicy back_off_policy_;
196 |
197 | private Publishing _publishing;
198 | public Publishing Publishing
199 | {
200 | get { return _publishing; }
201 | }
202 |
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ClientLoggerInterceptor.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using System.Threading.Tasks;
19 | using Grpc.Core;
20 | using Grpc.Core.Interceptors;
21 | using NLog;
22 |
23 | namespace Org.Apache.Rocketmq
24 | {
25 | public class ClientLoggerInterceptor : Interceptor
26 | {
27 |
28 | private static readonly Logger Logger = MqLogManager.Instance.GetCurrentClassLogger();
29 |
30 | public override TResponse BlockingUnaryCall(
31 | TRequest request,
32 | ClientInterceptorContext context,
33 | BlockingUnaryCallContinuation continuation)
34 | {
35 | LogCall(context.Method);
36 | AddCallerMetadata(ref context);
37 |
38 | return continuation(request, context);
39 | }
40 |
41 | public override AsyncUnaryCall AsyncUnaryCall(
42 | TRequest request,
43 | ClientInterceptorContext context,
44 | AsyncUnaryCallContinuation continuation)
45 | {
46 | LogCall(context.Method);
47 | AddCallerMetadata(ref context);
48 |
49 | var call = continuation(request, context);
50 |
51 | return new AsyncUnaryCall(HandleResponse(call.ResponseAsync), call.ResponseHeadersAsync, call.GetStatus, call.GetTrailers, call.Dispose);
52 | }
53 |
54 | private async Task HandleResponse(Task t)
55 | {
56 | try
57 | {
58 | var response = await t;
59 | Logger.Debug($"Response received: {response}");
60 | return response;
61 | }
62 | catch (Exception ex)
63 | {
64 | Logger.Error($"Call error: {ex.Message}");
65 | throw;
66 | }
67 | }
68 |
69 | public override AsyncClientStreamingCall AsyncClientStreamingCall(
70 | ClientInterceptorContext context,
71 | AsyncClientStreamingCallContinuation continuation)
72 | {
73 | LogCall(context.Method);
74 | AddCallerMetadata(ref context);
75 |
76 | return continuation(context);
77 | }
78 |
79 | public override AsyncServerStreamingCall AsyncServerStreamingCall(
80 | TRequest request,
81 | ClientInterceptorContext context,
82 | AsyncServerStreamingCallContinuation continuation)
83 | {
84 | LogCall(context.Method);
85 | AddCallerMetadata(ref context);
86 |
87 | return continuation(request, context);
88 | }
89 |
90 | public override AsyncDuplexStreamingCall AsyncDuplexStreamingCall(
91 | ClientInterceptorContext context,
92 | AsyncDuplexStreamingCallContinuation continuation)
93 | {
94 | LogCall(context.Method);
95 | AddCallerMetadata(ref context);
96 |
97 | return continuation(context);
98 | }
99 |
100 | private void LogCall(Method method)
101 | where TRequest : class
102 | where TResponse : class
103 | {
104 | Logger.Debug($"Starting call. Type: {method.Type}. Request: {typeof(TRequest)}. Response: {typeof(TResponse)}");
105 | }
106 |
107 | private void AddCallerMetadata(ref ClientInterceptorContext context)
108 | where TRequest : class
109 | where TResponse : class
110 | {
111 | var headers = context.Options.Headers;
112 |
113 | // Call doesn't have a headers collection to add to.
114 | // Need to create a new context with headers for the call.
115 | if (headers == null)
116 | {
117 | headers = new Metadata();
118 | var options = context.Options.WithHeaders(headers);
119 | context = new ClientInterceptorContext(context.Method, context.Host, options);
120 | }
121 |
122 | // Add caller metadata to call headers
123 | headers.Add("caller-user", Environment.UserName);
124 | headers.Add("caller-machine", Environment.MachineName);
125 | headers.Add("caller-os", Environment.OSVersion.ToString());
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ClientManagerFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using System.Collections.Generic;
19 | using System.Collections.Concurrent;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 | public sealed class ClientManagerFactory
24 | {
25 | public static IClientManager getClientManager(string resourceNamespace)
26 | {
27 | if (clientManagers.ContainsKey(resourceNamespace))
28 | {
29 | return clientManagers[resourceNamespace];
30 | }
31 |
32 | var clientManager = new ClientManager();
33 | // TODO: configure client managers.
34 | if (clientManagers.TryAdd(resourceNamespace, clientManager))
35 | {
36 | return clientManager;
37 | }
38 |
39 | return clientManagers[resourceNamespace];
40 | }
41 |
42 | private static ConcurrentDictionary clientManagers = new ConcurrentDictionary();
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ConfigFileCredentialsProvider.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System.IO;
18 | using System;
19 | using System.Text.Json;
20 | using System.Collections.Generic;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 |
25 | /**
26 | * File-based credentials provider that reads JSON configurations from ${HOME}/.rocketmq/config
27 | * A sample config content is as follows:
28 | * {"AccessKey": "key", "AccessSecret": "secret"}
29 | */
30 | public class ConfigFileCredentialsProvider : ICredentialsProvider
31 | {
32 |
33 | public ConfigFileCredentialsProvider()
34 | {
35 | var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
36 | string configFileRelativePath = "/.rocketmq/config";
37 | if (!File.Exists(home + configFileRelativePath))
38 | {
39 | return;
40 | }
41 |
42 | try
43 | {
44 | using (var reader = new StreamReader(home + configFileRelativePath))
45 | {
46 | string json = reader.ReadToEnd();
47 | var kv = JsonSerializer.Deserialize>(json);
48 | accessKey = kv["AccessKey"];
49 | accessSecret = kv["AccessSecret"];
50 | valid = true;
51 | }
52 | }
53 | catch (IOException)
54 | {
55 | }
56 | }
57 |
58 | public Credentials getCredentials()
59 | {
60 | if (!valid)
61 | {
62 | return null;
63 | }
64 |
65 | return new Credentials(accessKey, accessSecret);
66 | }
67 |
68 | private string accessKey;
69 | private string accessSecret;
70 |
71 | private bool valid = false;
72 | }
73 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Credentials.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | public class Credentials
23 | {
24 |
25 | public Credentials(string accessKey, string accessSecret)
26 | {
27 | this.accessKey = accessKey;
28 | this.accessSecret = accessSecret;
29 | }
30 |
31 | public Credentials(string accessKey, string accessSecret, string sessionToken, DateTime expirationInstant)
32 | {
33 | this.accessKey = accessKey;
34 | this.accessSecret = accessSecret;
35 | this.sessionToken = sessionToken;
36 | this.expirationInstant = expirationInstant;
37 | }
38 |
39 | public bool empty()
40 | {
41 | return String.IsNullOrEmpty(accessKey) || String.IsNullOrEmpty(accessSecret);
42 | }
43 |
44 | public bool expired()
45 | {
46 | if (DateTime.MinValue == expirationInstant)
47 | {
48 | return false;
49 | }
50 |
51 | return DateTime.Now > expirationInstant;
52 | }
53 |
54 | private string accessKey;
55 | public string AccessKey
56 | {
57 | get { return accessKey; }
58 | }
59 |
60 | private string accessSecret;
61 | public string AccessSecret
62 | {
63 | get { return accessSecret; }
64 | }
65 |
66 | private string sessionToken;
67 | public string SessionToken
68 | {
69 | get { return sessionToken; }
70 | }
71 |
72 | private DateTime expirationInstant = DateTime.MinValue;
73 |
74 | }
75 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ExpressionType.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | namespace Org.Apache.Rocketmq
18 | {
19 |
20 | public enum ExpressionType
21 | {
22 | TAG,
23 | SQL92,
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/FilterExpression.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | namespace Org.Apache.Rocketmq
19 | {
20 | public class FilterExpression
21 | {
22 | public FilterExpression(string expression, ExpressionType type)
23 | {
24 | Expression = expression;
25 | Type = type;
26 | }
27 |
28 | public ExpressionType Type { get; }
29 | public string Expression { get; }
30 | }
31 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IClient.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Threading.Tasks;
19 | using System.Threading;
20 | using System;
21 | using rmq = Apache.Rocketmq.V2;
22 |
23 | namespace Org.Apache.Rocketmq
24 | {
25 | public interface IClient : IClientConfig
26 | {
27 |
28 | Task Heartbeat();
29 |
30 | Task NotifyClientTermination();
31 |
32 | void BuildClientSetting(rmq::Settings settings);
33 |
34 |
35 | void OnSettingsReceived(rmq::Settings settings);
36 |
37 | CancellationTokenSource TelemetryCts();
38 | }
39 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IClientConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 |
19 | namespace Org.Apache.Rocketmq
20 | {
21 | public interface IClientConfig
22 | {
23 | string region();
24 |
25 | string serviceName();
26 |
27 | string resourceNamespace();
28 |
29 | ICredentialsProvider credentialsProvider();
30 |
31 | string tenantId();
32 |
33 | TimeSpan getLongPollingTimeout();
34 |
35 | string getGroupName();
36 |
37 | string clientId();
38 |
39 | bool isTracingEnabled();
40 | }
41 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IClientManager.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Threading.Tasks;
19 | using System;
20 | using System.Collections.Generic;
21 | using grpc = global::Grpc.Core;
22 | using rmq = Apache.Rocketmq.V2;
23 |
24 |
25 | namespace Org.Apache.Rocketmq
26 | {
27 | public interface IClientManager
28 | {
29 | IRpcClient GetRpcClient(string target);
30 |
31 | grpc::AsyncDuplexStreamingCall Telemetry(string target, grpc::Metadata metadata);
32 |
33 | Task ResolveRoute(string target, grpc::Metadata metadata, rmq::QueryRouteRequest request, TimeSpan timeout);
34 |
35 | Task Heartbeat(string target, grpc::Metadata metadata, rmq::HeartbeatRequest request, TimeSpan timeout);
36 |
37 | Task NotifyClientTermination(string target, grpc::Metadata metadata, rmq::NotifyClientTerminationRequest request, TimeSpan timeout);
38 |
39 | Task SendMessage(string target, grpc::Metadata metadata, rmq::SendMessageRequest request, TimeSpan timeout);
40 |
41 | Task> QueryLoadAssignment(string target, grpc::Metadata metadata, rmq::QueryAssignmentRequest request, TimeSpan timeout);
42 |
43 | Task> ReceiveMessage(string target, grpc::Metadata metadata, rmq::ReceiveMessageRequest request, TimeSpan timeout);
44 |
45 | Task Ack(string target, grpc::Metadata metadata, rmq::AckMessageRequest request, TimeSpan timeout);
46 |
47 | Task ChangeInvisibleDuration(string target, grpc::Metadata metadata, rmq::ChangeInvisibleDurationRequest request, TimeSpan timeout);
48 |
49 | Task Shutdown();
50 | }
51 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IConsumer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Threading.Tasks;
19 | namespace Org.Apache.Rocketmq
20 | {
21 | public interface IConsumer
22 | {
23 | Task Start();
24 |
25 | Task Shutdown();
26 | }
27 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ICredentialsProvider.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | namespace Org.Apache.Rocketmq
18 | {
19 | public interface ICredentialsProvider
20 | {
21 | Credentials getCredentials();
22 | }
23 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IMessageListener.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Collections.Generic;
19 | using System.Threading.Tasks;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 |
24 | public interface IMessageListener
25 | {
26 | Task Consume(List messages, List failed);
27 |
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IProducer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Threading.Tasks;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | public interface IProducer
23 | {
24 | Task Start();
25 |
26 | Task Shutdown();
27 |
28 | Task Send(Message message);
29 | }
30 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/IRpcClient.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Threading.Tasks;
21 | using Apache.Rocketmq.V2;
22 | using Grpc.Core;
23 |
24 | namespace Org.Apache.Rocketmq
25 | {
26 | public interface IRpcClient
27 | {
28 | AsyncDuplexStreamingCall Telemetry(Metadata metadata);
29 |
30 | Task QueryRoute(Metadata metadata, QueryRouteRequest request, TimeSpan timeout);
31 |
32 | Task Heartbeat(Metadata metadata, HeartbeatRequest request, TimeSpan timeout);
33 |
34 | Task SendMessage(Metadata metadata, SendMessageRequest request, TimeSpan timeout);
35 |
36 | Task QueryAssignment(Metadata metadata, QueryAssignmentRequest request,
37 | TimeSpan timeout);
38 |
39 | Task> ReceiveMessage(Metadata metadata, ReceiveMessageRequest request, TimeSpan timeout);
40 |
41 | Task AckMessage(Metadata metadata, AckMessageRequest request, TimeSpan timeout);
42 |
43 | Task ChangeInvisibleDuration(Metadata metadata, ChangeInvisibleDurationRequest request, TimeSpan timeout);
44 |
45 | Task ForwardMessageToDeadLetterQueue(Metadata metadata,
46 | ForwardMessageToDeadLetterQueueRequest request, TimeSpan timeout);
47 |
48 | Task EndTransaction(Metadata metadata, EndTransactionRequest request, TimeSpan timeout);
49 |
50 |
51 | Task NotifyClientTermination(Metadata metadata,
52 | NotifyClientTerminationRequest request, TimeSpan timeout);
53 |
54 | Task Shutdown();
55 | }
56 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Message.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Collections.Generic;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 |
24 | public class Message
25 | {
26 | public Message() : this(null, null)
27 | {
28 | }
29 |
30 | public Message(string topic, byte[] body) : this(topic, null, new List(), body) { }
31 |
32 | public Message(string topic, string tag, byte[] body) : this(topic, tag, new List(), body)
33 | {
34 | }
35 |
36 | public Message(string topic, string tag, List keys, byte[] body)
37 | {
38 | MessageId = SequenceGenerator.Instance.Next();
39 | MaxAttemptTimes = 3;
40 | Topic = topic;
41 | Tag = tag;
42 | Keys = keys;
43 | Body = body;
44 | UserProperties = new Dictionary();
45 | DeliveryTimestamp = DateTime.MinValue;
46 | }
47 |
48 | public string MessageId
49 | {
50 | get;
51 | internal set;
52 | }
53 |
54 | public string Topic
55 | {
56 | get;
57 | set;
58 | }
59 |
60 | public byte[] Body
61 | {
62 | get;
63 | set;
64 | }
65 |
66 | public string Tag
67 | {
68 | get;
69 | set;
70 | }
71 |
72 | public List Keys
73 | {
74 | get;
75 | set;
76 | }
77 |
78 | public Dictionary UserProperties
79 | {
80 | get;
81 | set;
82 | }
83 |
84 | public int MaxAttemptTimes
85 | {
86 | get;
87 | set;
88 | }
89 |
90 |
91 | public DateTime DeliveryTimestamp
92 | {
93 | get;
94 | set;
95 | }
96 |
97 | public int DeliveryAttempt
98 | {
99 | get;
100 | internal set;
101 | }
102 |
103 | public string MessageGroup
104 | {
105 | get;
106 | set;
107 | }
108 |
109 | public bool Fifo()
110 | {
111 | return !String.IsNullOrEmpty(MessageGroup);
112 | }
113 |
114 | public bool Scheduled()
115 | {
116 | return DeliveryTimestamp > DateTime.UtcNow;
117 | }
118 |
119 | internal bool _checksumVerifiedOk = true;
120 | internal string _receiptHandle;
121 | internal string _sourceHost;
122 | }
123 |
124 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/MessageException.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | [Serializable]
23 | public class MessageException : Exception
24 | {
25 | public MessageException(string message) : base(message)
26 | {
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/MessageIdGenerator.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Diagnostics;
20 | using System.IO;
21 | using System.Threading;
22 |
23 | namespace Org.Apache.Rocketmq
24 | {
25 | /**
26 | * MessageId generate rules refer: https://yuque.antfin-inc.com/aone709911/ca1edg/af2t6o
27 | */
28 | public class MessageIdGenerator
29 | {
30 | public static readonly string version = "01";
31 | private static readonly MessageIdGenerator Instance = new();
32 |
33 | private readonly string _prefix;
34 |
35 | private readonly long _secondsSinceCustomEpoch;
36 | private readonly Stopwatch _stopwatch;
37 |
38 | private int _sequence;
39 |
40 | private MessageIdGenerator()
41 | {
42 | MemoryStream stream = new MemoryStream();
43 | BinaryWriter writer = new BinaryWriter(stream);
44 |
45 | var macAddress = Utilities.GetMacAddress();
46 | writer.Write(macAddress, 0, 6);
47 |
48 | int processId = Utilities.GetProcessId();
49 |
50 | byte[] processIdBytes = BitConverter.GetBytes(processId);
51 | if (BitConverter.IsLittleEndian)
52 | {
53 | Array.Reverse(processIdBytes);
54 | }
55 |
56 | writer.Write(processIdBytes, 2, 2);
57 | var array = stream.ToArray();
58 | _prefix = version + Utilities.ByteArrayToHexString(array);
59 |
60 | DateTime epoch = new DateTime(2021, 1, 1,
61 | 0, 0, 0, 0, DateTimeKind.Utc);
62 |
63 | var now = DateTime.Now;
64 | _secondsSinceCustomEpoch = Convert.ToInt64(now.ToUniversalTime().Subtract(epoch).TotalSeconds);
65 | _stopwatch = Stopwatch.StartNew();
66 |
67 | _sequence = 0;
68 | }
69 |
70 | public String Next()
71 | {
72 | long deltaSeconds = _secondsSinceCustomEpoch + _stopwatch.ElapsedMilliseconds / 1_000;
73 |
74 | MemoryStream stream = new MemoryStream();
75 | BinaryWriter writer = new BinaryWriter(stream);
76 |
77 | byte[] deltaSecondsBytes = BitConverter.GetBytes(deltaSeconds);
78 | if (BitConverter.IsLittleEndian)
79 | {
80 | Array.Reverse(deltaSecondsBytes);
81 | }
82 |
83 | writer.Write(deltaSecondsBytes, 4, 4);
84 |
85 | int no = Interlocked.Increment(ref _sequence);
86 | byte[] noBytes = BitConverter.GetBytes(no);
87 | if (BitConverter.IsLittleEndian)
88 | {
89 | Array.Reverse(noBytes);
90 | }
91 |
92 | writer.Write(noBytes);
93 | var suffixBytes = stream.ToArray();
94 |
95 | return _prefix + Utilities.ByteArrayToHexString(suffixBytes);
96 | }
97 |
98 |
99 | public static MessageIdGenerator GetInstance()
100 | {
101 | return Instance;
102 | }
103 | }
104 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/MessageType.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | namespace Org.Apache.Rocketmq
19 | {
20 | public enum MessageType
21 | {
22 | Normal,
23 | Fifo,
24 | Delay,
25 | Transaction,
26 | }
27 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/MetadataConstants.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | public class MetadataConstants
23 | {
24 | public const string TENANT_ID_KEY = "x-mq-tenant-id";
25 | public const string NAMESPACE_KEY = "x-mq-namespace";
26 | public const string AUTHORIZATION = "authorization";
27 | public const string STS_SESSION_TOKEN = "x-mq-session-token";
28 | public const string DATE_TIME_KEY = "x-mq-date-time";
29 | public const string ALGORITHM_KEY = "MQv2-HMAC-SHA1";
30 | public const string CREDENTIAL_KEY = "Credential";
31 | public const string SIGNED_HEADERS_KEY = "SignedHeaders";
32 | public const string SIGNATURE_KEY = "Signature";
33 | public const string DATE_TIME_FORMAT = "yyyyMMddTHHmmssZ";
34 | public const string LANGUAGE_KEY = "x-mq-language";
35 | public const string CLIENT_VERSION_KEY = "x-mq-client-version";
36 | public const string PROTOCOL_VERSION_KEY = "x-mq-protocol-version";
37 | public const string REQUEST_ID_KEY = "x-mq-request-id";
38 |
39 | public const string CLIENT_ID_KEY = "x-mq-client-id";
40 | }
41 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/MqLogManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using NLog;
5 | using NLog.Config;
6 |
7 | namespace Org.Apache.Rocketmq
8 | {
9 | /**
10 | * RocketMQ Log Manager.
11 | *
12 | * Configure component logging, please refer to https://github.com/NLog/NLog/wiki/Configure-component-logging
13 | */
14 | public class MqLogManager
15 | {
16 | public static LogFactory Instance
17 | {
18 | get { return LazyInstance.Value; }
19 | }
20 |
21 | private static readonly Lazy LazyInstance = new(BuildLogFactory);
22 |
23 | private static LogFactory BuildLogFactory()
24 | {
25 | // Use name of current assembly to construct NLog config filename
26 | Assembly thisAssembly = Assembly.GetExecutingAssembly();
27 | string configFilePath = Path.ChangeExtension(thisAssembly.Location, ".nlog");
28 |
29 | LogFactory logFactory = new LogFactory();
30 | logFactory.Configuration = new XmlLoggingConfiguration(configFilePath, logFactory);
31 | return logFactory;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/ProcessQueue.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | namespace Org.Apache.Rocketmq
19 | {
20 | public class ProcessQueue
21 | {
22 |
23 | public ProcessQueue()
24 | {
25 | _lastReceivedTime = DateTime.UtcNow;
26 | }
27 | public bool Dropped { get; set; }
28 |
29 | private DateTime _lastReceivedTime;
30 |
31 | public DateTime LastReceiveTime
32 | {
33 | get { return _lastReceivedTime; }
34 | set { _lastReceivedTime = value; }
35 | }
36 |
37 | internal bool Expired()
38 | {
39 | return DateTime.UtcNow.Subtract(_lastReceivedTime).TotalMilliseconds > 30 * 1000;
40 | }
41 |
42 | }
43 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Producer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Threading.Tasks;
20 | using rmq = Apache.Rocketmq.V2;
21 | using System.Collections.Generic;
22 | using System.Collections.Concurrent;
23 | using System.Diagnostics;
24 | using System.Diagnostics.Metrics;
25 | using Google.Protobuf;
26 | using Google.Protobuf.WellKnownTypes;
27 | using Grpc.Core;
28 | using NLog;
29 | using OpenTelemetry;
30 | using OpenTelemetry.Exporter;
31 | using OpenTelemetry.Metrics;
32 |
33 | namespace Org.Apache.Rocketmq
34 | {
35 | public class Producer : Client, IProducer
36 | {
37 | public Producer(AccessPoint accessPoint, string resourceNamespace) : base(accessPoint, resourceNamespace)
38 | {
39 | _loadBalancer = new ConcurrentDictionary();
40 | _sendFailureTotal = MetricMeter.CreateCounter("rocketmq_send_failure_total");
41 | _sendLatency = MetricMeter.CreateHistogram(SendLatencyName,
42 | description: "Measure the duration of publishing messages to brokers",
43 | unit: "milliseconds");
44 | }
45 |
46 | public override async Task Start()
47 | {
48 | await base.Start();
49 | // More initialization
50 | // TODO: Add authentication header
51 |
52 | _meterProvider = Sdk.CreateMeterProviderBuilder()
53 | .AddMeter("Apache.RocketMQ.Client")
54 | .AddOtlpExporter(delegate(OtlpExporterOptions options, MetricReaderOptions readerOptions)
55 | {
56 | options.Protocol = OtlpExportProtocol.Grpc;
57 | options.Endpoint = new Uri(_accessPoint.TargetUrl());
58 | options.TimeoutMilliseconds = (int) _clientSettings.RequestTimeout.ToTimeSpan().TotalMilliseconds;
59 |
60 | readerOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = 60 * 1000;
61 | })
62 | .AddView((instrument) =>
63 | {
64 | if (instrument.Meter.Name == MeterName && instrument.Name == SendLatencyName)
65 | {
66 | return new ExplicitBucketHistogramConfiguration()
67 | {
68 | Boundaries = new double[] {1, 5, 10, 20, 50, 200, 500},
69 | };
70 | }
71 | return null;
72 | })
73 | .Build();
74 | }
75 |
76 | public override async Task Shutdown()
77 | {
78 | // Release local resources
79 | await base.Shutdown();
80 | }
81 |
82 | protected override void PrepareHeartbeatData(rmq::HeartbeatRequest request)
83 | {
84 | request.ClientType = rmq::ClientType.Producer;
85 |
86 | // Concept of ProducerGroup has been removed.
87 | }
88 |
89 | public async Task Send(Message message)
90 | {
91 | if (!_loadBalancer.ContainsKey(message.Topic))
92 | {
93 | var topicRouteData = await GetRouteFor(message.Topic, false);
94 | if (null == topicRouteData || null == topicRouteData.MessageQueues || 0 == topicRouteData.MessageQueues.Count)
95 | {
96 | Logger.Error($"Failed to resolve route info for {message.Topic}");
97 | throw new TopicRouteException(string.Format("No topic route for {0}", message.Topic));
98 | }
99 |
100 | var loadBalancerItem = new PublishLoadBalancer(topicRouteData);
101 | _loadBalancer.TryAdd(message.Topic, loadBalancerItem);
102 | }
103 |
104 | var publishLb = _loadBalancer[message.Topic];
105 |
106 | var request = new rmq::SendMessageRequest();
107 | var entry = new rmq::Message();
108 | entry.Body = ByteString.CopyFrom(message.Body);
109 | entry.Topic = new rmq::Resource();
110 | entry.Topic.ResourceNamespace = resourceNamespace();
111 | entry.Topic.Name = message.Topic;
112 | request.Messages.Add(entry);
113 |
114 | // User properties
115 | foreach (var item in message.UserProperties)
116 | {
117 | entry.UserProperties.Add(item.Key, item.Value);
118 | }
119 |
120 | entry.SystemProperties = new rmq::SystemProperties();
121 | entry.SystemProperties.MessageId = message.MessageId;
122 | entry.SystemProperties.MessageType = rmq::MessageType.Normal;
123 | if (DateTime.MinValue != message.DeliveryTimestamp)
124 | {
125 | entry.SystemProperties.MessageType = rmq::MessageType.Delay;
126 | entry.SystemProperties.DeliveryTimestamp = Timestamp.FromDateTime(message.DeliveryTimestamp);
127 |
128 | if (message.Fifo())
129 | {
130 | Logger.Warn("A message may not be FIFO and delayed at the same time");
131 | throw new MessageException("A message may not be both FIFO and Timed");
132 | }
133 | } else if (!String.IsNullOrEmpty(message.MessageGroup))
134 | {
135 | entry.SystemProperties.MessageType = rmq::MessageType.Fifo;
136 | entry.SystemProperties.MessageGroup = message.MessageGroup;
137 | }
138 |
139 | if (!string.IsNullOrEmpty(message.Tag))
140 | {
141 | entry.SystemProperties.Tag = message.Tag;
142 | }
143 |
144 | if (0 != message.Keys.Count)
145 | {
146 | foreach (var key in message.Keys)
147 | {
148 | entry.SystemProperties.Keys.Add(key);
149 | }
150 | }
151 |
152 | List targets = new List();
153 | List candidates = publishLb.Select(message.MaxAttemptTimes);
154 | foreach (var messageQueue in candidates)
155 | {
156 | targets.Add(Utilities.TargetUrl(messageQueue));
157 | }
158 |
159 | var metadata = new Metadata();
160 | Signature.sign(this, metadata);
161 |
162 | Exception ex = null;
163 |
164 | foreach (var target in targets)
165 | {
166 | try
167 | {
168 | var stopWatch = new Stopwatch();
169 | stopWatch.Start();
170 | rmq::SendMessageResponse response = await Manager.SendMessage(target, metadata, request, RequestTimeout);
171 | if (null != response && rmq::Code.Ok == response.Status.Code)
172 | {
173 | var messageId = response.Entries[0].MessageId;
174 |
175 | // Account latency histogram
176 | stopWatch.Stop();
177 | var latency = stopWatch.ElapsedMilliseconds;
178 | _sendLatency.Record(latency, new("topic", message.Topic), new("client_id", clientId()));
179 |
180 | return new SendReceipt(messageId);
181 | }
182 | }
183 | catch (Exception e)
184 | {
185 | // Account failure count
186 | _sendFailureTotal.Add(1, new("topic", message.Topic), new("client_id", clientId()));
187 | Logger.Info(e, $"Failed to send message to {target}");
188 | ex = e;
189 | }
190 | }
191 |
192 | if (null != ex)
193 | {
194 | Logger.Error(ex, $"Failed to send message after {message.MaxAttemptTimes} attempts");
195 | throw ex;
196 | }
197 |
198 | Logger.Error($"Failed to send message after {message.MaxAttemptTimes} attempts with unspecified reasons");
199 | throw new Exception("Send message failed");
200 | }
201 |
202 | private readonly ConcurrentDictionary _loadBalancer;
203 |
204 | private readonly Counter _sendFailureTotal;
205 | private readonly Histogram _sendLatency;
206 |
207 | private static readonly string SendLatencyName = "rocketmq_send_success_cost_time";
208 | private MeterProvider _meterProvider;
209 | }
210 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Protos/apache/rocketmq/v2/admin.proto:
--------------------------------------------------------------------------------
1 | // Licensed to the Apache Software Foundation (ASF) under one or more
2 | // contributor license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright ownership.
4 | // The ASF licenses this file to You under the Apache License, Version 2.0
5 | // (the "License"); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | syntax = "proto3";
17 |
18 | package apache.rocketmq.v2;
19 |
20 | option cc_enable_arenas = true;
21 | option csharp_namespace = "Apache.Rocketmq.V2";
22 | option java_multiple_files = true;
23 | option java_package = "apache.rocketmq.v2";
24 | option java_generate_equals_and_hash = true;
25 | option java_string_check_utf8 = true;
26 | option java_outer_classname = "MQAdmin";
27 |
28 | message ChangeLogLevelRequest {
29 | enum Level {
30 | TRACE = 0;
31 | DEBUG = 1;
32 | INFO = 2;
33 | WARN = 3;
34 | ERROR = 4;
35 | }
36 | Level level = 1;
37 | }
38 |
39 | message ChangeLogLevelResponse { string remark = 1; }
40 |
41 | service Admin {
42 | rpc ChangeLogLevel(ChangeLogLevelRequest) returns (ChangeLogLevelResponse) {}
43 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Protos/google/rpc/code.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 |
17 | package google.rpc;
18 |
19 | option go_package = "google.golang.org/genproto/googleapis/rpc/code;code";
20 | option java_multiple_files = true;
21 | option java_outer_classname = "CodeProto";
22 | option java_package = "com.google.rpc";
23 | option objc_class_prefix = "RPC";
24 |
25 | // The canonical error codes for gRPC APIs.
26 | //
27 | //
28 | // Sometimes multiple error codes may apply. Services should return
29 | // the most specific error code that applies. For example, prefer
30 | // `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply.
31 | // Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`.
32 | enum Code {
33 | // Not an error; returned on success
34 | //
35 | // HTTP Mapping: 200 OK
36 | OK = 0;
37 |
38 | // The operation was cancelled, typically by the caller.
39 | //
40 | // HTTP Mapping: 499 Client Closed Request
41 | CANCELLED = 1;
42 |
43 | // Unknown error. For example, this error may be returned when
44 | // a `Status` value received from another address space belongs to
45 | // an error space that is not known in this address space. Also
46 | // errors raised by APIs that do not return enough error information
47 | // may be converted to this error.
48 | //
49 | // HTTP Mapping: 500 Internal Server Error
50 | UNKNOWN = 2;
51 |
52 | // The client specified an invalid argument. Note that this differs
53 | // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments
54 | // that are problematic regardless of the state of the system
55 | // (e.g., a malformed file name).
56 | //
57 | // HTTP Mapping: 400 Bad Request
58 | INVALID_ARGUMENT = 3;
59 |
60 | // The deadline expired before the operation could complete. For operations
61 | // that change the state of the system, this error may be returned
62 | // even if the operation has completed successfully. For example, a
63 | // successful response from a server could have been delayed long
64 | // enough for the deadline to expire.
65 | //
66 | // HTTP Mapping: 504 Gateway Timeout
67 | DEADLINE_EXCEEDED = 4;
68 |
69 | // Some requested entity (e.g., file or directory) was not found.
70 | //
71 | // Note to server developers: if a request is denied for an entire class
72 | // of users, such as gradual feature rollout or undocumented whitelist,
73 | // `NOT_FOUND` may be used. If a request is denied for some users within
74 | // a class of users, such as user-based access control, `PERMISSION_DENIED`
75 | // must be used.
76 | //
77 | // HTTP Mapping: 404 Not Found
78 | NOT_FOUND = 5;
79 |
80 | // The entity that a client attempted to create (e.g., file or directory)
81 | // already exists.
82 | //
83 | // HTTP Mapping: 409 Conflict
84 | ALREADY_EXISTS = 6;
85 |
86 | // The caller does not have permission to execute the specified
87 | // operation. `PERMISSION_DENIED` must not be used for rejections
88 | // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
89 | // instead for those errors). `PERMISSION_DENIED` must not be
90 | // used if the caller can not be identified (use `UNAUTHENTICATED`
91 | // instead for those errors). This error code does not imply the
92 | // request is valid or the requested entity exists or satisfies
93 | // other pre-conditions.
94 | //
95 | // HTTP Mapping: 403 Forbidden
96 | PERMISSION_DENIED = 7;
97 |
98 | // The request does not have valid authentication credentials for the
99 | // operation.
100 | //
101 | // HTTP Mapping: 401 Unauthorized
102 | UNAUTHENTICATED = 16;
103 |
104 | // Some resource has been exhausted, perhaps a per-user quota, or
105 | // perhaps the entire file system is out of space.
106 | //
107 | // HTTP Mapping: 429 Too Many Requests
108 | RESOURCE_EXHAUSTED = 8;
109 |
110 | // The operation was rejected because the system is not in a state
111 | // required for the operation's execution. For example, the directory
112 | // to be deleted is non-empty, an rmdir operation is applied to
113 | // a non-directory, etc.
114 | //
115 | // Service implementors can use the following guidelines to decide
116 | // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:
117 | // (a) Use `UNAVAILABLE` if the client can retry just the failing call.
118 | // (b) Use `ABORTED` if the client should retry at a higher level
119 | // (e.g., when a client-specified test-and-set fails, indicating the
120 | // client should restart a read-modify-write sequence).
121 | // (c) Use `FAILED_PRECONDITION` if the client should not retry until
122 | // the system state has been explicitly fixed. E.g., if an "rmdir"
123 | // fails because the directory is non-empty, `FAILED_PRECONDITION`
124 | // should be returned since the client should not retry unless
125 | // the files are deleted from the directory.
126 | //
127 | // HTTP Mapping: 400 Bad Request
128 | FAILED_PRECONDITION = 9;
129 |
130 | // The operation was aborted, typically due to a concurrency issue such as
131 | // a sequencer check failure or transaction abort.
132 | //
133 | // See the guidelines above for deciding between `FAILED_PRECONDITION`,
134 | // `ABORTED`, and `UNAVAILABLE`.
135 | //
136 | // HTTP Mapping: 409 Conflict
137 | ABORTED = 10;
138 |
139 | // The operation was attempted past the valid range. E.g., seeking or
140 | // reading past end-of-file.
141 | //
142 | // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may
143 | // be fixed if the system state changes. For example, a 32-bit file
144 | // system will generate `INVALID_ARGUMENT` if asked to read at an
145 | // offset that is not in the range [0,2^32-1], but it will generate
146 | // `OUT_OF_RANGE` if asked to read from an offset past the current
147 | // file size.
148 | //
149 | // There is a fair bit of overlap between `FAILED_PRECONDITION` and
150 | // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific
151 | // error) when it applies so that callers who are iterating through
152 | // a space can easily look for an `OUT_OF_RANGE` error to detect when
153 | // they are done.
154 | //
155 | // HTTP Mapping: 400 Bad Request
156 | OUT_OF_RANGE = 11;
157 |
158 | // The operation is not implemented or is not supported/enabled in this
159 | // service.
160 | //
161 | // HTTP Mapping: 501 Not Implemented
162 | UNIMPLEMENTED = 12;
163 |
164 | // Internal errors. This means that some invariants expected by the
165 | // underlying system have been broken. This error code is reserved
166 | // for serious errors.
167 | //
168 | // HTTP Mapping: 500 Internal Server Error
169 | INTERNAL = 13;
170 |
171 | // The service is currently unavailable. This is most likely a
172 | // transient condition, which can be corrected by retrying with
173 | // a backoff. Note that it is not always safe to retry
174 | // non-idempotent operations.
175 | //
176 | // See the guidelines above for deciding between `FAILED_PRECONDITION`,
177 | // `ABORTED`, and `UNAVAILABLE`.
178 | //
179 | // HTTP Mapping: 503 Service Unavailable
180 | UNAVAILABLE = 14;
181 |
182 | // Unrecoverable data loss or corruption.
183 | //
184 | // HTTP Mapping: 500 Internal Server Error
185 | DATA_LOSS = 15;
186 | }
187 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Protos/google/rpc/error_details.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 |
17 | package google.rpc;
18 |
19 | import "google/protobuf/duration.proto";
20 |
21 | option go_package = "google.golang.org/genproto/googleapis/rpc/errdetails;errdetails";
22 | option java_multiple_files = true;
23 | option java_outer_classname = "ErrorDetailsProto";
24 | option java_package = "com.google.rpc";
25 | option objc_class_prefix = "RPC";
26 |
27 | // Describes when the clients can retry a failed request. Clients could ignore
28 | // the recommendation here or retry when this information is missing from error
29 | // responses.
30 | //
31 | // It's always recommended that clients should use exponential backoff when
32 | // retrying.
33 | //
34 | // Clients should wait until `retry_delay` amount of time has passed since
35 | // receiving the error response before retrying. If retrying requests also
36 | // fail, clients should use an exponential backoff scheme to gradually increase
37 | // the delay between retries based on `retry_delay`, until either a maximum
38 | // number of retries have been reached or a maximum retry delay cap has been
39 | // reached.
40 | message RetryInfo {
41 | // Clients should wait at least this long between retrying the same request.
42 | google.protobuf.Duration retry_delay = 1;
43 | }
44 |
45 | // Describes additional debugging info.
46 | message DebugInfo {
47 | // The stack trace entries indicating where the error occurred.
48 | repeated string stack_entries = 1;
49 |
50 | // Additional debugging information provided by the server.
51 | string detail = 2;
52 | }
53 |
54 | // Describes how a quota check failed.
55 | //
56 | // For example if a daily limit was exceeded for the calling project,
57 | // a service could respond with a QuotaFailure detail containing the project
58 | // id and the description of the quota limit that was exceeded. If the
59 | // calling project hasn't enabled the service in the developer console, then
60 | // a service could respond with the project id and set `service_disabled`
61 | // to true.
62 | //
63 | // Also see RetryInfo and Help types for other details about handling a
64 | // quota failure.
65 | message QuotaFailure {
66 | // A message type used to describe a single quota violation. For example, a
67 | // daily quota or a custom quota that was exceeded.
68 | message Violation {
69 | // The subject on which the quota check failed.
70 | // For example, "clientip:" or "project:".
72 | string subject = 1;
73 |
74 | // A description of how the quota check failed. Clients can use this
75 | // description to find more about the quota configuration in the service's
76 | // public documentation, or find the relevant quota limit to adjust through
77 | // developer console.
78 | //
79 | // For example: "Service disabled" or "Daily Limit for read operations
80 | // exceeded".
81 | string description = 2;
82 | }
83 |
84 | // Describes all quota violations.
85 | repeated Violation violations = 1;
86 | }
87 |
88 | // Describes the cause of the error with structured details.
89 | //
90 | // Example of an error when contacting the "pubsub.googleapis.com" API when it
91 | // is not enabled:
92 | //
93 | // { "reason": "API_DISABLED"
94 | // "domain": "googleapis.com"
95 | // "metadata": {
96 | // "resource": "projects/123",
97 | // "service": "pubsub.googleapis.com"
98 | // }
99 | // }
100 | //
101 | // This response indicates that the pubsub.googleapis.com API is not enabled.
102 | //
103 | // Example of an error that is returned when attempting to create a Spanner
104 | // instance in a region that is out of stock:
105 | //
106 | // { "reason": "STOCKOUT"
107 | // "domain": "spanner.googleapis.com",
108 | // "metadata": {
109 | // "availableRegions": "us-central1,us-east2"
110 | // }
111 | // }
112 | message ErrorInfo {
113 | // The reason of the error. This is a constant value that identifies the
114 | // proximate cause of the error. Error reasons are unique within a particular
115 | // domain of errors. This should be at most 63 characters and match
116 | // /[A-Z0-9_]+/.
117 | string reason = 1;
118 |
119 | // The logical grouping to which the "reason" belongs. The error domain
120 | // is typically the registered service name of the tool or product that
121 | // generates the error. Example: "pubsub.googleapis.com". If the error is
122 | // generated by some common infrastructure, the error domain must be a
123 | // globally unique value that identifies the infrastructure. For Google API
124 | // infrastructure, the error domain is "googleapis.com".
125 | string domain = 2;
126 |
127 | // Additional structured details about this error.
128 | //
129 | // Keys should match /[a-zA-Z0-9-_]/ and be limited to 64 characters in
130 | // length. When identifying the current value of an exceeded limit, the units
131 | // should be contained in the key, not the value. For example, rather than
132 | // {"instanceLimit": "100/request"}, should be returned as,
133 | // {"instanceLimitPerRequest": "100"}, if the client exceeds the number of
134 | // instances that can be created in a single (batch) request.
135 | map metadata = 3;
136 | }
137 |
138 | // Describes what preconditions have failed.
139 | //
140 | // For example, if an RPC failed because it required the Terms of Service to be
141 | // acknowledged, it could list the terms of service violation in the
142 | // PreconditionFailure message.
143 | message PreconditionFailure {
144 | // A message type used to describe a single precondition failure.
145 | message Violation {
146 | // The type of PreconditionFailure. We recommend using a service-specific
147 | // enum type to define the supported precondition violation subjects. For
148 | // example, "TOS" for "Terms of Service violation".
149 | string type = 1;
150 |
151 | // The subject, relative to the type, that failed.
152 | // For example, "google.com/cloud" relative to the "TOS" type would indicate
153 | // which terms of service is being referenced.
154 | string subject = 2;
155 |
156 | // A description of how the precondition failed. Developers can use this
157 | // description to understand how to fix the failure.
158 | //
159 | // For example: "Terms of service not accepted".
160 | string description = 3;
161 | }
162 |
163 | // Describes all precondition violations.
164 | repeated Violation violations = 1;
165 | }
166 |
167 | // Describes violations in a client request. This error type focuses on the
168 | // syntactic aspects of the request.
169 | message BadRequest {
170 | // A message type used to describe a single bad request field.
171 | message FieldViolation {
172 | // A path leading to a field in the request body. The value will be a
173 | // sequence of dot-separated identifiers that identify a protocol buffer
174 | // field. E.g., "field_violations.field" would identify this field.
175 | string field = 1;
176 |
177 | // A description of why the request element is bad.
178 | string description = 2;
179 | }
180 |
181 | // Describes all violations in a client request.
182 | repeated FieldViolation field_violations = 1;
183 | }
184 |
185 | // Contains metadata about the request that clients can attach when filing a bug
186 | // or providing other forms of feedback.
187 | message RequestInfo {
188 | // An opaque string that should only be interpreted by the service generating
189 | // it. For example, it can be used to identify requests in the service's logs.
190 | string request_id = 1;
191 |
192 | // Any data that was used to serve this request. For example, an encrypted
193 | // stack trace that can be sent back to the service provider for debugging.
194 | string serving_data = 2;
195 | }
196 |
197 | // Describes the resource that is being accessed.
198 | message ResourceInfo {
199 | // A name for the type of resource being accessed, e.g. "sql table",
200 | // "cloud storage bucket", "file", "Google calendar"; or the type URL
201 | // of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic".
202 | string resource_type = 1;
203 |
204 | // The name of the resource being accessed. For example, a shared calendar
205 | // name: "example.com_4fghdhgsrgh@group.calendar.google.com", if the current
206 | // error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED].
207 | string resource_name = 2;
208 |
209 | // The owner of the resource (optional).
210 | // For example, "user:" or "project:".
212 | string owner = 3;
213 |
214 | // Describes what error is encountered when accessing this resource.
215 | // For example, updating a cloud project may require the `writer` permission
216 | // on the developer console project.
217 | string description = 4;
218 | }
219 |
220 | // Provides links to documentation or for performing an out of band action.
221 | //
222 | // For example, if a quota check failed with an error indicating the calling
223 | // project hasn't enabled the accessed service, this can contain a URL pointing
224 | // directly to the right place in the developer console to flip the bit.
225 | message Help {
226 | // Describes a URL link.
227 | message Link {
228 | // Describes what the link offers.
229 | string description = 1;
230 |
231 | // The URL of the link.
232 | string url = 2;
233 | }
234 |
235 | // URL(s) pointing to additional information on handling the current error.
236 | repeated Link links = 1;
237 | }
238 |
239 | // Provides a localized error message that is safe to return to the user
240 | // which can be attached to an RPC error.
241 | message LocalizedMessage {
242 | // The locale used following the specification defined at
243 | // http://www.rfc-editor.org/rfc/bcp/bcp47.txt.
244 | // Examples are: "en-US", "fr-CH", "es-MX"
245 | string locale = 1;
246 |
247 | // The localized error message in the above locale.
248 | string message = 2;
249 | }
250 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Protos/google/rpc/status.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 |
17 | package google.rpc;
18 |
19 | import "google/protobuf/any.proto";
20 |
21 | option cc_enable_arenas = true;
22 | option go_package = "google.golang.org/genproto/googleapis/rpc/status;status";
23 | option java_multiple_files = true;
24 | option java_outer_classname = "StatusProto";
25 | option java_package = "com.google.rpc";
26 | option objc_class_prefix = "RPC";
27 |
28 | // The `Status` type defines a logical error model that is suitable for
29 | // different programming environments, including REST APIs and RPC APIs. It is
30 | // used by [gRPC](https://github.com/grpc). Each `Status` message contains
31 | // three pieces of data: error code, error message, and error details.
32 | //
33 | // You can find out more about this error model and how to work with it in the
34 | // [API Design Guide](https://cloud.google.com/apis/design/errors).
35 | message Status {
36 | // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
37 | int32 code = 1;
38 |
39 | // A developer-facing error message, which should be in English. Any
40 | // user-facing error message should be localized and sent in the
41 | // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
42 | string message = 2;
43 |
44 | // A list of messages that carry the error details. There is a common set of
45 | // message types for APIs to use.
46 | repeated google.protobuf.Any details = 3;
47 | }
48 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/PublishLoadBalancer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using System.Collections.Generic;
19 | using rmq = Apache.Rocketmq.V2;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 | public class PublishLoadBalancer
24 | {
25 | public PublishLoadBalancer(TopicRouteData route)
26 | {
27 | this._messageQueues = new List();
28 | foreach (var messageQueue in route.MessageQueues)
29 | {
30 | if (rmq::Permission.Unspecified == messageQueue.Permission)
31 | {
32 | continue;
33 | }
34 |
35 | if (rmq::Permission.Read == messageQueue.Permission)
36 | {
37 | continue;
38 | }
39 |
40 | this._messageQueues.Add(messageQueue);
41 | }
42 |
43 | this._messageQueues.Sort(Utilities.CompareMessageQueue);
44 | Random random = new Random();
45 | this._roundRobinIndex = random.Next(0, this._messageQueues.Count);
46 | }
47 |
48 | public void Update(TopicRouteData route)
49 | {
50 | List partitions = new List();
51 | foreach (var partition in route.MessageQueues)
52 | {
53 | if (rmq::Permission.Unspecified == partition.Permission)
54 | {
55 | continue;
56 | }
57 |
58 | if (rmq::Permission.Read == partition.Permission)
59 | {
60 | continue;
61 | }
62 | partitions.Add(partition);
63 | }
64 | partitions.Sort();
65 | this._messageQueues = partitions;
66 | }
67 |
68 | /**
69 | * Accept a partition iff its broker is different.
70 | */
71 | private bool Accept(List existing, rmq::MessageQueue messageQueue)
72 | {
73 | if (0 == existing.Count)
74 | {
75 | return true;
76 | }
77 |
78 | foreach (var item in existing)
79 | {
80 | if (item.Broker.Equals(messageQueue.Broker))
81 | {
82 | return false;
83 | }
84 | }
85 | return true;
86 | }
87 |
88 | public List Select(int maxAttemptTimes)
89 | {
90 | List result = new List();
91 |
92 | List all = this._messageQueues;
93 | if (0 == all.Count)
94 | {
95 | return result;
96 | }
97 | int start = ++_roundRobinIndex;
98 | int found = 0;
99 |
100 | for (int i = 0; i < all.Count; i++)
101 | {
102 | int idx = ((start + i) & int.MaxValue) % all.Count;
103 | if (Accept(result, all[idx]))
104 | {
105 | result.Add(all[idx]);
106 | if (++found >= maxAttemptTimes)
107 | {
108 | break;
109 | }
110 | }
111 | }
112 |
113 | return result;
114 | }
115 |
116 | private List _messageQueues;
117 |
118 | private int _roundRobinIndex;
119 | }
120 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Publishing.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using rmq = Apache.Rocketmq.V2;
19 | using System.Collections.Generic;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 | // Settings for publishing
24 | public class Publishing
25 | {
26 | public List Topics { get; set; }
27 | public int CompressBodyThreshold { get; set; }
28 |
29 | public int MaxBodySize { get; set; }
30 | }
31 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/PushConsumer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System.Collections.Concurrent;
18 | using System.Collections.Generic;
19 | using rmq = Apache.Rocketmq.V2;
20 | using System.Threading;
21 | using System.Threading.Tasks;
22 |
23 | namespace Org.Apache.Rocketmq
24 | {
25 | public class PushConsumer : Client, IConsumer
26 | {
27 | public PushConsumer(AccessPoint accessPoint, string resourceNamespace, string group) : base(accessPoint, resourceNamespace)
28 | {
29 | _group = group;
30 | _topicFilterExpressionMap = new ConcurrentDictionary();
31 | _topicAssignmentsMap = new ConcurrentDictionary>();
32 | _processQueueMap = new ConcurrentDictionary();
33 | _scanAssignmentCTS = new CancellationTokenSource();
34 | _scanExpiredProcessQueueCTS = new CancellationTokenSource();
35 | }
36 |
37 | public override async Task Start()
38 | {
39 | if (null == _messageListener)
40 | {
41 | throw new System.Exception("Bad configuration: message listener is required");
42 | }
43 |
44 | await base.Start();
45 |
46 | // Step-1: Resolve topic routes
47 | List> queryRouteTasks = new List>();
48 | foreach (var item in _topicFilterExpressionMap)
49 | {
50 | queryRouteTasks.Add(GetRouteFor(item.Key, true));
51 | }
52 | Task.WhenAll(queryRouteTasks).GetAwaiter().GetResult();
53 |
54 | // Step-2: Send heartbeats to all involving brokers so that we may get immediate, valid assignments.
55 | await Heartbeat();
56 |
57 | // Step-3: Scan load assignments that are assigned to current client
58 | schedule(async () =>
59 | {
60 | await scanLoadAssignments();
61 | }, 10, _scanAssignmentCTS.Token);
62 |
63 | schedule(() =>
64 | {
65 | ScanExpiredProcessQueue();
66 | }, 10, _scanExpiredProcessQueueCTS.Token);
67 | }
68 |
69 | public override async Task Shutdown()
70 | {
71 | _scanAssignmentCTS.Cancel();
72 | _scanExpiredProcessQueueCTS.Cancel();
73 |
74 | // Shutdown resources of derived class
75 | await base.Shutdown();
76 | }
77 |
78 | private async Task scanLoadAssignments()
79 | {
80 | Logger.Debug("Start to scan load assignments from server");
81 | List>> tasks = new List>>();
82 | foreach (var item in _topicFilterExpressionMap)
83 | {
84 | tasks.Add(scanLoadAssignment(item.Key, _group));
85 | }
86 | var result = await Task.WhenAll(tasks);
87 |
88 | foreach (var assignments in result)
89 | {
90 | if (assignments.Count == 0)
91 | {
92 | continue;
93 | }
94 |
95 | checkAndUpdateAssignments(assignments);
96 | }
97 | Logger.Debug("Completed scanning load assignments");
98 | }
99 |
100 | private void ScanExpiredProcessQueue()
101 | {
102 | foreach (var item in _processQueueMap)
103 | {
104 | if (item.Value.Expired())
105 | {
106 | Task.Run(async () =>
107 | {
108 | await ExecutePop0(item.Key);
109 | });
110 | }
111 | }
112 | }
113 |
114 | private void checkAndUpdateAssignments(List assignments)
115 | {
116 | if (assignments.Count == 0)
117 | {
118 | return;
119 | }
120 |
121 | string topic = assignments[0].MessageQueue.Topic.Name;
122 |
123 | // Compare to generate or cancel pop-cycles
124 | List existing;
125 | _topicAssignmentsMap.TryGetValue(topic, out existing);
126 |
127 | foreach (var assignment in assignments)
128 | {
129 | if (null == existing || !existing.Contains(assignment))
130 | {
131 | ExecutePop(assignment);
132 | }
133 | }
134 |
135 | if (null != existing)
136 | {
137 | foreach (var assignment in existing)
138 | {
139 | if (!assignments.Contains(assignment))
140 | {
141 | Logger.Info($"Stop receiving messages from {assignment.MessageQueue.ToString()}");
142 | CancelPop(assignment);
143 | }
144 | }
145 | }
146 |
147 | }
148 |
149 | private void ExecutePop(rmq::Assignment assignment)
150 | {
151 | var processQueue = new ProcessQueue();
152 | if (_processQueueMap.TryAdd(assignment, processQueue))
153 | {
154 | Task.Run(async () =>
155 | {
156 | await ExecutePop0(assignment);
157 | });
158 | }
159 | }
160 |
161 | private async Task ExecutePop0(rmq::Assignment assignment)
162 | {
163 | Logger.Info($"Start to pop {assignment.MessageQueue.ToString()}");
164 | while (true)
165 | {
166 | try
167 | {
168 | ProcessQueue processQueue;
169 | if (!_processQueueMap.TryGetValue(assignment, out processQueue))
170 | {
171 | break;
172 | }
173 |
174 | if (processQueue.Dropped)
175 | {
176 | break;
177 | }
178 |
179 | List messages = await base.ReceiveMessage(assignment, _group);
180 | processQueue.LastReceiveTime = System.DateTime.UtcNow;
181 |
182 | // TODO: cache message and dispatch them
183 |
184 | List failed = new List();
185 | await _messageListener.Consume(messages, failed);
186 |
187 | foreach (var message in failed)
188 | {
189 | await base.ChangeInvisibleDuration(message._sourceHost, _group, message.Topic, message._receiptHandle, message.MessageId);
190 | }
191 |
192 | foreach (var message in messages)
193 | {
194 | if (!failed.Contains(message))
195 | {
196 | bool success = await base.Ack(message._sourceHost, _group, message.Topic, message._receiptHandle, message.MessageId);
197 | if (!success)
198 | {
199 | //TODO: log error.
200 | }
201 | }
202 | }
203 | }
204 | catch (System.Exception)
205 | {
206 | // TODO: log exception raised.
207 | }
208 |
209 |
210 | }
211 | }
212 |
213 | private void CancelPop(rmq::Assignment assignment)
214 | {
215 | if (!_processQueueMap.ContainsKey(assignment))
216 | {
217 | return;
218 | }
219 |
220 | ProcessQueue processQueue;
221 | if (_processQueueMap.Remove(assignment, out processQueue))
222 | {
223 | processQueue.Dropped = true;
224 | }
225 | }
226 |
227 | protected override void PrepareHeartbeatData(rmq::HeartbeatRequest request)
228 | {
229 | }
230 |
231 | public void Subscribe(string topic, string expression, ExpressionType type)
232 | {
233 | var filterExpression = new FilterExpression(expression, type);
234 | _topicFilterExpressionMap[topic] = filterExpression;
235 |
236 | }
237 |
238 | public void RegisterListener(IMessageListener listener)
239 | {
240 | if (null != listener)
241 | {
242 | _messageListener = listener;
243 | }
244 | }
245 |
246 | private string _group;
247 |
248 | private ConcurrentDictionary _topicFilterExpressionMap;
249 | private IMessageListener _messageListener;
250 |
251 | private CancellationTokenSource _scanAssignmentCTS;
252 |
253 | private ConcurrentDictionary> _topicAssignmentsMap;
254 |
255 | private ConcurrentDictionary _processQueueMap;
256 |
257 | private CancellationTokenSource _scanExpiredProcessQueueCTS;
258 |
259 | }
260 |
261 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/RpcClient.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Net.Http;
21 | using System.Net.Security;
22 | using System.Threading;
23 | using System.Threading.Tasks;
24 | using rmq = Apache.Rocketmq.V2;
25 | using Grpc.Core;
26 | using Grpc.Core.Interceptors;
27 | using Grpc.Net.Client;
28 | using NLog;
29 |
30 | namespace Org.Apache.Rocketmq
31 | {
32 | public class RpcClient : IRpcClient
33 | {
34 | protected static readonly Logger Logger = MqLogManager.Instance.GetCurrentClassLogger();
35 | private readonly rmq::MessagingService.MessagingServiceClient _stub;
36 | private readonly GrpcChannel _channel;
37 |
38 | public RpcClient(string target)
39 | {
40 | _channel = GrpcChannel.ForAddress(target, new GrpcChannelOptions
41 | {
42 | HttpHandler = CreateHttpHandler()
43 | });
44 | var invoker = _channel.Intercept(new ClientLoggerInterceptor());
45 | _stub = new rmq::MessagingService.MessagingServiceClient(invoker);
46 | }
47 |
48 | public async Task Shutdown()
49 | {
50 | if (null != _channel)
51 | {
52 | await _channel.ShutdownAsync();
53 | }
54 | }
55 |
56 | /**
57 | * See https://docs.microsoft.com/en-us/aspnet/core/grpc/performance?view=aspnetcore-6.0 for performance consideration and
58 | * why parameters are configured this way.
59 | */
60 | private HttpMessageHandler CreateHttpHandler()
61 | {
62 | var sslOptions = new SslClientAuthenticationOptions();
63 | // Disable server certificate validation during development phase.
64 | // Comment out the following line if server certificate validation is required.
65 | sslOptions.RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
66 | var handler = new SocketsHttpHandler
67 | {
68 | PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
69 | KeepAlivePingDelay = TimeSpan.FromSeconds(60),
70 | KeepAlivePingTimeout = TimeSpan.FromSeconds(30),
71 | EnableMultipleHttp2Connections = true,
72 | SslOptions = sslOptions,
73 | };
74 | return handler;
75 | }
76 |
77 | public AsyncDuplexStreamingCall Telemetry(Metadata metadata)
78 | {
79 | var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(3));
80 | var callOptions = new CallOptions(metadata, deadline);
81 | return _stub.Telemetry(callOptions);
82 | }
83 |
84 | public async Task QueryRoute(Metadata metadata, rmq::QueryRouteRequest request, TimeSpan timeout)
85 | {
86 | var deadline = DateTime.UtcNow.Add(timeout);
87 | var callOptions = new CallOptions(metadata, deadline);
88 |
89 | var call = _stub.QueryRouteAsync(request, callOptions);
90 | return await call.ResponseAsync;
91 | }
92 |
93 |
94 | public async Task Heartbeat(Metadata metadata, rmq::HeartbeatRequest request, TimeSpan timeout)
95 | {
96 | var deadline = DateTime.UtcNow.Add(timeout);
97 | var callOptions = new CallOptions(metadata, deadline);
98 |
99 | var call = _stub.HeartbeatAsync(request, callOptions);
100 | return await call.ResponseAsync;
101 | }
102 |
103 | public async Task SendMessage(Metadata metadata, rmq::SendMessageRequest request,
104 | TimeSpan timeout)
105 | {
106 | var deadline = DateTime.UtcNow.Add(timeout);
107 | var callOptions = new CallOptions(metadata, deadline);
108 |
109 | var call = _stub.SendMessageAsync(request, callOptions);
110 | return await call.ResponseAsync;
111 | }
112 |
113 | public async Task QueryAssignment(Metadata metadata, rmq::QueryAssignmentRequest request,
114 | TimeSpan timeout)
115 | {
116 | var deadline = DateTime.UtcNow.Add(timeout);
117 | var callOptions = new CallOptions(metadata, deadline);
118 |
119 | var call = _stub.QueryAssignmentAsync(request, callOptions);
120 | return await call.ResponseAsync;
121 | }
122 |
123 | public async Task> ReceiveMessage(Metadata metadata,
124 | rmq::ReceiveMessageRequest request, TimeSpan timeout) {
125 | var deadline = DateTime.UtcNow.Add(timeout);
126 | var callOptions = new CallOptions(metadata, deadline);
127 | var call = _stub.ReceiveMessage(request, callOptions);
128 | var result = new List();
129 | var stream = call.ResponseStream;
130 | while (await stream.MoveNext())
131 | {
132 | var entry = stream.Current;
133 | Logger.Debug($"Got ReceiveMessageResponse {entry}");
134 | result.Add(entry);
135 | }
136 | Logger.Debug($"Receiving of messages completed");
137 | return result;
138 | }
139 |
140 | public async Task AckMessage(Metadata metadata, rmq::AckMessageRequest request,
141 | TimeSpan timeout)
142 | {
143 | var deadline = DateTime.UtcNow.Add(timeout);
144 | var callOptions = new CallOptions(metadata, deadline);
145 |
146 | var call = _stub.AckMessageAsync(request, callOptions);
147 | return await call.ResponseAsync;
148 | }
149 |
150 | public async Task ChangeInvisibleDuration(Metadata metadata, rmq::ChangeInvisibleDurationRequest request,
151 | TimeSpan timeout)
152 | {
153 | var deadline = DateTime.UtcNow.Add(timeout);
154 | var callOptions = new CallOptions(metadata, deadline);
155 |
156 | var call = _stub.ChangeInvisibleDurationAsync(request, callOptions);
157 | return await call.ResponseAsync;
158 | }
159 |
160 | public async Task ForwardMessageToDeadLetterQueue(Metadata metadata,
161 | rmq::ForwardMessageToDeadLetterQueueRequest request, TimeSpan timeout)
162 | {
163 | var deadline = DateTime.UtcNow.Add(timeout);
164 | var callOptions = new CallOptions(metadata, deadline);
165 |
166 | var call = _stub.ForwardMessageToDeadLetterQueueAsync(request, callOptions);
167 | return await call.ResponseAsync;
168 | }
169 |
170 | public async Task EndTransaction(Metadata metadata, rmq::EndTransactionRequest request,
171 | TimeSpan timeout)
172 | {
173 | var deadline = DateTime.UtcNow.Add(timeout);
174 | var callOptions = new CallOptions(metadata, deadline);
175 |
176 | var call = _stub.EndTransactionAsync(request, callOptions);
177 | return await call.ResponseAsync;
178 | }
179 |
180 | public async Task NotifyClientTermination(Metadata metadata,
181 | rmq::NotifyClientTerminationRequest request, TimeSpan timeout)
182 | {
183 | var deadline = DateTime.UtcNow.Add(timeout);
184 | var callOptions = new CallOptions(metadata, deadline);
185 |
186 | var call = _stub.NotifyClientTerminationAsync(request, callOptions);
187 | return await call.ResponseAsync;
188 | }
189 | }
190 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/SendReceipt.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | namespace Org.Apache.Rocketmq
19 | {
20 | public sealed class SendReceipt
21 | {
22 | public SendReceipt(string messageId)
23 | {
24 | status_ = SendStatus.SEND_OK;
25 | messageId_ = messageId;
26 | }
27 |
28 | public SendReceipt(string messageId, SendStatus status)
29 | {
30 | status_ = status;
31 | messageId_ = messageId;
32 | }
33 |
34 | private string messageId_;
35 |
36 | public string MessageId
37 | {
38 | get { return messageId_; }
39 | }
40 |
41 |
42 | private SendStatus status_;
43 |
44 | public SendStatus Status
45 | {
46 | get { return status_; }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/SendStatus.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | namespace Org.Apache.Rocketmq
19 | {
20 | public enum SendStatus
21 | {
22 | SEND_OK,
23 | FLUSH_DISK_TIMEOUT,
24 | FLUSH_SLAVE_TIMEOUT,
25 | SLAVE_NOT_AVAILABLE,
26 | }
27 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/SequenceGenerator.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using System.Threading;
19 | using System.Net.NetworkInformation;
20 | using NLog;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 | /**
25 | * See https://yuque.antfin-inc.com/aone709911/ca1edg/af2t6o for Sequence ID spec.
26 | *
27 | * In the implementation layer, this class follows Singleton pattern.
28 | */
29 | public sealed class SequenceGenerator
30 | {
31 | private static readonly Logger Logger = MqLogManager.Instance.GetCurrentClassLogger();
32 |
33 | public static SequenceGenerator Instance
34 | {
35 | get
36 | {
37 | return Nested.instance;
38 | }
39 | }
40 |
41 | private class Nested
42 | {
43 | static Nested()
44 | {
45 |
46 | }
47 |
48 | internal static readonly SequenceGenerator instance = new SequenceGenerator();
49 | }
50 |
51 | private SequenceGenerator()
52 | {
53 | currentSecond = SecondsSinceCustomEpoch();
54 | macAddress = MacAddress();
55 | pidBytes = ToArray(pid);
56 | if (BitConverter.IsLittleEndian)
57 | {
58 | Array.Reverse(version);
59 | }
60 | }
61 |
62 | /**
63 | * Sequence version, 2 bytes.
64 | */
65 | private static byte[] version = new byte[2] { 0x00, 0x01 };
66 |
67 | /**
68 | * MAC address, 6 bytes.
69 | */
70 | private byte[] macAddress;
71 |
72 | private int sequenceInSecond = 0;
73 | private int currentSecond;
74 |
75 | private static int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
76 | private static byte[] pidBytes;
77 |
78 | private static byte[] ToArray(int number)
79 | {
80 | byte[] bytes = BitConverter.GetBytes(number);
81 | if (BitConverter.IsLittleEndian)
82 | Array.Reverse(bytes);
83 | return bytes;
84 | }
85 |
86 | private static int SecondsSinceCustomEpoch()
87 | {
88 | var customEpoch = new DateTime(2021, 01, 01, 00, 00, 00, DateTimeKind.Utc);
89 | var diff = DateTime.UtcNow.Subtract(customEpoch);
90 | return (int)diff.TotalSeconds;
91 | }
92 |
93 | private static byte[] MacAddress()
94 | {
95 | foreach (var nic in NetworkInterface.GetAllNetworkInterfaces())
96 | {
97 | if (nic.OperationalStatus == OperationalStatus.Up)
98 | {
99 | if (nic.Name.StartsWith("lo"))
100 | {
101 | continue;
102 | }
103 | Logger.Debug($"NIC={nic.Name}");
104 | return nic.GetPhysicalAddress().GetAddressBytes();
105 | }
106 | }
107 | return null;
108 | }
109 |
110 | public string Next()
111 | {
112 | byte[] data = new byte[18];
113 | Array.Copy(version, 0, data, 0, 2);
114 | Array.Copy(macAddress, 0, data, 2, 6);
115 | Array.Copy(pidBytes, 2, data, 8, 2);
116 | int second = SecondsSinceCustomEpoch();
117 | if (second != currentSecond)
118 | {
119 | currentSecond = second;
120 | Interlocked.Exchange(ref sequenceInSecond, 0);
121 | }
122 | byte[] secondBytes = ToArray(second);
123 | Array.Copy(secondBytes, 0, data, 10, 4);
124 | int sequence = Interlocked.Increment(ref sequenceInSecond);
125 | byte[] sequenceBytes = ToArray(sequence);
126 | Array.Copy(sequenceBytes, 0, data, 14, 4);
127 | return BitConverter.ToString(data).Replace("-", ""); ;
128 | }
129 | }
130 |
131 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Session.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Threading;
19 | using System.Threading.Channels;
20 | using System.Threading.Tasks;
21 | using grpc = global::Grpc.Core;
22 | using NLog;
23 | using rmq = Apache.Rocketmq.V2;
24 |
25 | namespace Org.Apache.Rocketmq
26 | {
27 | public class Session
28 | {
29 | private static readonly Logger Logger = MqLogManager.Instance.GetCurrentClassLogger();
30 |
31 | public Session(string target,
32 | grpc::AsyncDuplexStreamingCall stream,
33 | IClient client)
34 | {
35 | this._target = target;
36 | this._stream = stream;
37 | this._client = client;
38 | this._channel = Channel.CreateUnbounded();
39 | }
40 |
41 | public async Task Loop()
42 | {
43 | var reader = this._stream.ResponseStream;
44 | var writer = this._stream.RequestStream;
45 | var request = new rmq::TelemetryCommand();
46 | request.Settings = new rmq::Settings();
47 | _client.BuildClientSetting(request.Settings);
48 | await writer.WriteAsync(request);
49 | Logger.Debug($"Writing Client Settings Done: {request.Settings.ToString()}");
50 | while (!_client.TelemetryCts().IsCancellationRequested)
51 | {
52 | if (await reader.MoveNext(_client.TelemetryCts().Token))
53 | {
54 | var cmd = reader.Current;
55 | Logger.Debug($"Received a TelemetryCommand: {cmd.ToString()}");
56 | switch (cmd.CommandCase)
57 | {
58 | case rmq::TelemetryCommand.CommandOneofCase.None:
59 | {
60 | Logger.Warn($"Telemetry failed: {cmd.Status}");
61 | if (0 == Interlocked.CompareExchange(ref _established, 0, 2))
62 | {
63 | await _channel.Writer.WriteAsync(false);
64 | }
65 | break;
66 | }
67 | case rmq::TelemetryCommand.CommandOneofCase.Settings:
68 | {
69 | if (0 == Interlocked.CompareExchange(ref _established, 0, 1))
70 | {
71 | await _channel.Writer.WriteAsync(true);
72 | }
73 |
74 | Logger.Info($"Received settings from server {cmd.Settings.ToString()}");
75 | _client.OnSettingsReceived(cmd.Settings);
76 | break;
77 | }
78 | case rmq::TelemetryCommand.CommandOneofCase.PrintThreadStackTraceCommand:
79 | {
80 | break;
81 | }
82 | case rmq::TelemetryCommand.CommandOneofCase.RecoverOrphanedTransactionCommand:
83 | {
84 | break;
85 | }
86 | case rmq::TelemetryCommand.CommandOneofCase.VerifyMessageCommand:
87 | {
88 | break;
89 | }
90 | }
91 | }
92 | }
93 | Logger.Info("Telemetry stream cancelled");
94 | await writer.CompleteAsync();
95 | }
96 |
97 | private string _target;
98 |
99 | public string Target
100 | {
101 | get { return _target; }
102 | }
103 |
104 | public async Task AwaitSettingNegotiationCompletion()
105 | {
106 | if (0 != Interlocked.Read(ref _established))
107 | {
108 | return;
109 | }
110 |
111 | Logger.Debug("Await setting negotiation");
112 | await _channel.Reader.ReadAsync();
113 | }
114 |
115 | private grpc::AsyncDuplexStreamingCall _stream;
116 | private IClient _client;
117 |
118 | private long _established = 0;
119 |
120 | private Channel _channel;
121 | };
122 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Signature.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using System.Text;
19 | using grpc = global::Grpc.Core;
20 | using System.Security.Cryptography;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 | public class Signature
25 | {
26 | public static void sign(IClientConfig clientConfig, grpc::Metadata metadata)
27 | {
28 | metadata.Add(MetadataConstants.LANGUAGE_KEY, "DOTNET");
29 | metadata.Add(MetadataConstants.CLIENT_VERSION_KEY, "5.0.0");
30 | metadata.Add(MetadataConstants.CLIENT_ID_KEY, clientConfig.clientId());
31 | if (!String.IsNullOrEmpty(clientConfig.tenantId()))
32 | {
33 | metadata.Add(MetadataConstants.TENANT_ID_KEY, clientConfig.tenantId());
34 | }
35 |
36 | if (!String.IsNullOrEmpty(clientConfig.resourceNamespace()))
37 | {
38 | metadata.Add(MetadataConstants.NAMESPACE_KEY, clientConfig.resourceNamespace());
39 | }
40 |
41 | string time = DateTime.Now.ToString(MetadataConstants.DATE_TIME_FORMAT);
42 | metadata.Add(MetadataConstants.DATE_TIME_KEY, time);
43 |
44 | if (null != clientConfig.credentialsProvider())
45 | {
46 | var credentials = clientConfig.credentialsProvider().getCredentials();
47 | if (null == credentials || credentials.expired())
48 | {
49 | return;
50 | }
51 |
52 | if (!String.IsNullOrEmpty(credentials.SessionToken))
53 | {
54 | metadata.Add(MetadataConstants.STS_SESSION_TOKEN, credentials.SessionToken);
55 | }
56 |
57 | byte[] secretData = Encoding.ASCII.GetBytes(credentials.AccessSecret);
58 | byte[] data = Encoding.ASCII.GetBytes(time);
59 | HMACSHA1 signer = new HMACSHA1(secretData);
60 | byte[] digest = signer.ComputeHash(data);
61 | string hmac = BitConverter.ToString(digest).Replace("-", "");
62 | string authorization = string.Format("{0} {1}={2}/{3}/{4}, {5}={6}, {7}={8}",
63 | MetadataConstants.ALGORITHM_KEY,
64 | MetadataConstants.CREDENTIAL_KEY,
65 | credentials.AccessKey,
66 | clientConfig.region(),
67 | clientConfig.serviceName(),
68 | MetadataConstants.SIGNED_HEADERS_KEY,
69 | MetadataConstants.DATE_TIME_KEY,
70 | MetadataConstants.SIGNATURE_KEY,
71 | hmac);
72 | metadata.Add(MetadataConstants.AUTHORIZATION, authorization);
73 | }
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/SimpleConsumer.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using rmq = Apache.Rocketmq.V2;
20 | using System.Threading.Tasks;
21 | using System.Collections.Concurrent;
22 | using System.Threading;
23 | using Grpc.Core;
24 | using System.Collections.Generic;
25 | using System.Linq;
26 | using Google.Protobuf.WellKnownTypes;
27 |
28 | namespace Org.Apache.Rocketmq
29 | {
30 | public class SimpleConsumer : Client
31 | {
32 |
33 | public SimpleConsumer(AccessPoint accessPoint,
34 | string resourceNamespace, string group)
35 | : base(accessPoint, resourceNamespace)
36 | {
37 | _fifo = false;
38 | _subscriptions = new ConcurrentDictionary();
39 | _topicAssignments = new ConcurrentDictionary>();
40 | _group = group;
41 | }
42 |
43 | public override void BuildClientSetting(rmq::Settings settings)
44 | {
45 | base.BuildClientSetting(settings);
46 |
47 | settings.ClientType = rmq::ClientType.SimpleConsumer;
48 | settings.Subscription = new rmq::Subscription();
49 | settings.Subscription.Group = new rmq::Resource();
50 | settings.Subscription.Group.Name = _group;
51 | settings.Subscription.Group.ResourceNamespace = ResourceNamespace;
52 |
53 | foreach (var kv in _subscriptions)
54 | {
55 | settings.Subscription.Subscriptions.Add(kv.Value);
56 | }
57 | }
58 |
59 | public override async Task Start()
60 | {
61 | await base.Start();
62 |
63 | // Scan load assignment periodically
64 | schedule(async () =>
65 | {
66 | while (!_scanAssignmentCts.IsCancellationRequested)
67 | {
68 | await ScanLoadAssignments();
69 | }
70 | }, 30, _scanAssignmentCts.Token);
71 |
72 | await ScanLoadAssignments();
73 | }
74 |
75 | public override async Task Shutdown()
76 | {
77 | await base.Shutdown();
78 | if (!await NotifyClientTermination())
79 | {
80 | Logger.Warn("Failed to NotifyClientTermination");
81 | }
82 | }
83 |
84 | private async Task ScanLoadAssignments()
85 | {
86 |
87 | List>> tasks = new List>>();
88 | List topics = new List();
89 | foreach (var sub in _subscriptions)
90 | {
91 | var request = new rmq::QueryAssignmentRequest();
92 | request.Topic = new rmq::Resource();
93 | request.Topic.ResourceNamespace = ResourceNamespace;
94 | request.Topic.Name = sub.Key;
95 | topics.Add(sub.Key);
96 | request.Group = new rmq::Resource();
97 | request.Group.Name = _group;
98 | request.Group.ResourceNamespace = ResourceNamespace;
99 |
100 | request.Endpoints = new rmq::Endpoints();
101 | request.Endpoints.Scheme = rmq.AddressScheme.Ipv4;
102 | var address = new rmq::Address();
103 | address.Host = _accessPoint.Host;
104 | address.Port = _accessPoint.Port;
105 | request.Endpoints.Addresses.Add(address);
106 |
107 | var metadata = new Metadata();
108 | Signature.sign(this, metadata);
109 | tasks.Add(Manager.QueryLoadAssignment(_accessPoint.TargetUrl(), metadata, request, TimeSpan.FromSeconds(3)));
110 | }
111 |
112 | List[] list = await Task.WhenAll(tasks);
113 |
114 | var i = 0;
115 | foreach (var assignments in list)
116 | {
117 | string topic = topics[i];
118 | if (null == assignments || 0 == assignments.Count)
119 | {
120 | Logger.Warn($"Faild to acquire assignments. Topic={topic}, Group={_group}");
121 | ++i;
122 | continue;
123 | }
124 | Logger.Debug($"Assignments received. Topic={topic}, Group={_group}");
125 | _topicAssignments.AddOrUpdate(topic, assignments, (t, prev) => assignments);
126 | ++i;
127 | }
128 | }
129 |
130 | protected override void PrepareHeartbeatData(rmq::HeartbeatRequest request)
131 | {
132 | request.ClientType = rmq::ClientType.SimpleConsumer;
133 | request.Group = new rmq::Resource();
134 | request.Group.Name = _group;
135 | request.Group.ResourceNamespace = ResourceNamespace;
136 | }
137 |
138 | public void Subscribe(string topic, rmq::FilterType filterType, string expression)
139 | {
140 | var entry = new rmq::SubscriptionEntry();
141 | entry.Topic = new rmq::Resource();
142 | entry.Topic.Name = topic;
143 | entry.Topic.ResourceNamespace = ResourceNamespace;
144 | entry.Expression = new rmq::FilterExpression();
145 | entry.Expression.Type = filterType;
146 | entry.Expression.Expression = expression;
147 | _subscriptions.AddOrUpdate(topic, entry, (k, prev) => entry);
148 | AddTopicOfInterest(topic);
149 | }
150 |
151 | public override void OnSettingsReceived(rmq.Settings settings)
152 | {
153 | base.OnSettingsReceived(settings);
154 |
155 | if (settings.Subscription.Fifo)
156 | {
157 | _fifo = true;
158 | Logger.Info($"#OnSettingsReceived: Group {_group} is FIFO");
159 | }
160 | }
161 |
162 | public async Task> Receive(int batchSize, TimeSpan timeout)
163 | {
164 | var messageQueue = NextQueue();
165 | if (null == messageQueue)
166 | {
167 | Logger.Debug("NextQueue returned null");
168 | return new List();
169 | }
170 |
171 | var request = new rmq.ReceiveMessageRequest();
172 | request.Group = new rmq.Resource();
173 | request.Group.ResourceNamespace = ResourceNamespace;
174 | request.Group.Name = _group;
175 |
176 | request.MessageQueue = new rmq.MessageQueue();
177 | request.MessageQueue.MergeFrom(messageQueue);
178 | request.BatchSize = batchSize;
179 |
180 | // Client is responsible of extending message invisibility duration
181 | request.AutoRenew = false;
182 |
183 | var targetUrl = Utilities.TargetUrl(messageQueue);
184 | var metadata = new Metadata();
185 | Signature.sign(this, metadata);
186 |
187 | return await Manager.ReceiveMessage(targetUrl, metadata, request, timeout);
188 | }
189 |
190 |
191 | public async Task Ack(Message message)
192 | {
193 | var request = new rmq.AckMessageRequest();
194 | request.Group = new rmq.Resource();
195 | request.Group.ResourceNamespace = ResourceNamespace;
196 | request.Group.Name = _group;
197 |
198 | request.Topic = new rmq.Resource();
199 | request.Topic.ResourceNamespace = ResourceNamespace;
200 | request.Topic.Name = message.Topic;
201 |
202 | var entry = new rmq.AckMessageEntry();
203 | request.Entries.Add(entry);
204 | entry.MessageId = message.MessageId;
205 | entry.ReceiptHandle = message._receiptHandle;
206 |
207 | var targetUrl = message._sourceHost;
208 | var metadata = new Metadata();
209 | Signature.sign(this, metadata);
210 | await Manager.Ack(targetUrl, metadata, request, RequestTimeout);
211 | }
212 |
213 | public async Task ChangeInvisibleDuration(Message message, TimeSpan invisibleDuration)
214 | {
215 | var request = new rmq.ChangeInvisibleDurationRequest();
216 | request.Group = new rmq.Resource();
217 | request.Group.ResourceNamespace = ResourceNamespace;
218 | request.Group.Name = _group;
219 |
220 | request.Topic = new rmq.Resource();
221 | request.Topic.ResourceNamespace = ResourceNamespace;
222 | request.Topic.Name = message.Topic;
223 |
224 | request.ReceiptHandle = message._receiptHandle;
225 | request.MessageId = message.MessageId;
226 |
227 | request.InvisibleDuration = Duration.FromTimeSpan(invisibleDuration);
228 |
229 | var targetUrl = message._sourceHost;
230 | var metadata = new Metadata();
231 | Signature.sign(this, metadata);
232 | await Manager.ChangeInvisibleDuration(targetUrl, metadata, request, RequestTimeout);
233 | }
234 |
235 | private rmq.MessageQueue NextQueue()
236 | {
237 | if (_topicAssignments.IsEmpty)
238 | {
239 | return null;
240 | }
241 |
242 | UInt32 topicSeq = CurrentTopicSequence.Value;
243 | CurrentTopicSequence.Value = topicSeq + 1;
244 |
245 | var total = _topicAssignments.Count;
246 | var topicIndex = topicSeq % total;
247 | var topic = _topicAssignments.Keys.Skip((int)topicIndex).First();
248 |
249 | UInt32 queueSeq = CurrentQueueSequence.Value;
250 | CurrentQueueSequence.Value = queueSeq + 1;
251 | List assignments;
252 | if (_topicAssignments.TryGetValue(topic, out assignments))
253 | {
254 | if (null == assignments)
255 | {
256 | return null;
257 | }
258 | var idx = queueSeq % assignments.Count;
259 | return assignments[(int)idx].MessageQueue;
260 |
261 | }
262 |
263 | return null;
264 | }
265 |
266 | private ThreadLocal CurrentTopicSequence = new ThreadLocal(true);
267 | private ThreadLocal CurrentQueueSequence = new ThreadLocal(true);
268 |
269 | private readonly string _group;
270 | private bool _fifo;
271 | private readonly ConcurrentDictionary _subscriptions;
272 | private readonly ConcurrentDictionary> _topicAssignments;
273 | private readonly CancellationTokenSource _scanAssignmentCts = new CancellationTokenSource();
274 | }
275 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/StaticCredentialsProvider.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | namespace Org.Apache.Rocketmq
18 | {
19 | public class StaticCredentialsProvider : ICredentialsProvider
20 | {
21 |
22 | public StaticCredentialsProvider(string accessKey, string accessSecret)
23 | {
24 | this.accessKey = accessKey;
25 | this.accessSecret = accessSecret;
26 | }
27 |
28 | public Credentials getCredentials()
29 | {
30 | return new Credentials(accessKey, accessSecret);
31 | }
32 |
33 | private string accessKey;
34 | private string accessSecret;
35 | }
36 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Topic.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | public class Topic : IComparable, IEquatable
23 | {
24 | public Topic(string resourceNamespace, string name)
25 | {
26 | ResourceNamespace = resourceNamespace;
27 | Name = name;
28 | }
29 |
30 | public string ResourceNamespace { get; }
31 | public string Name { get; }
32 |
33 | public bool Equals(Topic other)
34 | {
35 | if (ReferenceEquals(null, other))
36 | {
37 | return false;
38 | }
39 |
40 | if (ReferenceEquals(this, other))
41 | {
42 | return true;
43 | }
44 |
45 | return ResourceNamespace == other.ResourceNamespace && Name == other.Name;
46 | }
47 |
48 | public override bool Equals(object obj)
49 | {
50 | if (ReferenceEquals(null, obj) || obj.GetType() != GetType())
51 | {
52 | return false;
53 | }
54 |
55 | if (ReferenceEquals(this, obj))
56 | {
57 | return true;
58 | }
59 |
60 | return Equals((Topic)obj);
61 | }
62 |
63 | public override int GetHashCode()
64 | {
65 | return HashCode.Combine(ResourceNamespace, Name);
66 | }
67 |
68 | public int CompareTo(Topic other)
69 | {
70 | if (ReferenceEquals(null, other))
71 | {
72 | return -1;
73 | }
74 |
75 | var compareTo = String.CompareOrdinal(ResourceNamespace, other.ResourceNamespace);
76 | if (0 == compareTo)
77 | {
78 | compareTo = String.CompareOrdinal(Name, other.Name);
79 | }
80 |
81 | return compareTo;
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/TopicRouteData.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Collections.Generic;
20 | using rmq = Apache.Rocketmq.V2;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 | public class TopicRouteData : IEquatable
25 | {
26 | public TopicRouteData(List partitions)
27 | {
28 | _messageQueues = partitions;
29 |
30 | _messageQueues.Sort(Utilities.CompareMessageQueue);
31 | }
32 |
33 | private List _messageQueues;
34 | public List MessageQueues { get { return _messageQueues; } }
35 |
36 | public bool Equals(TopicRouteData other)
37 | {
38 | if (ReferenceEquals(null, other)) return false;
39 | if (ReferenceEquals(this, other)) return true;
40 | return Equals(_messageQueues, other._messageQueues);
41 | }
42 |
43 | public override bool Equals(object obj)
44 | {
45 | if (ReferenceEquals(null, obj)) return false;
46 | if (ReferenceEquals(this, obj)) return true;
47 | if (obj.GetType() != this.GetType()) return false;
48 | return Equals((TopicRouteData)obj);
49 | }
50 |
51 | public override int GetHashCode()
52 | {
53 | return (_messageQueues != null ? _messageQueues.GetHashCode() : 0);
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/TopicRouteException.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | namespace Org.Apache.Rocketmq
19 | {
20 | public class TopicRouteException : Exception
21 | {
22 | public TopicRouteException(string message) : base(message)
23 | {
24 |
25 | }
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/Utilities.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System.Diagnostics;
19 | using System.Linq;
20 | using System.Net.NetworkInformation;
21 | using System.Text;
22 | using System;
23 | using rmq = Apache.Rocketmq.V2;
24 |
25 | namespace Org.Apache.Rocketmq
26 | {
27 | public static class Utilities
28 | {
29 | public static byte[] GetMacAddress()
30 | {
31 | return NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(nic =>
32 | nic.OperationalStatus == OperationalStatus.Up &&
33 | nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)?.GetPhysicalAddress().GetAddressBytes();
34 | }
35 |
36 | public static int GetProcessId()
37 | {
38 | return Process.GetCurrentProcess().Id;
39 | }
40 |
41 | public static string ByteArrayToHexString(byte[] bytes)
42 | {
43 | StringBuilder result = new StringBuilder(bytes.Length * 2);
44 | const string hexAlphabet = "0123456789ABCDEF";
45 |
46 | foreach (byte b in bytes)
47 | {
48 | result.Append(hexAlphabet[(int)(b >> 4)]);
49 | result.Append(hexAlphabet[(int)(b & 0xF)]);
50 | }
51 |
52 | return result.ToString();
53 | }
54 |
55 | public static string TargetUrl(rmq::MessageQueue messageQueue)
56 | {
57 | // TODO: Assert associated broker has as least one service endpoint.
58 | var serviceEndpoint = messageQueue.Broker.Endpoints.Addresses[0];
59 | return $"https://{serviceEndpoint.Host}:{serviceEndpoint.Port}";
60 | }
61 |
62 | public static int CompareMessageQueue(rmq::MessageQueue lhs, rmq::MessageQueue rhs)
63 | {
64 | int topic_comparison = String.Compare(lhs.Topic.ResourceNamespace + lhs.Topic.Name, rhs.Topic.ResourceNamespace + rhs.Topic.Name);
65 | if (topic_comparison != 0)
66 | {
67 | return topic_comparison;
68 | }
69 |
70 | int broker_name_comparison = String.Compare(lhs.Broker.Name, rhs.Broker.Name);
71 | if (0 != broker_name_comparison)
72 | {
73 | return broker_name_comparison;
74 | }
75 |
76 | return lhs.Id < rhs.Id ? -1 : (lhs.Id == rhs.Id ? 0 : 1);
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/rocketmq-client-csharp/rocketmq-client-csharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RocketMQ-Client-CSharp
5 | 1.0.0
6 | Zhanhui Li
7 | Apache Software Foundation
8 | net5.0
9 | Org.Apache.Rocketmq
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 | all
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Protos\apache\rocketmq\v2\definition.proto
32 | Protos\google\rpc\status.proto
33 | Protos\google\rpc\error_details.proto
34 |
35 |
36 |
37 |
38 |
39 | Always
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/rocketmq-client-csharp/rocketmq-client-csharp.nlog:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/rocketmq-client.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "rocketmq-client-csharp", "rocketmq-client-csharp\rocketmq-client-csharp.csproj", "{7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "examples", "examples\examples.csproj", "{9F749350-A3D0-423E-AFB6-79E521C777D0}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{92248517-D1FD-4C65-A691-647C696B9F85}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Debug|x64 = Debug|x64
16 | Debug|x86 = Debug|x86
17 | Release|Any CPU = Release|Any CPU
18 | Release|x64 = Release|x64
19 | Release|x86 = Release|x86
20 | EndGlobalSection
21 | GlobalSection(SolutionProperties) = preSolution
22 | HideSolutionNode = FALSE
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Debug|x64.ActiveCfg = Debug|Any CPU
28 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Debug|x64.Build.0 = Debug|Any CPU
29 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Debug|x86.ActiveCfg = Debug|Any CPU
30 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Debug|x86.Build.0 = Debug|Any CPU
31 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Release|x64.ActiveCfg = Release|Any CPU
34 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Release|x64.Build.0 = Release|Any CPU
35 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Release|x86.ActiveCfg = Release|Any CPU
36 | {7BD84605-FDC5-4B47-8D5D-A9EEADA0EA99}.Release|x86.Build.0 = Release|Any CPU
37 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Debug|x64.ActiveCfg = Debug|Any CPU
40 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Debug|x64.Build.0 = Debug|Any CPU
41 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Debug|x86.ActiveCfg = Debug|Any CPU
42 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Debug|x86.Build.0 = Debug|Any CPU
43 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Release|x64.ActiveCfg = Release|Any CPU
46 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Release|x64.Build.0 = Release|Any CPU
47 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Release|x86.ActiveCfg = Release|Any CPU
48 | {9F749350-A3D0-423E-AFB6-79E521C777D0}.Release|x86.Build.0 = Release|Any CPU
49 | {92248517-D1FD-4C65-A691-647C696B9F85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {92248517-D1FD-4C65-A691-647C696B9F85}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {92248517-D1FD-4C65-A691-647C696B9F85}.Debug|x64.ActiveCfg = Debug|Any CPU
52 | {92248517-D1FD-4C65-A691-647C696B9F85}.Debug|x64.Build.0 = Debug|Any CPU
53 | {92248517-D1FD-4C65-A691-647C696B9F85}.Debug|x86.ActiveCfg = Debug|Any CPU
54 | {92248517-D1FD-4C65-A691-647C696B9F85}.Debug|x86.Build.0 = Debug|Any CPU
55 | {92248517-D1FD-4C65-A691-647C696B9F85}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {92248517-D1FD-4C65-A691-647C696B9F85}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {92248517-D1FD-4C65-A691-647C696B9F85}.Release|x64.ActiveCfg = Release|Any CPU
58 | {92248517-D1FD-4C65-A691-647C696B9F85}.Release|x64.Build.0 = Release|Any CPU
59 | {92248517-D1FD-4C65-A691-647C696B9F85}.Release|x86.ActiveCfg = Release|Any CPU
60 | {92248517-D1FD-4C65-A691-647C696B9F85}.Release|x86.Build.0 = Release|Any CPU
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/tests/ClientConfigTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | [TestClass]
23 | public class ClientConfigTest
24 | {
25 | [TestMethod]
26 | public void testClientId()
27 | {
28 | var clientConfig = new ClientConfig();
29 | string clientId = clientConfig.clientId();
30 | Assert.IsTrue(clientId.Contains("@"));
31 | Assert.IsTrue(clientId.Contains("#default"));
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/tests/ClientManagerTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using System;
18 | using Grpc.Core;
19 | using Microsoft.VisualStudio.TestTools.UnitTesting;
20 | using rmq = Apache.Rocketmq.V2;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 |
25 | [TestClass]
26 | public class ClientManagerTest
27 | {
28 |
29 | [TestMethod]
30 | public void TestResolveRoute()
31 | {
32 | string topic = "cpp_sdk_standard";
33 | string resourceNamespace = "MQ_INST_1080056302921134_BXuIbML7";
34 | var request = new rmq::QueryRouteRequest();
35 | request.Topic = new rmq::Resource();
36 | request.Topic.ResourceNamespace = resourceNamespace;
37 | request.Topic.Name = topic;
38 | request.Endpoints = new rmq::Endpoints();
39 | request.Endpoints.Scheme = rmq::AddressScheme.Ipv4;
40 | var address = new rmq::Address();
41 | address.Host = "116.62.231.199";
42 | address.Port = 80;
43 | request.Endpoints.Addresses.Add(address);
44 |
45 | var metadata = new Metadata();
46 | var clientConfig = new ClientConfig();
47 | var credentialsProvider = new ConfigFileCredentialsProvider();
48 | clientConfig.CredentialsProvider = credentialsProvider;
49 | clientConfig.ResourceNamespace = resourceNamespace;
50 | clientConfig.Region = "cn-hangzhou-pre";
51 | Signature.sign(clientConfig, metadata);
52 | var clientManager = new ClientManager();
53 | string target = "https://116.62.231.199:80";
54 | var topicRouteData = clientManager.ResolveRoute(target, metadata, request, TimeSpan.FromSeconds(3)).GetAwaiter().GetResult();
55 | Console.WriteLine(topicRouteData);
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/tests/ConfigFileCredentialsProviderTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using Microsoft.VisualStudio.TestTools.UnitTesting;
19 | using System;
20 |
21 | namespace Org.Apache.Rocketmq
22 | {
23 | [TestClass]
24 | public class ConfigFileCredentialsProviderTest
25 | {
26 | [TestMethod]
27 | public void testGetCredentials()
28 | {
29 | var provider = new ConfigFileCredentialsProvider();
30 | var credentials = provider.getCredentials();
31 | Assert.IsNotNull(credentials);
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/tests/DateTimeTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 |
23 | [TestClass]
24 | public class DateTimeTest
25 | {
26 |
27 | [TestMethod]
28 | public void testFormat()
29 | {
30 | DateTime instant = new DateTime(2022, 02, 15, 08, 31, 56);
31 | string time = instant.ToString(MetadataConstants.DATE_TIME_FORMAT);
32 | string expected = "20220215T083156Z";
33 | Assert.AreEqual(time, expected);
34 | }
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/tests/MessageIdGeneratorTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using Microsoft.VisualStudio.TestTools.UnitTesting;
19 | using Org.Apache.Rocketmq;
20 |
21 | namespace tests
22 | {
23 | [TestClass]
24 | public class MessageIdGeneratorTest
25 | {
26 | [TestMethod]
27 | public void TestNext()
28 | {
29 | MessageIdGenerator instance = MessageIdGenerator.GetInstance();
30 | var firstMessageId = instance.Next();
31 | Assert.AreEqual(34, firstMessageId.Length);
32 | Assert.AreEqual(MessageIdGenerator.version, firstMessageId.Substring(0, 2));
33 |
34 | var secondMessageId = instance.Next();
35 | Assert.AreEqual(34, secondMessageId.Length);
36 | Assert.AreEqual(MessageIdGenerator.version, secondMessageId.Substring(0, 2));
37 |
38 | Assert.AreNotEqual(firstMessageId, secondMessageId);
39 | Assert.AreEqual(firstMessageId.Substring(0, 24), secondMessageId.Substring(0, 24));
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/tests/MessageTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System;
19 | using System.Text;
20 | using System.Collections.Generic;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 | [TestClass]
25 | public class MessageTest
26 | {
27 |
28 | [TestMethod]
29 | public void testCtor()
30 | {
31 | var msg1 = new Message();
32 | Assert.IsNotNull(msg1.MessageId);
33 | Assert.IsTrue(msg1.MessageId.StartsWith("01"));
34 | Assert.IsNull(msg1.Topic);
35 | Assert.IsNull(msg1.Body);
36 | Assert.IsNull(msg1.Tag);
37 | Assert.AreEqual(msg1.Keys.Count, 0);
38 | Assert.AreEqual(msg1.UserProperties.Count, 0);
39 | }
40 |
41 | [TestMethod]
42 | public void testCtor2()
43 | {
44 | string topic = "T1";
45 | string bodyString = "body";
46 | byte[] body = Encoding.ASCII.GetBytes(bodyString);
47 | var msg1 = new Message(topic, body);
48 | Assert.AreEqual(msg1.Topic, topic);
49 | Assert.AreEqual(msg1.Body, body);
50 | Assert.IsNull(msg1.Tag);
51 | Assert.AreEqual(msg1.Keys.Count, 0);
52 | Assert.AreEqual(msg1.UserProperties.Count, 0);
53 | }
54 |
55 | [TestMethod]
56 | public void testCtor3()
57 | {
58 | string topic = "T1";
59 | string bodyString = "body";
60 | byte[] body = Encoding.ASCII.GetBytes(bodyString);
61 | string tag = "TagA";
62 | var msg1 = new Message(topic, tag, body);
63 | Assert.AreEqual(msg1.Topic, topic);
64 | Assert.AreEqual(msg1.Body, body);
65 | Assert.AreEqual(msg1.Tag, tag);
66 | Assert.AreEqual(msg1.Keys.Count, 0);
67 | Assert.AreEqual(msg1.UserProperties.Count, 0);
68 | }
69 |
70 | [TestMethod]
71 | public void testCtor4()
72 | {
73 | string topic = "T1";
74 | string bodyString = "body";
75 | byte[] body = Encoding.ASCII.GetBytes(bodyString);
76 | string tag = "TagA";
77 | List keys = new List();
78 | keys.Add("Key1");
79 | keys.Add("Key2");
80 |
81 | var msg1 = new Message(topic, tag, keys, body);
82 | Assert.AreEqual(msg1.Topic, topic);
83 | Assert.AreEqual(msg1.Body, body);
84 | Assert.AreEqual(msg1.Tag, tag);
85 | Assert.AreEqual(msg1.Keys, keys);
86 | Assert.AreEqual(msg1.UserProperties.Count, 0);
87 | }
88 |
89 | [TestMethod]
90 | public void testCtor5()
91 | {
92 | string topic = "T1";
93 | string bodyString = "body";
94 | byte[] body = Encoding.ASCII.GetBytes(bodyString);
95 | string tag = "TagA";
96 | List keys = new List();
97 | keys.Add("Key1");
98 | keys.Add("Key2");
99 |
100 | var msg1 = new Message(topic, tag, keys, body);
101 |
102 | msg1.UserProperties.Add("k", "v");
103 | msg1.UserProperties.Add("k2", "v2");
104 |
105 | Assert.AreEqual(msg1.Topic, topic);
106 | Assert.AreEqual(msg1.Body, body);
107 | Assert.AreEqual(msg1.Tag, tag);
108 | Assert.AreEqual(msg1.Keys, keys);
109 | Assert.AreEqual(msg1.UserProperties.Count, 2);
110 |
111 | string value;
112 | msg1.UserProperties.TryGetValue("k", out value);
113 | Assert.AreEqual(value, "v");
114 |
115 | msg1.UserProperties.TryGetValue("k2", out value);
116 | Assert.AreEqual(value, "v2");
117 |
118 | }
119 |
120 | }
121 | }
--------------------------------------------------------------------------------
/tests/MqLogManagerTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using NLog;
4 | using Org.Apache.Rocketmq;
5 |
6 | namespace tests
7 | {
8 | [TestClass]
9 | public class MqLogManagerTest
10 | {
11 | private static readonly Logger Logger = MqLogManager.Instance.GetCurrentClassLogger();
12 |
13 | [TestMethod]
14 | public void TestLog()
15 | {
16 | Logger.Trace("This is a trace message.");
17 | Logger.Debug("This is a debug message.");
18 | Logger.Info("This is an info message.");
19 | Logger.Warn("This is a warn message.");
20 | Logger.Error("This is an error message.");
21 | Logger.Fatal("This is a fatal message.");
22 |
23 | Logger.Error(new Exception("foobar"), "this is an error message with exception.");
24 | Logger.Fatal(new Exception("foobar"), "this is a fatal message with exception.");
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/ProducerTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Threading.Tasks;
21 | using Org.Apache.Rocketmq;
22 |
23 |
24 | namespace tests
25 | {
26 | [TestClass]
27 | public class ProducerTest
28 | {
29 |
30 | private static AccessPoint _accessPoint;
31 |
32 | [ClassInitialize]
33 | public static void SetUp(TestContext context)
34 | {
35 | _accessPoint = new AccessPoint
36 | {
37 | Host = HOST,
38 | Port = PORT
39 | };
40 | }
41 |
42 | [ClassCleanup]
43 | public static void TearDown()
44 | {
45 | }
46 |
47 | [TestMethod]
48 | public async Task TestLifecycle()
49 | {
50 | var producer = new Producer(_accessPoint, resourceNamespace);
51 | producer.CredentialsProvider = new ConfigFileCredentialsProvider();
52 | producer.Region = "cn-hangzhou-pre";
53 | await producer.Start();
54 | await producer.Shutdown();
55 | }
56 |
57 | [TestMethod]
58 | public async Task TestSendStandardMessage()
59 | {
60 | var producer = new Producer(_accessPoint, resourceNamespace);
61 | producer.CredentialsProvider = new ConfigFileCredentialsProvider();
62 | producer.Region = "cn-hangzhou-pre";
63 | await producer.Start();
64 | byte[] body = new byte[1024];
65 | Array.Fill(body, (byte)'x');
66 | var msg = new Message(topic, body);
67 |
68 | // Tag the massage. A message has at most one tag.
69 | msg.Tag = "Tag-0";
70 |
71 | // Associate the message with one or multiple keys
72 | var keys = new List();
73 | keys.Add("k1");
74 | keys.Add("k2");
75 | msg.Keys = keys;
76 |
77 | var sendResult = await producer.Send(msg);
78 | Assert.IsNotNull(sendResult);
79 | await producer.Shutdown();
80 | }
81 |
82 | [TestMethod]
83 | public async Task TestSendMultipleMessages()
84 | {
85 | var producer = new Producer(_accessPoint, resourceNamespace);
86 | producer.CredentialsProvider = new ConfigFileCredentialsProvider();
87 | producer.Region = "cn-hangzhou-pre";
88 | await producer.Start();
89 | byte[] body = new byte[1024];
90 | Array.Fill(body, (byte)'x');
91 | for (var i = 0; i < 128; i++)
92 | {
93 | var msg = new Message(topic, body);
94 |
95 | // Tag the massage. A message has at most one tag.
96 | msg.Tag = "Tag-0";
97 |
98 | // Associate the message with one or multiple keys
99 | var keys = new List();
100 | keys.Add("k1");
101 | keys.Add("k2");
102 | msg.Keys = keys;
103 | var sendResult = await producer.Send(msg);
104 | Assert.IsNotNull(sendResult);
105 | }
106 | await producer.Shutdown();
107 | }
108 |
109 | [TestMethod]
110 | public async Task TestSendFifoMessage()
111 | {
112 | var producer = new Producer(_accessPoint, resourceNamespace);
113 | producer.CredentialsProvider = new ConfigFileCredentialsProvider();
114 | producer.Region = "cn-hangzhou-pre";
115 | await producer.Start();
116 | byte[] body = new byte[1024];
117 | Array.Fill(body, (byte)'x');
118 | var msg = new Message(topic, body);
119 |
120 | // Messages of the same group will get delivered one after another.
121 | msg.MessageGroup = "message-group-0";
122 |
123 | // Verify messages are FIFO iff their message group is not null or empty.
124 | Assert.IsTrue(msg.Fifo());
125 |
126 | var sendResult = await producer.Send(msg);
127 | Assert.IsNotNull(sendResult);
128 | await producer.Shutdown();
129 | }
130 |
131 | [TestMethod]
132 | public async Task TestSendScheduledMessage()
133 | {
134 | var producer = new Producer(_accessPoint, resourceNamespace);
135 | producer.CredentialsProvider = new ConfigFileCredentialsProvider();
136 | producer.Region = "cn-hangzhou-pre";
137 | await producer.Start();
138 | byte[] body = new byte[1024];
139 | Array.Fill(body, (byte)'x');
140 | var msg = new Message(topic, body);
141 |
142 | msg.DeliveryTimestamp = DateTime.UtcNow + TimeSpan.FromSeconds(10);
143 | Assert.IsTrue(msg.Scheduled());
144 |
145 | var sendResult = await producer.Send(msg);
146 | Assert.IsNotNull(sendResult);
147 | await producer.Shutdown();
148 | }
149 |
150 |
151 | /**
152 | * Trying send a message that is both FIFO and Scheduled should fail.
153 | */
154 | [TestMethod]
155 | public async Task TestSendMessage_Failure()
156 | {
157 | var producer = new Producer(_accessPoint, resourceNamespace);
158 | producer.CredentialsProvider = new ConfigFileCredentialsProvider();
159 | producer.Region = "cn-hangzhou-pre";
160 | await producer.Start();
161 | byte[] body = new byte[1024];
162 | Array.Fill(body, (byte)'x');
163 | var msg = new Message(topic, body);
164 | msg.MessageGroup = "Group-0";
165 | msg.DeliveryTimestamp = DateTime.UtcNow + TimeSpan.FromSeconds(10);
166 | Assert.IsTrue(msg.Scheduled());
167 |
168 | try
169 | {
170 | await producer.Send(msg);
171 | Assert.Fail("Should have raised an exception");
172 | }
173 | catch (MessageException e)
174 | {
175 | }
176 | await producer.Shutdown();
177 | }
178 |
179 | private static string resourceNamespace = "";
180 |
181 | private static string topic = "cpp_sdk_standard";
182 |
183 | private static string HOST = "127.0.0.1";
184 | private static int PORT = 8081;
185 | }
186 |
187 | }
--------------------------------------------------------------------------------
/tests/PushConsumerTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System.Collections.Generic;
19 | using System;
20 | using System.Threading.Tasks;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 |
25 | public class TestMessageListener : IMessageListener
26 | {
27 | public Task Consume(List messages, List failed)
28 | {
29 | foreach (var message in messages)
30 | {
31 | Console.WriteLine("");
32 | }
33 |
34 | return Task.CompletedTask;
35 | }
36 | }
37 |
38 | public class CountableMessageListener : IMessageListener
39 | {
40 | public Task Consume(List messages, List failed)
41 | {
42 | foreach (var message in messages)
43 | {
44 | Console.WriteLine("{}", message.MessageId);
45 | }
46 |
47 | return Task.CompletedTask;
48 | }
49 | }
50 |
51 | [TestClass]
52 | public class PushConsumerTest
53 | {
54 |
55 | [ClassInitialize]
56 | public static void SetUp(TestContext context)
57 | {
58 | credentialsProvider = new ConfigFileCredentialsProvider();
59 |
60 | }
61 |
62 | [ClassCleanup]
63 | public static void TearDown()
64 | {
65 |
66 | }
67 |
68 | [TestInitialize]
69 | public void SetUp()
70 | {
71 | accessPoint = new AccessPoint();
72 | accessPoint.Host = host;
73 | accessPoint.Port = port;
74 | }
75 |
76 | [TestMethod]
77 | public void testLifecycle()
78 | {
79 | var consumer = new PushConsumer(accessPoint, resourceNamespace, group);
80 | consumer.CredentialsProvider = new ConfigFileCredentialsProvider();
81 | consumer.Region = "cn-hangzhou-pre";
82 | consumer.Subscribe(topic, "*", ExpressionType.TAG);
83 | consumer.RegisterListener(new TestMessageListener());
84 | consumer.Start();
85 |
86 | consumer.Shutdown();
87 | }
88 |
89 |
90 | // [Ignore]
91 | [TestMethod]
92 | public void testConsumeMessage()
93 | {
94 | var consumer = new PushConsumer(accessPoint, resourceNamespace, group);
95 | consumer.CredentialsProvider = new ConfigFileCredentialsProvider();
96 | consumer.Region = "cn-hangzhou-pre";
97 | consumer.Subscribe(topic, "*", ExpressionType.TAG);
98 | consumer.RegisterListener(new CountableMessageListener());
99 | consumer.Start();
100 | System.Threading.Thread.Sleep(System.TimeSpan.FromSeconds(300));
101 | consumer.Shutdown();
102 | }
103 |
104 |
105 | private static string resourceNamespace = "MQ_INST_1080056302921134_BXuIbML7";
106 |
107 | private static string topic = "cpp_sdk_standard";
108 |
109 | private static string group = "GID_cpp_sdk_standard";
110 |
111 | private static ICredentialsProvider credentialsProvider;
112 | private static string host = "116.62.231.199";
113 | private static int port = 80;
114 |
115 | private AccessPoint accessPoint;
116 |
117 | }
118 |
119 | }
--------------------------------------------------------------------------------
/tests/RpcClientTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System;
19 | using System.Text;
20 | using System.Threading;
21 | using System.Threading.Tasks;
22 | using System.Collections.Generic;
23 | using grpc = Grpc.Core;
24 | using rmq = Apache.Rocketmq.V2;
25 |
26 |
27 | namespace Org.Apache.Rocketmq
28 | {
29 |
30 | [TestClass]
31 | public class RpcClientTest
32 | {
33 |
34 | [TestMethod]
35 | public async Task testTelemetry()
36 | {
37 | Console.WriteLine("Test Telemetry streaming");
38 | string target = "https://11.166.42.94:8081";
39 | var rpc_client = new RpcClient(target);
40 | var client_config = new ClientConfig();
41 | var metadata = new grpc::Metadata();
42 | Signature.sign(client_config, metadata);
43 |
44 | var cmd = new rmq::TelemetryCommand();
45 | cmd.Settings = new rmq::Settings();
46 | cmd.Settings.ClientType = rmq::ClientType.Producer;
47 | cmd.Settings.AccessPoint = new rmq::Endpoints();
48 | cmd.Settings.AccessPoint.Scheme = rmq::AddressScheme.Ipv4;
49 | var address = new rmq::Address();
50 | address.Port = 8081;
51 | address.Host = "11.166.42.94";
52 | cmd.Settings.AccessPoint.Addresses.Add(address);
53 | cmd.Settings.RequestTimeout = new Google.Protobuf.WellKnownTypes.Duration();
54 | cmd.Settings.RequestTimeout.Seconds = 3;
55 | cmd.Settings.RequestTimeout.Nanos = 0;
56 | cmd.Settings.Publishing = new rmq::Publishing();
57 | var topic = new rmq::Resource();
58 | topic.Name = "cpp_sdk_standard";
59 | cmd.Settings.Publishing.Topics.Add(topic);
60 | cmd.Settings.UserAgent = new rmq::UA();
61 | cmd.Settings.UserAgent.Language = rmq::Language.DotNet;
62 | cmd.Settings.UserAgent.Version = "1.0";
63 | cmd.Settings.UserAgent.Hostname = System.Net.Dns.GetHostName();
64 | cmd.Settings.UserAgent.Platform = System.Environment.OSVersion.ToString();
65 |
66 | var duplexStreaming = rpc_client.Telemetry(metadata);
67 | var reader = duplexStreaming.ResponseStream;
68 | var writer = duplexStreaming.RequestStream;
69 |
70 | var cts = new CancellationTokenSource();
71 | await writer.WriteAsync(cmd);
72 | Console.WriteLine("Command written");
73 | if (await reader.MoveNext(cts.Token))
74 | {
75 | var response = reader.Current;
76 | switch (response.CommandCase)
77 | {
78 | case rmq::TelemetryCommand.CommandOneofCase.Settings:
79 | {
80 | var responded_settings = response.Settings;
81 | Console.WriteLine($"{responded_settings.ToString()}");
82 | break;
83 | }
84 | case rmq::TelemetryCommand.CommandOneofCase.None:
85 | {
86 | Console.WriteLine($"Unknown response command type: {response.Status.ToString()}");
87 | break;
88 | }
89 | }
90 | Console.WriteLine("Server responded ");
91 | }
92 | else
93 | {
94 | Console.WriteLine("Server is not responding");
95 | var status = duplexStreaming.GetStatus();
96 | Console.WriteLine($"status={status.ToString()}");
97 |
98 | var trailers = duplexStreaming.GetTrailers();
99 | Console.WriteLine($"trailers={trailers.ToString()}");
100 | }
101 | }
102 |
103 | [TestMethod]
104 | public void testQueryRoute()
105 | {
106 | string target = "https://11.166.42.94:8081";
107 | var rpc_client = new RpcClient(target);
108 | var client_config = new ClientConfig();
109 | var metadata = new grpc::Metadata();
110 | Signature.sign(client_config, metadata);
111 | var request = new rmq::QueryRouteRequest();
112 | request.Topic = new rmq::Resource();
113 | request.Topic.Name = "cpp_sdk_standard";
114 | request.Endpoints = new rmq::Endpoints();
115 | request.Endpoints.Scheme = rmq::AddressScheme.Ipv4;
116 | var address = new rmq::Address();
117 | address.Port = 8081;
118 | address.Host = "11.166.42.94";
119 | request.Endpoints.Addresses.Add(address);
120 | var response = rpc_client.QueryRoute(metadata, request, client_config.RequestTimeout);
121 | var result = response.GetAwaiter().GetResult();
122 | }
123 |
124 | [TestMethod]
125 | public async Task TestSend()
126 | {
127 | string target = "https://11.166.42.94:8081";
128 | var rpc_client = new RpcClient(target);
129 | var client_config = new ClientConfig();
130 | var metadata = new grpc::Metadata();
131 | Signature.sign(client_config, metadata);
132 |
133 | var request = new rmq::SendMessageRequest();
134 | var message = new rmq::Message();
135 | message.Topic = new rmq::Resource();
136 | message.Topic.Name = "cpp_sdk_standard";
137 | message.Body = Google.Protobuf.ByteString.CopyFromUtf8("Test Body");
138 | message.SystemProperties = new rmq::SystemProperties();
139 | message.SystemProperties.Tag = "TagA";
140 | message.SystemProperties.MessageId = "abc";
141 | request.Messages.Add(message);
142 | var response = await rpc_client.SendMessage(metadata, request, TimeSpan.FromSeconds(3));
143 | Assert.AreEqual(rmq::Code.Ok, response.Status.Code);
144 | }
145 | }
146 | }
--------------------------------------------------------------------------------
/tests/SendResultTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using Microsoft.VisualStudio.TestTools.UnitTesting;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 |
23 | [TestClass]
24 | public class SendResultTest
25 | {
26 |
27 | [TestMethod]
28 | public void testCtor()
29 | {
30 | string messageId = new string("abc");
31 | var sendResult = new SendReceipt(messageId);
32 | Assert.AreEqual(messageId, sendResult.MessageId);
33 | Assert.AreEqual(SendStatus.SEND_OK, sendResult.Status);
34 | }
35 |
36 |
37 | [TestMethod]
38 | public void testCtor2()
39 | {
40 | string messageId = new string("abc");
41 | var sendResult = new SendReceipt(messageId, SendStatus.FLUSH_DISK_TIMEOUT);
42 | Assert.AreEqual(messageId, sendResult.MessageId);
43 | Assert.AreEqual(SendStatus.FLUSH_DISK_TIMEOUT, sendResult.Status);
44 | }
45 |
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/tests/SequenceGeneratorTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 |
19 | using System;
20 | using System.Collections.Generic;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 | [TestClass]
25 | public class SequenceGeneratorTest
26 | {
27 |
28 | [ClassInitialize]
29 | public static void SetUp(TestContext context)
30 | {
31 | }
32 |
33 | [TestMethod]
34 | public void testNext()
35 | {
36 | var set = new HashSet();
37 | for (int i = 0; i < 500000; i++)
38 | {
39 | var nextId = SequenceGenerator.Instance.Next();
40 | if (set.Contains(nextId))
41 | {
42 | Assert.Fail("SequenceGenerator violates uniqueness");
43 | }
44 | set.Add(nextId);
45 | }
46 | }
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/tests/SignatureTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using grpc = global::Grpc.Core;
19 | using Moq;
20 | using System;
21 |
22 | namespace Org.Apache.Rocketmq
23 | {
24 |
25 | [TestClass]
26 | public class SignatureTest
27 | {
28 |
29 | [TestMethod]
30 | public void testSign()
31 | {
32 | var mock = new Mock();
33 | mock.Setup(x => x.getGroupName()).Returns("G1");
34 | mock.Setup(x => x.tenantId()).Returns("Tenant-id");
35 | mock.Setup(x => x.resourceNamespace()).Returns("mq:arn:test:");
36 | mock.Setup(x => x.serviceName()).Returns("mq");
37 | mock.Setup(x => x.region()).Returns("cn-hangzhou");
38 |
39 | string accessKey = "key";
40 | string accessSecret = "secret";
41 | var credentialsProvider = new StaticCredentialsProvider(accessKey, accessSecret);
42 | mock.Setup(x => x.credentialsProvider()).Returns(credentialsProvider);
43 |
44 | var metadata = new grpc::Metadata();
45 | Signature.sign(mock.Object, metadata);
46 | Assert.IsNotNull(metadata.Get(MetadataConstants.AUTHORIZATION));
47 | }
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/tests/SimpleConsumerTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | using System;
19 | using System.Threading;
20 | using Microsoft.VisualStudio.TestTools.UnitTesting;
21 | using rmq = Apache.Rocketmq.V2;
22 | using System.Threading.Tasks;
23 | using Castle.Core.Logging;
24 | using Org.Apache.Rocketmq;
25 |
26 | namespace tests
27 | {
28 |
29 | [TestClass]
30 | public class SimpleConsumerTest
31 | {
32 |
33 | private static AccessPoint accessPoint;
34 | private static string _resourceNamespace = "";
35 | private static string _group = "GID_cpp_sdk_standard";
36 | private static string _topic = "cpp_sdk_standard";
37 |
38 |
39 | [ClassInitialize]
40 | public static void SetUp(TestContext context)
41 | {
42 | accessPoint = new AccessPoint
43 | {
44 | Host = "127.0.0.1",
45 | Port = 8081
46 | };
47 | }
48 |
49 | [TestMethod]
50 | public async Task TestLifecycle()
51 | {
52 | var simpleConsumer = new SimpleConsumer(accessPoint, _resourceNamespace, _group);
53 | simpleConsumer.Subscribe(_topic, rmq::FilterType.Tag, "*");
54 | await simpleConsumer.Start();
55 | Thread.Sleep(1_000);
56 | await simpleConsumer.Shutdown();
57 | }
58 |
59 | [TestMethod]
60 | public async Task TestReceive()
61 | {
62 | var simpleConsumer = new SimpleConsumer(accessPoint, _resourceNamespace, _group);
63 | simpleConsumer.Subscribe(_topic, rmq::FilterType.Tag, "*");
64 | await simpleConsumer.Start();
65 | var batchSize = 32;
66 | var receiveTimeout = TimeSpan.FromSeconds(10);
67 | var messages = await simpleConsumer.Receive(batchSize, receiveTimeout);
68 | Assert.IsTrue(messages.Count > 0);
69 | Assert.IsTrue(messages.Count <= batchSize);
70 | await simpleConsumer.Shutdown();
71 | }
72 |
73 |
74 | [TestMethod]
75 | public async Task TestAck()
76 | {
77 | var simpleConsumer = new SimpleConsumer(accessPoint, _resourceNamespace, _group);
78 | simpleConsumer.Subscribe(_topic, rmq::FilterType.Tag, "*");
79 | await simpleConsumer.Start();
80 | var batchSize = 32;
81 | var receiveTimeout = TimeSpan.FromSeconds(10);
82 | var messages = await simpleConsumer.Receive(batchSize, receiveTimeout);
83 | foreach (var message in messages)
84 | {
85 | await simpleConsumer.Ack(message);
86 | Console.WriteLine($"Ack {message.MessageId} OK");
87 | }
88 | await simpleConsumer.Shutdown();
89 | }
90 |
91 | [TestMethod]
92 | public async Task TestChangeInvisibleDuration()
93 | {
94 | var simpleConsumer = new SimpleConsumer(accessPoint, _resourceNamespace, _group);
95 | simpleConsumer.Subscribe(_topic, rmq::FilterType.Tag, "*");
96 | await simpleConsumer.Start();
97 | var batchSize = 32;
98 | var receiveTimeout = TimeSpan.FromSeconds(10);
99 | var messages = await simpleConsumer.Receive(batchSize, receiveTimeout);
100 | foreach (var message in messages)
101 | {
102 | await simpleConsumer.ChangeInvisibleDuration(message, TimeSpan.FromSeconds(10));
103 | Console.WriteLine($"ChangeInvisibleDuration for message[MsgId={message.MessageId}] OK");
104 | }
105 | await simpleConsumer.Shutdown();
106 | }
107 | }
108 | }
--------------------------------------------------------------------------------
/tests/StaticCredentialsProviderTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 |
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 | [TestClass]
23 | public class StaticCredentialsProviderTest
24 | {
25 |
26 | [TestMethod]
27 | public void testGetCredentials()
28 | {
29 | var accessKey = "key";
30 | var accessSecret = "secret";
31 | var provider = new StaticCredentialsProvider(accessKey, accessSecret);
32 | var credentials = provider.getCredentials();
33 | Assert.IsNotNull(credentials);
34 | Assert.IsFalse(credentials.expired(), "Credentials from StaticCredentialsProvider should never expire");
35 | Assert.AreEqual(credentials.AccessKey, accessKey);
36 | Assert.AreEqual(credentials.AccessSecret, accessSecret);
37 | }
38 |
39 | }
40 | }
--------------------------------------------------------------------------------
/tests/TopicTest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using System.Collections.Generic;
19 |
20 | namespace Org.Apache.Rocketmq
21 | {
22 |
23 | [TestClass]
24 | public class TopicTest
25 | {
26 |
27 | [TestMethod]
28 | public void testCompareTo()
29 | {
30 | List topics = new List();
31 | topics.Add(new Topic("ns1", "t1"));
32 | topics.Add(new Topic("ns0", "t1"));
33 | topics.Add(new Topic("ns0", "t0"));
34 |
35 | topics.Sort();
36 |
37 | Assert.AreEqual(topics[0].ResourceNamespace, "ns0");
38 | Assert.AreEqual(topics[0].Name, "t0");
39 |
40 | Assert.AreEqual(topics[1].ResourceNamespace, "ns0");
41 | Assert.AreEqual(topics[1].Name, "t1");
42 |
43 |
44 | Assert.AreEqual(topics[2].ResourceNamespace, "ns1");
45 | Assert.AreEqual(topics[2].Name, "t1");
46 |
47 | }
48 |
49 |
50 | }
51 | }
--------------------------------------------------------------------------------
/tests/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Org.Apache.Rocketmq;
3 | using Grpc.Net.Client;
4 | using rmq = Apache.Rocketmq.V2;
5 |
6 | using System;
7 | using System.Collections.Concurrent;
8 | using System.Collections.Generic;
9 |
10 | namespace tests
11 | {
12 | [TestClass]
13 | public class UnitTest1
14 | {
15 | [TestMethod]
16 | public void TestMethod1()
17 | {
18 | rmq::Permission perm = rmq::Permission.None;
19 | switch (perm)
20 | {
21 | case rmq::Permission.None:
22 | {
23 | Console.WriteLine("None");
24 | break;
25 | }
26 |
27 | case rmq::Permission.Read:
28 | {
29 | Console.WriteLine("Read");
30 | break;
31 | }
32 |
33 | case rmq::Permission.Write:
34 | {
35 | Console.WriteLine("Write");
36 | break;
37 | }
38 |
39 | case rmq::Permission.ReadWrite:
40 | {
41 | Console.WriteLine("ReadWrite");
42 | break;
43 | }
44 |
45 | }
46 | }
47 |
48 | [TestMethod]
49 | public void TestRpcClientImplCtor()
50 | {
51 | RpcClient impl = new RpcClient("https://localhost:5001");
52 | }
53 |
54 | [TestMethod]
55 | public void TestConcurrentDictionary()
56 | {
57 | var dict = new ConcurrentDictionary>();
58 | string s = "abc";
59 | List result;
60 | var exists = dict.TryGetValue(s, out result);
61 | Assert.IsFalse(exists);
62 | Assert.IsNull(result);
63 |
64 | result = new List();
65 | result.Add("abc");
66 | Assert.IsTrue(dict.TryAdd(s, result));
67 |
68 | List list;
69 | exists = dict.TryGetValue(s, out list);
70 | Assert.IsTrue(exists);
71 | Assert.IsNotNull(list);
72 | Assert.AreEqual(1, list.Count);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/tests/tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------