Skip to content

Commit

Permalink
refactor!(core): redesign all api. (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
DingpingZhang committed Sep 2, 2021
1 parent 148fcc7 commit bc06b2a
Show file tree
Hide file tree
Showing 43 changed files with 694 additions and 864 deletions.
14 changes: 0 additions & 14 deletions HandyIpc.Core/ClientBuilder.cs

This file was deleted.

46 changes: 0 additions & 46 deletions HandyIpc.Core/Configuration.cs

This file was deleted.

9 changes: 5 additions & 4 deletions HandyIpc.Core/Client.cs → HandyIpc.Core/ContainerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

namespace HandyIpc
{
internal sealed class Client : IClient
internal sealed class ContainerClient : IContainerClient
{
private readonly SenderBase _sender;
private readonly Sender _sender;
private readonly ISerializer _serializer;
private readonly ConcurrentDictionary<Type, object> _typeInstanceMapping = new();

private bool _isDisposed;

public Client(SenderBase sender, ISerializer serializer)
public ContainerClient(Sender sender, ISerializer serializer)
{
_sender = sender;
_serializer = serializer;
Expand All @@ -22,7 +22,7 @@ public T Resolve<T>(string key)
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(IClient));
throw new ObjectDisposedException(nameof(IContainerClient));
}

return (T)_typeInstanceMapping.GetOrAdd(typeof(T), interfaceType =>
Expand All @@ -37,6 +37,7 @@ public void Dispose()
_isDisposed = true;

_typeInstanceMapping.Clear();
_sender.Dispose();
}
}
}
39 changes: 39 additions & 0 deletions HandyIpc.Core/ContainerClientBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using HandyIpc.Core;

namespace HandyIpc
{
public class ContainerClientBuilder : IClientConfiguration
{
private Func<IClient> _clientFactory = () => throw new InvalidOperationException(
$"Must invoke the {nameof(IServerConfiguration)}.Use(Func<{nameof(IClient)}> factory) method " +
"to register a factory before invoking the Build method.");
private Func<ISerializer> _serializerFactory = () => throw new InvalidOperationException(
$"Must invoke the {nameof(IServerConfiguration)}.Use(Func<{nameof(ISerializer)}> factory) method " +
"to register a factory before invoking the Build method.");
private Func<ILogger> _loggerFactory = () => new DebugLogger();

public IClientConfiguration Use(Func<ISerializer> factory)
{
_serializerFactory = factory;
return this;
}

public IClientConfiguration Use(Func<ILogger> factory)
{
_loggerFactory = factory;
return this;
}

public IClientConfiguration Use(Func<IClient> factory)
{
_clientFactory = factory;
return this;
}

public IContainerClient Build()
{
return new ContainerClient(new Sender(_clientFactory()), _serializerFactory());
}
}
}
7 changes: 7 additions & 0 deletions HandyIpc.Core/ContainerClientExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace HandyIpc
{
public static class ContainerClientExtensions
{
public static T Resolve<T>(this IContainerClient client) => client.Resolve<T>(typeof(T).GetDefaultKey());
}
}
36 changes: 36 additions & 0 deletions HandyIpc.Core/ContainerRegistryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;

namespace HandyIpc
{
public static class ContainerRegistryExtensions
{
public static IContainerRegistry Register<TInterface, TImpl>(this IContainerRegistry registry, string? key = null)
where TInterface : class
where TImpl : TInterface, new()
{
return registry.Register<TInterface>(() => new TImpl(), key);
}

public static IContainerRegistry Register<TInterface>(this IContainerRegistry registry, Func<TInterface> factory, string? key = null)
where TInterface : class
{
key ??= typeof(TInterface).GetDefaultKey();
return registry.Register(typeof(TInterface), factory, key);
}

public static IContainerRegistry Register(this IContainerRegistry registry, Type interfaceType, Type classType, string? key = null)
{
key ??= interfaceType.GetDefaultKey();
return classType.ContainsGenericParameters
? registry.Register(interfaceType, GenericFactory, key)
: registry.Register(interfaceType, () => Activator.CreateInstance(classType), key);

// Local Method
object GenericFactory(Type[] genericTypes)
{
var constructedClassType = classType.MakeGenericType(genericTypes);
return Activator.CreateInstance(constructedClassType);
}
}
}
}
108 changes: 108 additions & 0 deletions HandyIpc.Core/ContainerServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using HandyIpc.Core;

