Skip to content

Commit

Permalink
Merge pull request #770 from Cysharp/feature/refactor/StreamingHubHan…
Browse files Browse the repository at this point in the history
…dlerRepository

Make StreamingHubHandlerRepository non-static class
  • Loading branch information
mayuki authored May 8, 2024
2 parents f1e9adc + e2f6428 commit dc90d87
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ public static class MagicOnionServicesExtensions
public static IMagicOnionServerBuilder AddMagicOnion(this IServiceCollection services, Action<MagicOnionOptions>? configureOptions = null)
{
var configName = Options.Options.DefaultName;
services.AddSingleton<MagicOnionServiceDefinition>(sp => MagicOnionEngine.BuildServerServiceDefinition(sp, sp.GetRequiredService<IOptionsMonitor<MagicOnionOptions>>().Get(configName)));
services.TryAddSingleton<MagicOnionServiceDefinition>(sp => MagicOnionEngine.BuildServerServiceDefinition(sp, sp.GetRequiredService<IOptionsMonitor<MagicOnionOptions>>().Get(configName)));
return services.AddMagicOnionCore(configureOptions);
}

public static IMagicOnionServerBuilder AddMagicOnion(this IServiceCollection services, Assembly[] searchAssemblies, Action<MagicOnionOptions>? configureOptions = null)
{
var configName = Options.Options.DefaultName;
services.AddSingleton<MagicOnionServiceDefinition>(sp => MagicOnionEngine.BuildServerServiceDefinition(sp, searchAssemblies, sp.GetRequiredService<IOptionsMonitor<MagicOnionOptions>>().Get(configName)));
services.TryAddSingleton<MagicOnionServiceDefinition>(sp => MagicOnionEngine.BuildServerServiceDefinition(sp, searchAssemblies, sp.GetRequiredService<IOptionsMonitor<MagicOnionOptions>>().Get(configName)));
return services.AddMagicOnionCore(configureOptions);
}

public static IMagicOnionServerBuilder AddMagicOnion(this IServiceCollection services, IEnumerable<Type> searchTypes, Action<MagicOnionOptions>? configureOptions = null)
{
var configName = Options.Options.DefaultName;
services.AddSingleton<MagicOnionServiceDefinition>(sp => MagicOnionEngine.BuildServerServiceDefinition(sp, searchTypes, sp.GetRequiredService<IOptionsMonitor<MagicOnionOptions>>().Get(configName)));
services.TryAddSingleton<MagicOnionServiceDefinition>(sp => MagicOnionEngine.BuildServerServiceDefinition(sp, searchTypes, sp.GetRequiredService<IOptionsMonitor<MagicOnionOptions>>().Get(configName)));
return services.AddMagicOnionCore(configureOptions);
}

Expand All @@ -48,7 +48,8 @@ internal static IMagicOnionServerBuilder AddMagicOnionCore(this IServiceCollecti
var glueServiceType = MagicOnionGlueService.CreateType();
services.TryAddSingleton<IGroupRepositoryFactory, ImmutableArrayGroupRepositoryFactory>();

services.AddSingleton<MagicOnionServiceDefinitionGlueDescriptor>(sp => new MagicOnionServiceDefinitionGlueDescriptor(glueServiceType, sp.GetRequiredService<MagicOnionServiceDefinition>()));
services.TryAddSingleton<StreamingHubHandlerRepository>();
services.TryAddSingleton<MagicOnionServiceDefinitionGlueDescriptor>(sp => new MagicOnionServiceDefinitionGlueDescriptor(glueServiceType, sp.GetRequiredService<MagicOnionServiceDefinition>()));
services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IServiceMethodProvider<>).MakeGenericType(glueServiceType), typeof(MagicOnionGlueServiceMethodProvider<>).MakeGenericType(glueServiceType)));

// MagicOnion: Metrics
Expand Down
5 changes: 3 additions & 2 deletions src/MagicOnion.Server/Hubs/StreamingHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using MessagePack;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;

namespace MagicOnion.Server.Hubs;

Expand Down Expand Up @@ -111,7 +112,7 @@ public async Task<DuplexStreamingResult<byte[], byte[]>> Connect()

var streamingContext = GetDuplexStreamingContext<byte[], byte[]>();

