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

Proxy Invocations Except Current Session #33

Merged
merged 8 commits into from
Jan 12, 2024
Merged
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
15 changes: 8 additions & 7 deletions src/NexNet.Generator/NexusGenerator.Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ public void EmitNexusInvocation(StringBuilder sb, InvocationInterfaceMeta proxyI
/// Emits the invocation of the method on the nexus.
/// </summary>
/// <param name="sb"></param>
public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)
/// <param name="forLog">Change the output to write the output params. Used for logging.</param>
public void EmitNexusMethodInvocation(StringBuilder sb, bool forLog)
{
sb.Append(this.Name).Append("(");

Expand All @@ -309,7 +310,7 @@ public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)
// otherwise we need to pass the serialized value.
if (methodParameterMeta.IsDuplexPipe)
{
if (writeParamNames)
if (forLog)
{
sb.Append(methodParameterMeta.Name)
.Append(" = {arguments.Item")
Expand All @@ -325,7 +326,7 @@ public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)
}
else if (methodParameterMeta.IsDuplexUnmanagedChannel)
{
if (writeParamNames)
if (forLog)
{
sb.Append(methodParameterMeta.Name)
.Append(" = {arguments.Item")
Expand All @@ -343,7 +344,7 @@ public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)
}
else if (methodParameterMeta.IsDuplexChannel)
{
if (writeParamNames)
if (forLog)
{
sb.Append(methodParameterMeta.Name)
.Append(" = {arguments.Item")
Expand All @@ -361,7 +362,7 @@ public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)
}
else if (methodParameterMeta.SerializedValue != null)
{
if (writeParamNames)
if (forLog)
{
sb.Append(methodParameterMeta.Name)
.Append(" = {arguments.Item")
Expand All @@ -379,7 +380,7 @@ public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)

if (CancellationTokenParameter != null)
{
if (writeParamNames)
if (forLog)
{
sb.Append(CancellationTokenParameter.Name).Append(" = ct");
}
Expand All @@ -396,7 +397,7 @@ public void EmitNexusMethodInvocation(StringBuilder sb, bool writeParamNames)

sb.Append(");");

if (!writeParamNames)
if (!forLog)
sb.AppendLine();
}

Expand Down
209 changes: 209 additions & 0 deletions src/NexNet.IntegrationTests/NexusServerTests_NexusInvocations.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Buffers;
using System.Collections;
using NexNet.IntegrationTests.Pipes;
using NexNet.IntegrationTests.TestInterfaces;
using NUnit.Framework;
#pragma warning disable VSTHRD200
Expand Down Expand Up @@ -261,6 +262,214 @@ public async Task NexusInvokesOnGroups(Type type)
await tcs2.Task.Timeout(1);
}

[TestCase(Type.Uds)]
[TestCase(Type.Tcp)]
[TestCase(Type.TcpTls)]
[TestCase(Type.Quic)]
public async Task NexusInvokesOnGroupExceptCurrent(Type type)
{
var groupInvokedCount = 0;
var voidInvokedCount = 0;
var tcs1 = new TaskCompletionSource();

var (client1, clientNexus1) = CreateClient(CreateClientConfig(type));
var (client2, clientNexus2) = CreateClient(CreateClientConfig(type));

var server = CreateServer(CreateServerConfig(type), connectedNexus =>
{
connectedNexus.ServerTaskEvent = async nexus =>
{
await nexus.Context.Clients.GroupExceptCaller("group").ClientTask();

// Delay to ensure the method has time to invoke on the client sessions.
await Task.Delay(50);
nexus.Context.Clients.Group("group").ClientVoid();
};

connectedNexus.OnConnectedEvent = nexus =>
{
nexus.Context.Groups.Add("group");
return ValueTask.CompletedTask;
};
});

clientNexus1.ClientTaskEvent = clientNexus2.ClientTaskEvent = _ =>
{
Interlocked.Increment(ref groupInvokedCount);
return ValueTask.CompletedTask;
};

clientNexus1.ClientVoidEvent = clientNexus2.ClientVoidEvent = _ =>
{
if (Interlocked.Increment(ref voidInvokedCount) == 2)
tcs1.SetResult();
};

await server.StartAsync().Timeout(1);

await client1.ConnectAsync().Timeout(1);
await client2.ConnectAsync().Timeout(1);

await client1.Proxy.ServerTask();

await tcs1.Task.Timeout(1);
Assert.AreEqual(1, groupInvokedCount);
}