namespace HandyIpc
{
internal sealed class ContainerServer : IContainerServer
{
private readonly IServer _server;
private readonly Middleware _middleware;
private readonly ISerializer _serializer;
private readonly ILogger _logger;

private CancellationTokenSource? _cancellationTokenSource;

public bool IsRunning { get; private set; }

public ContainerServer(IServer server, Middleware middleware, ISerializer serializer, ILogger logger)
{
_server = server;
_middleware = middleware;
_serializer = serializer;
_logger = logger;
}

public void Start()
{
if (_cancellationTokenSource is null or { IsCancellationRequested: true })
{
_cancellationTokenSource = new CancellationTokenSource();
}

#pragma warning disable 4014
// Async run the server without waiting.
StartAsync(_cancellationTokenSource.Token);
#pragma warning restore 4014

IsRunning = true;
}

public void Stop()
{
_cancellationTokenSource?.Cancel();
IsRunning = false;
}

public void Dispose()
{
Stop();
_server.Dispose();
}

private async Task StartAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
IConnection connection = await _server.WaitForConnectionAsync();
RequestHandler handler = _middleware.ToHandler(_serializer, _logger);

if (token.IsCancellationRequested)
{
break;
}

// Do not await the request handler, and go to await next stream connection directly.
#pragma warning disable 4014
HandleRequestAsync(connection, handler, token);
#pragma warning restore 4014
}
}

private async Task HandleRequestAsync(IConnection connection, RequestHandler handler, CancellationToken token)
{
try
{
while (true)
{
if (token.IsCancellationRequested)
{
break;
}

byte[] buffer = await connection.ReadAsync(token);
if (buffer.Length == 0)
{
continue;
}

byte[] output = await handler(buffer);
await connection.WriteAsync(output, token);
}
}
catch (OperationCanceledException)
{
// Ignore
}
catch (Exception e)
{
_logger.Error("Unexpected exception occurred when starting the server instance.", e);
}
finally
{
connection.Dispose();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,50 @@

namespace HandyIpc
{
internal class ServerBuilder : Configuration, IServerBuilder
public class ContainerServerBuilder : IServerConfiguration, IContainerRegistry
{
private readonly List<(string key, Type type, Func<object> factory)> _interfaceMap = new();
private readonly List<(string key, Type type, Func<Type[], object> factory)> _genericInterfaceMap = new();

public IServerRegistry Register(Type interfaceType, Func<object> factory, string key)
private Func<IServer> _serverFactory = () => throw new InvalidOperationException(
$"Must invoke the {nameof(IServerConfiguration)}.Use(Func<{nameof(IServer)}> factory) method " +
"to register a factory before invoking the Build method.");
private Func<ISerializer> _serializerFactory = () => throw new InvalidOperationException(
$"Must invoke the {nameof(IServerConfiguration)}.Use(Func<{nameof(ISerializer)}> factory) method " +
"to register a factory before invoking the Build method.");
private Func<ILogger> _loggerFactory = () => new DebugLogger();

public IServerConfiguration Use(Func<ISerializer> factory)
{
_serializerFactory = factory;
return this;
}

public IServerConfiguration Use(Func<ILogger> factory)
{
_loggerFactory = factory;
return this;
}

public IServerConfiguration Use(Func<IServer> factory)
{
_serverFactory = factory;
return this;
}

public IContainerRegistry Register(Type interfaceType, Func<object> factory, string key)
{
_interfaceMap.Add((key, interfaceType, factory));
return this;
}

public IServerRegistry Register(Type interfaceType, Func<Type[], object> factory, string key)
public IContainerRegistry Register(Type interfaceType, Func<Type[], object> factory, string key)
{
_genericInterfaceMap.Add((key, interfaceType, factory));
return this;
}

public IServer Build()
public IContainerServer Build()
{
Dictionary<string, Middleware> map = new();
foreach (var (key, type, factory) in _interfaceMap)
Expand All @@ -39,20 +65,13 @@ public IServer Build()
map.Add(key, methodDispatcher);
}

Middleware middleware = BuildBasicMiddleware().Then(Middlewares.GetInterfaceMiddleware(map));

ReceiverBase receiver = ReceiverFactory();
ILogger logger = LoggerFactory();
receiver.SetLogger(logger);
return new Server(receiver, middleware, SerializerFactory(), logger);
}

private static Middleware BuildBasicMiddleware()
{
return Middlewares.Compose(
Middleware middleware = Middlewares.Compose(
Middlewares.Heartbeat,
Middlewares.ExceptionHandler,
Middlewares.RequestParser);
Middlewares.RequestParser,
Middlewares.GetInterfaceMiddleware(map));

return new ContainerServer(_serverFactory(), middleware, _serializerFactory(), _loggerFactory());
}

private static IMethodDispatcher CreateDispatcher(Type interfaceType, Func<object> factory)
Expand Down
14 changes: 0 additions & 14 deletions HandyIpc.Core/Core/ReceiverBase.cs

This file was deleted.

Loading

0 comments on commit bc06b2a

Please sign in to comment.