diff --git a/src/NATS.Client.Abstractions/INatsSocketConnection.cs b/src/NATS.Client.Abstractions/INatsSocketConnection.cs new file mode 100644 index 000000000..c71570000 --- /dev/null +++ b/src/NATS.Client.Abstractions/INatsSocketConnection.cs @@ -0,0 +1,43 @@ +using System.Net.Sockets; + +namespace NATS.Client.Core; + +/// +/// Represents a socket connection to a NATS server. +/// +/// +/// This interface defines the contract for low-level socket connections to NATS servers, +/// providing methods for sending and receiving data and disposing the socket. +/// Disposing should attempt to perform graceful shutdown of the socket. +/// +public interface INatsSocketConnection : IAsyncDisposable +{ + /// + /// Sends data asynchronously over the connection. + /// + /// The buffer containing the data to send. + /// A task representing the asynchronous send operation with the number of bytes sent. + ValueTask SendAsync(ReadOnlyMemory buffer); + + /// + /// Receives data asynchronously from the connection. + /// + /// The buffer to store the received data. + /// A task representing the asynchronous receive operation with the number of bytes received. + ValueTask ReceiveAsync(Memory buffer); +} + +/// +/// Represents a NATS socket connection that can be upgraded to use TLS. +/// +/// +/// This interface extends to provide access to the underlying +/// socket that is used to create a SslStream. +/// +public interface INatsTlsUpgradeableSocketConnection : INatsSocketConnection +{ + /// + /// Gets the underlying Socket instance for the connection. + /// + Socket Socket { get; } +} diff --git a/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj b/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj index e4e38515b..2fb09c6ff 100644 --- a/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj +++ b/src/NATS.Client.Abstractions/NATS.Client.Abstractions.csproj @@ -17,6 +17,7 @@ + diff --git a/src/NATS.Client.Core/INatsSocketConnection.cs b/src/NATS.Client.Core/INatsSocketConnection.cs index 87386dc76..95f0861e9 100644 --- a/src/NATS.Client.Core/INatsSocketConnection.cs +++ b/src/NATS.Client.Core/INatsSocketConnection.cs @@ -1,32 +1,5 @@ -using System.Net.Sockets; - namespace NATS.Client.Core; -/// -/// Represents a socket connection to a NATS server. -/// -/// -/// This interface defines the contract for low-level socket connections to NATS servers, -/// providing methods for sending and receiving data and disposing the socket. -/// Disposing should attempt to perform graceful shutdown of the socket. -/// -public interface INatsSocketConnection : IAsyncDisposable -{ - /// - /// Sends data asynchronously over the connection. - /// - /// The buffer containing the data to send. - /// A task representing the asynchronous send operation with the number of bytes sent. - ValueTask SendAsync(ReadOnlyMemory buffer); - - /// - /// Receives data asynchronously from the connection. - /// - /// The buffer to store the received data. - /// A task representing the asynchronous receive operation with the number of bytes received. - ValueTask ReceiveAsync(Memory buffer); -} - /// /// Obsolete, use instead /// @@ -39,18 +12,3 @@ public interface ISocketConnection : INatsSocketConnection ValueTask AbortConnectionAsync(CancellationToken cancellationToken); } - -/// -/// Represents a NATS socket connection that can be upgraded to use TLS. -/// -/// -/// This interface extends to provide access to the underlying -/// socket that is used to create a SslStream. -/// -public interface INatsTlsUpgradeableSocketConnection : INatsSocketConnection -{ - /// - /// Gets the underlying Socket instance for the connection. - /// - Socket Socket { get; } -} diff --git a/src/NATS.Client.Core/TypeForwarders.cs b/src/NATS.Client.Core/TypeForwarders.cs index a565921ee..a9ff5cb35 100644 --- a/src/NATS.Client.Core/TypeForwarders.cs +++ b/src/NATS.Client.Core/TypeForwarders.cs @@ -5,3 +5,5 @@ [assembly: TypeForwardedTo(typeof(INatsSerialize<>))] [assembly: TypeForwardedTo(typeof(INatsDeserialize<>))] [assembly: TypeForwardedTo(typeof(INatsSerializerRegistry))] +[assembly: TypeForwardedTo(typeof(INatsSocketConnection))] +[assembly: TypeForwardedTo(typeof(INatsTlsUpgradeableSocketConnection))] diff --git a/tests/NATS.Client.CheckAbi/Program.cs b/tests/NATS.Client.CheckAbi/Program.cs index 433b42ed0..ed3b4ece6 100644 --- a/tests/NATS.Client.CheckAbi/Program.cs +++ b/tests/NATS.Client.CheckAbi/Program.cs @@ -23,10 +23,14 @@ void Check(string name, string expected, string actual) Check("INatsSerializeWithContext<>", "NATS.Client.Abstractions", typeof(INatsSerializeWithContext<>).Assembly.GetName().Name!); Check("INatsDeserializeWithContext<>", "NATS.Client.Abstractions", typeof(INatsDeserializeWithContext<>).Assembly.GetName().Name!); Check("NatsMsgContext", "NATS.Client.Abstractions", typeof(NatsMsgContext).Assembly.GetName().Name!); +Check("INatsSocketConnection", "NATS.Client.Abstractions", typeof(INatsSocketConnection).Assembly.GetName().Name!); +Check("INatsTlsUpgradeableSocketConnection", "NATS.Client.Abstractions", typeof(INatsTlsUpgradeableSocketConnection).Assembly.GetName().Name!); Console.WriteLine(); Console.WriteLine("Types as seen by TransientLib (compiled against 2.6.0):"); Check("INatsSerialize<> (transient)", "NATS.Client.Abstractions", MySerializer.GetSerializerInterfaceAssembly()); +Check("INatsSocketConnection (transient)", "NATS.Client.Abstractions", MySocketConnection.GetSocketConnectionInterfaceAssembly()); +Check("INatsTlsUpgradeableSocketConnection (transient)", "NATS.Client.Abstractions", MySocketConnection.GetTlsUpgradeableInterfaceAssembly()); Console.WriteLine(); Console.WriteLine("Assembly versions at runtime:"); @@ -54,6 +58,16 @@ void Check(string name, string expected, string actual) Console.WriteLine(); +Console.WriteLine("Testing TransientLib.MySocketConnection (compiled against 2.6.0):"); +INatsSocketConnection connection = new MySocketConnection(); +var sent = await connection.SendAsync(new ReadOnlyMemory(new byte[7])); +Console.WriteLine($" SendAsync reported {sent} bytes"); +if (sent != 7) + errors.Add($"SendAsync failed: got {sent}"); +await connection.DisposeAsync(); + +Console.WriteLine(); + if (errors.Count > 0) { Console.Error.WriteLine($"FAILED: {errors.Count} error(s):"); diff --git a/tests/NATS.Client.CheckAbiTransientLib/MySocketConnection.cs b/tests/NATS.Client.CheckAbiTransientLib/MySocketConnection.cs new file mode 100644 index 000000000..43bab5812 --- /dev/null +++ b/tests/NATS.Client.CheckAbiTransientLib/MySocketConnection.cs @@ -0,0 +1,30 @@ +using System.Net.Sockets; +using NATS.Client.Core; + +namespace NATS.Client.CheckAbiTransientLib; + +/// +/// Compiled against NATS.Net 2.6.0 where INatsSocketConnection and +/// INatsTlsUpgradeableSocketConnection live in NATS.Client.Core. When used with a newer +/// build, type forwarding should redirect both to NATS.Client.Abstractions. +/// +public class MySocketConnection : INatsTlsUpgradeableSocketConnection +{ + public Socket Socket => throw new NotSupportedException(); + + public static string GetSocketConnectionInterfaceAssembly() + { + return typeof(INatsSocketConnection).Assembly.GetName().Name!; + } + + public static string GetTlsUpgradeableInterfaceAssembly() + { + return typeof(INatsTlsUpgradeableSocketConnection).Assembly.GetName().Name!; + } + + public ValueTask SendAsync(ReadOnlyMemory buffer) => new(buffer.Length); + + public ValueTask ReceiveAsync(Memory buffer) => new(0); + + public ValueTask DisposeAsync() => default; +}