[TestCase(Type.Uds)]
[TestCase(Type.Tcp)]
[TestCase(Type.TcpTls)]
[TestCase(Type.Quic)]
public async Task NexusInvokesOnGroupsExceptCurrent(Type type)
{
var groupInvokedCount = 0;
var voidInvokedCount = 0;
var tcs1 = new TaskCompletionSource();

var (client1, clientNexus1) = CreateClient(CreateClientConfig(type));
var (client2, clientNexus2) = CreateClient(CreateClientConfig(type));

var server = CreateServer(CreateServerConfig(type), connectedNexus =>
{
connectedNexus.ServerTaskEvent = async nexus =>
{
await nexus.Context.Clients.GroupsExceptCaller(["group1", "group2"]).ClientTask();

// Delay to ensure the method has time to invoke on the client sessions.
await Task.Delay(50);
nexus.Context.Clients.Group("group1").ClientVoid();
};

connectedNexus.OnConnectedEvent = nexus =>
{
nexus.Context.Groups.Add(["group1", "group2"]);
return ValueTask.CompletedTask;
};
});

clientNexus1.ClientTaskEvent = clientNexus2.ClientTaskEvent = _ =>
{
Interlocked.Increment(ref groupInvokedCount);
return ValueTask.CompletedTask;
};

clientNexus1.ClientVoidEvent = clientNexus2.ClientVoidEvent = _ =>
{
if (Interlocked.Increment(ref voidInvokedCount) == 2)
tcs1.SetResult();
};

await server.StartAsync().Timeout(1);

await client1.ConnectAsync().Timeout(1);
await client2.ConnectAsync().Timeout(1);

await client1.Proxy.ServerTask();

await tcs1.Task.Timeout(1);
Assert.AreEqual(2, groupInvokedCount);
}

[TestCase(Type.Uds)]
[TestCase(Type.Tcp)]
[TestCase(Type.TcpTls)]
[TestCase(Type.Quic)]
public async Task DirectNexusProxyInvokesOnGroupIncludingCurrent(Type type)
{
var groupInvokedCount = 0;
var voidInvokedCount = 0;
var tcs1 = new TaskCompletionSource();

var (client1, clientNexus1) = CreateClient(CreateClientConfig(type));
var (client2, clientNexus2) = CreateClient(CreateClientConfig(type));

var server = CreateServer(CreateServerConfig(type), connectedNexus =>
{
connectedNexus.OnConnectedEvent = nexus =>
{
nexus.Context.Groups.Add("group");
return ValueTask.CompletedTask;
};
});

clientNexus1.ClientTaskEvent = clientNexus2.ClientTaskEvent = _ =>
{
Interlocked.Increment(ref groupInvokedCount);
return ValueTask.CompletedTask;
};

clientNexus1.ClientVoidEvent = clientNexus2.ClientVoidEvent = _ =>
{
if (Interlocked.Increment(ref voidInvokedCount) == 2)
tcs1.SetResult();
};

await server.StartAsync().Timeout(1);

await client1.ConnectAsync().Timeout(1);
await client2.ConnectAsync().Timeout(1);

await server.GetContext().Clients.GroupExceptCaller("group").ClientTask();

// Delay to ensure the method has time to invoke on the client sessions.
await Task.Delay(50);

server.GetContext().Clients.GroupExceptCaller("group").ClientVoid();

await tcs1.Task.Timeout(1);
Assert.AreEqual(2, groupInvokedCount);
}

