Skip to content

Commit

Permalink
Merge pull request #42 from Elfocrash/halter73/signalr-connectionhandler
Browse files Browse the repository at this point in the history
Halter73/signalr connectionhandler
  • Loading branch information
meslubi2021 authored Dec 20, 2024
2 parents 714b8f9 + f4fc1aa commit 2c0a20f
Show file tree
Hide file tree
Showing 21 changed files with 1,148 additions and 0 deletions.
Empty file.
100 changes: 100 additions & 0 deletions aspnetcore/signalr/connection-handler/sample/EchoConnectionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Features;

namespace SignalRConnectionHandlerSample
{
public class EchoConnectionHandler : ConnectionHandler
{
public override async Task OnConnectedAsync(ConnectionContext connection)
{
var transportType = connection.Features.Get<IHttpTransportFeature>()?.TransportType;
var welcomeString = $"Welcome. A connection has been established with the '{transportType}' transport.\n\n";

Write(connection.Transport.Output, welcomeString, Encoding.UTF8);
await connection.Transport.Output.FlushAsync();

while (true)
{
var result = await connection.Transport.Input.ReadAsync();
var buffer = result.Buffer;

try
{
if (!buffer.IsEmpty)
{
if (buffer.IsSingleSegment)
{
await connection.Transport.Output.WriteAsync(buffer.First);
}
else
{
foreach (var segment in buffer)
{
await connection.Transport.Output.WriteAsync(segment);
}
}
}

if (result.IsCompleted)
{
break;
}
}
finally
{
connection.Transport.Input.AdvanceTo(buffer.End);
}
}
}

private static void Write(PipeWriter pipeWriter, string text, Encoding encoding)
{
var minimumByteSize = encoding.GetMaxByteCount(1);
var encodedLength = encoding.GetByteCount(text);
var destination = pipeWriter.GetSpan(minimumByteSize);

if (encodedLength <= destination.Length)
{
// Just call Encoding.GetBytes if everything will fit into a single segment.
var bytesWritten = encoding.GetBytes(text, destination);
pipeWriter.Advance(bytesWritten);
}
else
{
WriteMultiSegmentEncoded(pipeWriter, text, encoding, destination, encodedLength, minimumByteSize);
}
}

private static void WriteMultiSegmentEncoded(PipeWriter writer, string text, Encoding encoding, Span<byte> destination, int encodedLength, int minimumByteSize)
{
var encoder = encoding.GetEncoder();
var source = text.AsSpan();
var completed = false;
var totalBytesUsed = 0;

// This may be a bug, but encoder.Convert returns completed = true for UTF7 too early.
// Therefore, we check encodedLength - totalBytesUsed too.
while (!completed || encodedLength - totalBytesUsed != 0)
{
encoder.Convert(source, destination, flush: source.Length == 0, out var charsUsed, out var bytesUsed, out completed);
totalBytesUsed += bytesUsed;

writer.Advance(bytesUsed);
source = source.Slice(charsUsed);

destination = writer.GetSpan(minimumByteSize);
}
}
}
}
26 changes: 26 additions & 0 deletions aspnetcore/signalr/connection-handler/sample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace SignalRConnectionHandlerSample
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

</Project>
44 changes: 44 additions & 0 deletions aspnetcore/signalr/connection-handler/sample/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace SignalRConnectionHandlerSample
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddConnections();
services.AddSignalR();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseFileServer();

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
app.UseEndpoints(endpoints =>
{
endpoints.MapConnectionHandler<EchoConnectionHandler>("/echo");
});
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
10 changes: 10 additions & 0 deletions aspnetcore/signalr/connection-handler/sample/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
1 change: 1 addition & 0 deletions aspnetcore/signalr/connection-handler/wip/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
wwwroot/lib/
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Buffers;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Features;