var group = StreamingHubHandlerRepository.GetGroupRepository(Context.MethodHandler);
var group = Context.ServiceProvider.GetRequiredService<StreamingHubHandlerRepository>().GetGroupRepository(Context.MethodHandler);
this.Group = new HubGroupRepository(this.Context, group);
try
{
Expand Down Expand Up @@ -172,7 +173,7 @@ async Task HandleMessageAsync()
// eg: Send the current game state to the client.
await OnConnected();

var handlers = StreamingHubHandlerRepository.GetHandlers(Context.MethodHandler);
var handlers = Context.ServiceProvider.GetRequiredService<StreamingHubHandlerRepository>().GetHandlers(Context.MethodHandler);

// Main loop of StreamingHub.
// Be careful to allocation and performance.
Expand Down
64 changes: 39 additions & 25 deletions src/MagicOnion.Server/Hubs/StreamingHubHandlerRepository.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
#if NET8_0_OR_GREATER
using System.Collections.Frozen;
#endif
using MagicOnion.Server.Internal;

namespace MagicOnion.Server.Hubs;

// Global cache of Streaming Handler
internal static class StreamingHubHandlerRepository
internal class StreamingHubHandlerRepository
{
static Dictionary<MethodHandler, UniqueHashDictionary<StreamingHubHandler>> cache
= new Dictionary<MethodHandler, UniqueHashDictionary<StreamingHubHandler>>(new MethodHandler.UniqueEqualityComparer());
bool frozen;

static Dictionary<MethodHandler, IGroupRepository> cacheGroup
= new Dictionary<MethodHandler, IGroupRepository>(new MethodHandler.UniqueEqualityComparer());
IDictionary<MethodHandler, UniqueHashDictionary<StreamingHubHandler>> cache
= new Dictionary<MethodHandler, UniqueHashDictionary<StreamingHubHandler>>(MethodHandler.UniqueEqualityComparer.Instance);

public static void RegisterHandler(MethodHandler parent, StreamingHubHandler[] hubHandlers)
IDictionary<MethodHandler, IGroupRepository> cacheGroup
= new Dictionary<MethodHandler, IGroupRepository>(MethodHandler.UniqueEqualityComparer.Instance);

public void RegisterHandler(MethodHandler parent, StreamingHubHandler[] hubHandlers)
{
ThrowIfFrozen();

var handlers = VerifyDuplicate(hubHandlers);
var hashDict = new UniqueHashDictionary<StreamingHubHandler>(handlers);

lock (cache)
{
cache.Add(parent, hashDict);
}
cache.Add(parent, hashDict);
}

public static UniqueHashDictionary<StreamingHubHandler> GetHandlers(MethodHandler parent)
public UniqueHashDictionary<StreamingHubHandler> GetHandlers(MethodHandler parent)
=> cache[parent];

public void AddGroupRepository(MethodHandler parent, IGroupRepository repository)
{
return cache[parent];
ThrowIfFrozen();
cacheGroup.Add(parent, repository);
}

public IGroupRepository GetGroupRepository(MethodHandler parent)
=> cacheGroup[parent];

public void Freeze()
{
ThrowIfFrozen();
frozen = true;

#if NET8_0_OR_GREATER
cache = cache.ToFrozenDictionary(MethodHandler.UniqueEqualityComparer.Instance);
cacheGroup = cacheGroup.ToFrozenDictionary(MethodHandler.UniqueEqualityComparer.Instance);
#endif
}

void ThrowIfFrozen()
{
if (frozen) throw new InvalidOperationException($"Cannot modify the {nameof(StreamingHubHandlerRepository)}. The instance is already frozen.");
}

static (int, StreamingHubHandler)[] VerifyDuplicate(StreamingHubHandler[] hubHandlers)
Expand All @@ -44,17 +71,4 @@ public static UniqueHashDictionary<StreamingHubHandler> GetHandlers(MethodHandle

return list.ToArray();
}

public static void AddGroupRepository(MethodHandler parent, IGroupRepository repository)
{
lock (cacheGroup)
{
cacheGroup.Add(parent, repository);
}
}

public static IGroupRepository GetGroupRepository(MethodHandler parent)
{
return cacheGroup[parent];
}
}
9 changes: 7 additions & 2 deletions src/MagicOnion.Server/MagicOnionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ public static MagicOnionServiceDefinition BuildServerServiceDefinition(IServiceP
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var loggerMagicOnionEngine = loggerFactory.CreateLogger(LoggerNameMagicOnionEngine);
var loggerMethodHandler = loggerFactory.CreateLogger(LoggerNameMethodHandler);

var streamingHubHandlerRepository = serviceProvider.GetRequiredService<StreamingHubHandlerRepository>();

MagicOnionServerLog.BeginBuildServiceDefinition(loggerMagicOnionEngine);

var sw = Stopwatch.StartNew();
Expand Down Expand Up @@ -200,7 +203,7 @@ public static MagicOnionServiceDefinition BuildServerServiceDefinition(IServiceP
}

streamingHubHandlers.AddRange(tempStreamingHubHandlers!);
StreamingHubHandlerRepository.RegisterHandler(connectHandler, tempStreamingHubHandlers!.ToArray());
streamingHubHandlerRepository.RegisterHandler(connectHandler, tempStreamingHubHandlers!.ToArray());
IGroupRepositoryFactory factory;
var attr = classType.GetCustomAttribute<GroupConfigurationAttribute>(true);
if (attr != null)
Expand All @@ -211,7 +214,7 @@ public static MagicOnionServiceDefinition BuildServerServiceDefinition(IServiceP
{
factory = serviceProvider.GetRequiredService<IGroupRepositoryFactory>();
}
StreamingHubHandlerRepository.AddGroupRepository(connectHandler, factory.CreateRepository(options.MessageSerializer.Create(MethodType.DuplexStreaming, null)));
streamingHubHandlerRepository.AddGroupRepository(connectHandler, factory.CreateRepository(options.MessageSerializer.Create(MethodType.DuplexStreaming, null)));
}
}
}
Expand All @@ -220,6 +223,8 @@ public static MagicOnionServiceDefinition BuildServerServiceDefinition(IServiceP
ExceptionDispatchInfo.Capture(agex.InnerExceptions[0]).Throw();
}

streamingHubHandlerRepository.Freeze();

var result = new MagicOnionServiceDefinition(handlers.ToArray(), streamingHubHandlers.ToArray());

sw.Stop();
Expand Down
2 changes: 2 additions & 0 deletions src/MagicOnion.Server/MethodHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ public bool Equals(MethodHandler? other)

public class UniqueEqualityComparer : IEqualityComparer<MethodHandler>
{
public static UniqueEqualityComparer Instance { get; } = new();

public bool Equals(MethodHandler? x, MethodHandler? y)
{
return (x == null && y == null) || (x != null && y != null && x.methodHandlerId.Equals(y.methodHandlerId));
Expand Down

0 comments on commit dc90d87

Please sign in to comment.