[TestCase(Type.Uds)]
[TestCase(Type.Tcp)]
[TestCase(Type.TcpTls)]
[TestCase(Type.Quic)]
public async Task DirectNexusProxyInvokesOnGroupsIncludingCurrent(Type type)
{
var groupInvokedCount = 0;
var voidInvokedCount = 0;
var tcs1 = new TaskCompletionSource();

var (client1, clientNexus1) = CreateClient(CreateClientConfig(type));
var (client2, clientNexus2) = CreateClient(CreateClientConfig(type));

var server = CreateServer(CreateServerConfig(type), connectedNexus =>
{
connectedNexus.OnConnectedEvent = nexus =>
{
nexus.Context.Groups.Add(["group1", "group2"]);
return ValueTask.CompletedTask;
};
});

clientNexus1.ClientTaskEvent = clientNexus2.ClientTaskEvent = _ =>
{
Interlocked.Increment(ref groupInvokedCount);
return ValueTask.CompletedTask;
};

clientNexus1.ClientVoidEvent = clientNexus2.ClientVoidEvent = _ =>
{
if (Interlocked.Increment(ref voidInvokedCount) == 2)
tcs1.SetResult();
};

await server.StartAsync().Timeout(1);

await client1.ConnectAsync().Timeout(1);
await client2.ConnectAsync().Timeout(1);

await server.GetContext().Clients.GroupsExceptCaller(["group1", "group2"]).ClientTask();

// Delay to ensure the method has time to invoke on the client sessions.
await Task.Delay(50);

server.GetContext().Clients.GroupExceptCaller("group1").ClientVoid();

await tcs1.Task.Timeout(1);
Assert.AreEqual(4, groupInvokedCount);
}

[TestCase(Type.Uds)]
[TestCase(Type.Tcp)]
[TestCase(Type.TcpTls)]
Expand Down
4 changes: 2 additions & 2 deletions src/NexNet.props
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project>
<PropertyGroup>
<Version>0.7.0</Version>
<Version>0.8.0</Version>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<TargetFramework>net8.0</TargetFramework>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Company>Dtronix</Company>
<Product>NexNet</Product>
<Copyright>Copyright © Dtronix 2023</Copyright>
<Copyright>Copyright © Dtronix 2024</Copyright>
<Authors>DJGosnell</Authors>
<PackageProjectUrl>https://github.com/Dtronix/NexNet</PackageProjectUrl>
<RepositoryUrl>https://github.com/Dtronix/NexNet</RepositoryUrl>
Expand Down
4 changes: 1 addition & 3 deletions src/NexNet/Internals/Pipelines/ConnectionAbortedException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,4 @@ public ConnectionAbortedException(string message) : base(message) { }
/// Create a new instance of ConnectionAbortedException
/// </summary>
public ConnectionAbortedException(string message, Exception inner) : base(message, inner) { }

private ConnectionAbortedException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}
2 changes: 0 additions & 2 deletions src/NexNet/Internals/Pipelines/ConnectionResetException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,4 @@ public ConnectionResetException(string message) : base(message) { }
/// Create a new ConnectionResetException instance
/// </summary>
public ConnectionResetException(string message, Exception inner) : base(message, inner) { }

private ConnectionResetException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
16 changes: 16 additions & 0 deletions src/NexNet/Invocation/IProxyBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,29 @@ public interface IProxyBase<out TProxy>
/// <returns>Proxy</returns>
TProxy Group(string groupName);

/// <summary>
/// Proxy for all clients part of the specified group.
/// Will not send the invocation to the current calling session.
/// </summary>
/// <param name="groupName">Group name to get the proxy for.</param>
/// <returns>Proxy</returns>
TProxy GroupExceptCaller(string groupName);

/// <summary>
/// Proxy for all clients part of the specified groups.
/// </summary>
/// <param name="groupName">Group names to get the proxies for.</param>
/// <returns>Proxy</returns>
TProxy Groups(string[] groupName);

/// <summary>
/// Proxy for all clients part of the specified groups.
/// Will not send the invocation to the current calling session.
/// </summary>
/// <param name="groupName">Group names to get the proxies for.</param>
/// <returns>Proxy</returns>
TProxy GroupsExceptCaller(string[] groupName);

/// <summary>
/// Gets all the connected client ids.
/// </summary>
Expand Down
Loading