Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging NATS .NET Client Library v1 and v2 Packages into a Unified >v2.4.x #601

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

- name: Check formatting
run: |
if dotnet format --verify-no-changes; then
if dotnet format --exclude ./src/NATS.Client/v1/ --verify-no-changes; then
echo "formatting passed"
else
rc="$?"
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ jobs:
- name: Test OpenTelemetry
run: dotnet test -c Debug --no-build --logger:"console;verbosity=normal" tests/NATS.Net.OpenTelemetry.Tests/NATS.Net.OpenTelemetry.Tests.csproj

- name: Compat v1-v2 Test (net8.0)
run: dotnet test -c Debug --no-build --logger:"console;verbosity=normal" -f net8.0 tests/NATS.Client.Compatv1v2.Tests/NATS.Client.Compatv1v2.Tests.csproj

- name: Check Native AOT
run: |
cd tests/NATS.Client.CheckNativeAot
Expand Down Expand Up @@ -153,3 +156,5 @@ jobs:
- name: Platform Test (Windows net481)
run: dotnet test -c Release --no-build --logger:"console;verbosity=normal" -f net481 .\tests\NATS.Client.Platform.Windows.Tests\NATS.Client.Platform.Windows.Tests.csproj

- name: Compat v1-v2 Test (Windows net462)
run: dotnet test -c Release --no-build --logger:"console;verbosity=normal" -f net462 .\tests\NATS.Client.Compatv1v2.Tests\NATS.Client.Compatv1v2.Tests.csproj
16 changes: 15 additions & 1 deletion NATS.Client.sln
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client", "src\NATS.Cli
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Client", "sandbox\Example.Client\Example.Client.csproj", "{A15CCDD5-B707-4142-B99A-64F0AB62318A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.Tests", "tests\NATS.Client.Tests\NATS.Client.Tests.csproj", "{6DAAAA87-8DDF-4E60-81CE-D8900327DE33}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.Simplified.Tests", "tests\NATS.Client.Simplified.Tests\NATS.Client.Simplified.Tests.csproj", "{6DAAAA87-8DDF-4E60-81CE-D8900327DE33}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.Simplified", "src\NATS.Client.Simplified\NATS.Client.Simplified.csproj", "{A8D357E3-4501-4350-88DA-ECBD63B87E91}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.Compatv1v2.Tests", "tests\NATS.Client.Compatv1v2.Tests\NATS.Client.Compatv1v2.Tests.csproj", "{86B9B4E8-F942-45AA-B6B2-3DACB1D24E00}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -309,6 +313,14 @@ Global
{6DAAAA87-8DDF-4E60-81CE-D8900327DE33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DAAAA87-8DDF-4E60-81CE-D8900327DE33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DAAAA87-8DDF-4E60-81CE-D8900327DE33}.Release|Any CPU.Build.0 = Release|Any CPU
{A8D357E3-4501-4350-88DA-ECBD63B87E91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8D357E3-4501-4350-88DA-ECBD63B87E91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8D357E3-4501-4350-88DA-ECBD63B87E91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8D357E3-4501-4350-88DA-ECBD63B87E91}.Release|Any CPU.Build.0 = Release|Any CPU
{86B9B4E8-F942-45AA-B6B2-3DACB1D24E00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86B9B4E8-F942-45AA-B6B2-3DACB1D24E00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86B9B4E8-F942-45AA-B6B2-3DACB1D24E00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86B9B4E8-F942-45AA-B6B2-3DACB1D24E00}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -362,6 +374,8 @@ Global
{48F1F736-3D87-4453-B497-BD9C203B2385} = {4827B3EC-73D8-436D-AE2A-5E29AC95FD0C}
{A15CCDD5-B707-4142-B99A-64F0AB62318A} = {95A69671-16CA-4133-981C-CC381B7AAA30}
{6DAAAA87-8DDF-4E60-81CE-D8900327DE33} = {C526E8AB-739A-48D7-8FC4-048978C9B650}
{A8D357E3-4501-4350-88DA-ECBD63B87E91} = {4827B3EC-73D8-436D-AE2A-5E29AC95FD0C}
{86B9B4E8-F942-45AA-B6B2-3DACB1D24E00} = {C526E8AB-739A-48D7-8FC4-048978C9B650}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8CBB7278-D093-448E-B3DE-B5991209A1AA}
Expand Down
2 changes: 1 addition & 1 deletion sandbox/Example.Client/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// See https://aka.ms/new-console-template for more information