namespace SignalRSamples.ConnectionHandlers
{
public class MessagesConnectionHandler : ConnectionHandler
{
private ConnectionList Connections { get; } = new ConnectionList();

public override async Task OnConnectedAsync(ConnectionContext connection)
{
Connections.Add(connection);

var transportType = connection.Features.Get<IHttpTransportFeature>()?.TransportType;

await Broadcast($"{connection.ConnectionId} connected ({transportType})");

try
{
while (true)
{
var result = await connection.Transport.Input.ReadAsync();
var buffer = result.Buffer;

try
{
if (!buffer.IsEmpty)
{
// We can avoid the copy here but we'll deal with that later
var text = Encoding.UTF8.GetString(buffer.ToArray());
text = $"{connection.ConnectionId}: {text}";
await Broadcast(Encoding.UTF8.GetBytes(text));
}
else if (result.IsCompleted)
{
break;
}
}
finally
{
connection.Transport.Input.AdvanceTo(buffer.End);
}
}
}
finally
{
Connections.Remove(connection);

await Broadcast($"{connection.ConnectionId} disconnected ({transportType})");
}
}

private Task Broadcast(string text)
{
return Broadcast(Encoding.UTF8.GetBytes(text));
}

private Task Broadcast(byte[] payload)
{
var tasks = new List<Task>(Connections.Count);
foreach (var c in Connections)
{
tasks.Add(c.Transport.Output.WriteAsync(payload).AsTask());
}

return Task.WhenAll(tasks);
}
}
}
48 changes: 48 additions & 0 deletions aspnetcore/signalr/connection-handler/wip/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.IO;
using System.Net;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using SignalRSamples.Hubs;

namespace SignalRSamples
{
public class Program
{
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();

var host = new WebHostBuilder()
.UseConfiguration(config)
.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true")
.ConfigureLogging(factory =>
{
factory.AddConsole();
})
.UseKestrel(options =>
{
// Default port
options.ListenLocalhost(5000);

// Hub bound to TCP end point
options.Listen(IPAddress.Any, 9001, builder =>
{
builder.UseHub<Chat>();
});
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();

host.Run();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<GenerateRazorAssemblyInfo>false</GenerateRazorAssemblyInfo>
</PropertyGroup>

<ItemGroup>
<Reference Include="Google.Protobuf" />
<Reference Include="Microsoft.AspNetCore.Cors" />
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
<Reference Include="Microsoft.AspNetCore.Hosting" />
<Reference Include="Microsoft.AspNetCore.Http.Connections" />
<Reference Include="Microsoft.AspNetCore.Server.IISIntegration" />
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" />
<Reference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" />
<Reference Include="Microsoft.AspNetCore.SignalR" />
<Reference Include="Microsoft.AspNetCore.StaticFiles" />
<Reference Include="Microsoft.Extensions.Configuration.CommandLine" />
<Reference Include="Microsoft.Extensions.Logging.Console" />
<Reference Include="System.Reactive.Linq" />
</ItemGroup>

<Target Name="CopyTSClient" BeforeTargets="AfterBuild">
<ItemGroup>
<SignalRBrowserJSClientFiles Include="$(MSBuildThisFileDirectory)..\..\clients\ts\signalr\dist\browser\*" />
<SignalRBrowserJSClientFiles Include="$(MSBuildThisFileDirectory)..\..\clients\ts\signalr-protocol-msgpack\dist\browser\*" />
<SignalRWebWorkerJSClientFiles Include="$(MSBuildThisFileDirectory)..\..\clients\ts\signalr\dist\webworker\*" />
</ItemGroup>
<Copy SourceFiles="@(SignalRBrowserJSClientFiles)" DestinationFolder="$(MSBuildThisFileDirectory)wwwroot\lib\signalr" />
<Copy SourceFiles="@(SignalRWebWorkerJSClientFiles)" DestinationFolder="$(MSBuildThisFileDirectory)wwwroot\lib\signalr-webworker"/>

<ItemGroup>
<MsgPackClientFiles Include="$(MSBuildThisFileDirectory)..\..\clients\ts\signalr-protocol-msgpack\node_modules\msgpack5\dist\*" />
</ItemGroup>
<Copy SourceFiles="@(MsgPackClientFiles)" DestinationFolder="$(MSBuildThisFileDirectory)wwwroot\lib\msgpack5" />
</Target>

</Project>
Loading

0 comments on commit 2c0a20f

Please sign in to comment.