using System.Text;
using NATS.Client;
using NATS.Net;

CancellationTokenSource cts = new();

Expand Down
26 changes: 26 additions & 0 deletions src/NATS.Client.Simplified/NATS.Client.Simplified.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

<!-- NuGet Packaging -->
<PackageTags>pubsub;messaging</PackageTags>
<Description>NATS core client for .NET</Description>

<!-- we won't publish on NuGet until we make a proper announcement
giving v1 developers a chance to make any potential changes
to their build scripts -->
<IsPackable>false</IsPackable>
<RootNamespace>NATS.Net</RootNamespace>

</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\NATS.Client.Core\NATS.Client.Core.csproj" />
<ProjectReference Include="..\NATS.Client.Serializers.Json\NATS.Client.Serializers.Json.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Threading.Channels;
using NATS.Client.Core;

namespace NATS.Client;
namespace NATS.Net;

/// <summary>
/// Represents a NATS client that provides methods for interacting with NATS server.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using NATS.Client.Core;
using NATS.Client.Serializers.Json;

namespace NATS.Client;
namespace NATS.Net;

/// <summary>
/// Default serializer interface for NATS messages.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using NATS.Client.Core;

namespace NATS.Client;
namespace NATS.Net;

/// <summary>
/// Default implementation of the INatsSerializerRegistry interface.
Expand Down
11 changes: 9 additions & 2 deletions src/NATS.Client/NATS.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@
to their build scripts -->
<IsPackable>false</IsPackable>

<NoWarn>$(NoWarn),SA1108,SA1129,SA1408,SA1127,SA1520,SA1132,SA1302,SA1116,SA1519,SA1206,SA1506
,CS8625,CS8601,SA1100,SA1517,SA1024,SA1509,SA1203,SA1002,CS8618,SA1312,CS8622,SA1117,SA1504
,SA1106,SA1308,SA1518,SA1107,SA1011,SA1122,SA1119,SA1128,SX1101,SA1137,CS8765,SA1303,SA1514
,SA1304,SA1212,SA1005,SA1003,SA1124,SA1311,SA1413,SA1000,SA1310,CS8767,SA1217,SA1515,SA1214
,SA1512,SX1309,SA1400,SA1204,SA1202,CS8619,CS8600,SA1004,SA1507,SA1508,SA1505,SA1001,SA1407
,SA1136,SA1501,CS8602,SA1012,SA1516,SA1013,CS8604,SA1300,CS8603,SA1502,SA1028,SA1307,SA1201
,SA1121,SA1027,SA1111,SA1025,SA1513,SA1401,SA1500,SA1021,SA1008,SA1009,SA1313,SA1026</NoWarn>

</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\NATS.Client.Core\NATS.Client.Core.csproj" />
<ProjectReference Include="..\NATS.Client.Serializers.Json\NATS.Client.Serializers.Json.csproj" />
<ProjectReference Include="..\NATS.Client.Simplified\NATS.Client.Simplified.csproj" />
</ItemGroup>

</Project>
40 changes: 40 additions & 0 deletions src/NATS.Client/v1/AckType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2021 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Text;

namespace NATS.Client
{
public sealed class AckType
{
public static AckType AckAck = new AckType("+ACK", true);
public static AckType AckNak = new AckType("-NAK", true);
public static AckType AckProgress = new AckType("+WPI", false);
public static AckType AckTerm = new AckType("+TERM", true);

public string Text { get; }
public byte[] Bytes { get; }
public bool IsTerminal { get; }

public AckType(string text, bool terminal)
{
Text = text;
Bytes = Encoding.ASCII.GetBytes(text);
IsTerminal = terminal;
}

public byte[] BodyBytes(long delayNanoseconds) {
return delayNanoseconds < 1 ? Bytes : Encoding.ASCII.GetBytes($"{Text} {{\"delay\": {delayNanoseconds}}}");
}
}
}
202 changes: 202 additions & 0 deletions src/NATS.Client/v1/AsyncSubscription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// Copyright 2015-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Threading;
using System.Threading.Tasks;

// disable XML comment warnings
#pragma warning disable 1591

namespace NATS.Client
{
/// <summary>
/// <see cref="AsyncSubscription"/> asynchronously delivers messages to listeners of the <see cref="MessageHandler"/>
/// event. This class should not be used directly.
/// </summary>
/// <remarks>
/// If the <see cref="AsyncSubscription"/> is created without listening to the <see cref="MessageHandler"/>
/// event, no messages will be received until <see cref="Start()"/> has been called.
/// </remarks>
public class AsyncSubscription : Subscription, IAsyncSubscription, ISubscription
{
/// <summary>
/// Occurs when the <see cref="AsyncSubscription"/> receives a message from the
/// underlying <see cref="Subscription"/>.
/// </summary>
public event EventHandler<MsgHandlerEventArgs> MessageHandler;

private Task msgFeeder = null;

private bool started = false;

internal AsyncSubscription(Connection conn, string subject, string queue, bool forceOwnChannel = false)
: base(conn, subject, queue)
{
mch = forceOwnChannel ? null : conn.getMessageChannel();
ownsChannel = mch == null;
if (ownsChannel)
{
mch = new Channel<Msg>(SubName());
}
}

internal override bool processMsg(Msg msg)
{
Connection localConn;
EventHandler<MsgHandlerEventArgs> localHandler;
long localMax;
long d;

lock (mu)
{
if (closed)
return false;

// the message handler has not been setup yet, drop the
// message.
if (MessageHandler == null)
return true;

if (conn == null)
return false;

d = tallyDeliveredMessage(msg);

localConn = conn;
localHandler = MessageHandler;
localMax = max;
}

if (localMax <= 0 || d <= localMax)
{
try
{
if (localHandler != null)
{
var msgHandlerEventArgs = new MsgHandlerEventArgs(msg);

localHandler(this, msgHandlerEventArgs);
}
}
catch (Exception) { }

if (d == max)
{
unsubscribe(false);
lock (mu)
{
conn = null;
}
}
}

return true;
}

internal bool isStarted()
{
return started;
}

internal void enableAsyncProcessing()
{
if (ownsChannel && msgFeeder == null)
{
// Use the default task scheduler and do not let child tasks launched
// when delivering messages to attach to this task (Issue #273)
msgFeeder = Task.Factory.StartNew(
doAsyncProcessing,
CancellationToken.None,
TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
}
started = true;
}

private void doAsyncProcessing() => conn.deliverMsgs(mch);

internal void disableAsyncProcessing()
{
lock (mu)
{
if (msgFeeder != null)
{
mch.close();
msgFeeder = null;
}
MessageHandler = null;
started = false;
}
}

/// <summary>
/// Starts delivering received messages to listeners on <see cref="MessageHandler"/>
/// from a separate thread.
/// </summary>
/// <remarks>
/// If the <see cref="IAsyncSubscription"/> has already started delivering messages, this
/// method is a no-op.
/// </remarks>
/// <exception cref="NATSBadSubscriptionException">There is no longer an associated <see cref="Connection"/>
/// for this <see cref="AsyncSubscription"/>.</exception>
public void Start()
{
if (started)
return;

lock (mu)
{
if (conn == null)
throw new NATSBadSubscriptionException();

conn.sendSubscriptionMessage(this);
enableAsyncProcessing();
}
}

/// <summary>
/// Removes interest in the given subject.
/// </summary>
/// <exception cref="NATSBadSubscriptionException">There is no longer an associated <see cref="Connection"/>
/// for this <see cref="AsyncSubscription"/>.</exception>
public override void Unsubscribe()
{
disableAsyncProcessing();
base.Unsubscribe();
}

/// <summary>
/// Issues an automatic call to <see cref="Unsubscribe"/> when <paramref name="max"/> messages have been
/// received.
/// </summary>
/// <remarks><para>This can be useful when sending a request to an unknown number of subscribers.
/// <see cref="Connection"/>'s Request methods use this functionality.</para>
/// <para>Calling this method will invoke <see cref="Start"/> if it has not already been called.</para></remarks>
/// <param name="max">The maximum number of messages to receive on the subscription before calling
/// <see cref="Unsubscribe"/>. Values less than or equal to zero (<c>0</c>) unsubscribe immediately.</param>
/// <exception cref="NATSBadSubscriptionException">There is no longer an associated <see cref="Connection"/>
/// for this <see cref="AsyncSubscription"/>.</exception>
public override void AutoUnsubscribe(int max)
{
Start();
base.AutoUnsubscribe(max);
}

internal override void close()
{
disableAsyncProcessing();
close(ownsChannel);
}
}
}
Loading
Loading