Skip to content

Instantly share code, notes, and snippets.

@analogrelay
Last active June 14, 2017 03:26
Show Gist options
  • Save analogrelay/1c3b1ad0fe1b7c488ed9a31faca500ad to your computer and use it in GitHub Desktop.
Save analogrelay/1c3b1ad0fe1b7c488ed9a31faca500ad to your computer and use it in GitHub Desktop.
Hub<anything>
// Treat Client Proxies kinda like Formatters; Hub<T> just tries to get an IClientProxyFactory<T> from DI and invokes it.
// We provide one for `dynamic` and another that can be registered as an open-generic and generated code at runtime.
// Users can provide custom implementations for anything.
public interface IClientProxy {
Task InvokeAsync(string method, params object[] args);
}
public interface IClientProxyFactory<T> {
T CreateProxy(IClientProxy proxy); // <-- may need some caching logic
}
public class HubProxies {
public IClientProxy All { get; }
public IClientProxy User(string userId);
public IClientProxy Group(string groupName);
public IClientProxy Client(string clientId);
}
public class HubProxies<T> {
private readonly IClientProxyFactory<T> _factory;
private readonly HubProxies _proxies;
public HubProxies(IClientProxyFactory<T> factory, HubProxies proxies) {
_factory = factory;
_proxies = proxies;
}
public new T All => _factory.CreateProxy(_proxies.All);
public new T User(string userId) => _factory.CreateProxy(_proxies.User(userId));
public new T Group(string groupName) => _factory.CreateProxy(_proxies.Group(groupName));
public new T Client(string clientId) => _factory.CreateProxy(_proxies.Client(clientId));
}
public abstract class Hub {
public HubProxies Clients { get; }
public virtual void Initialize(IServiceProvider services) {}
}
public abstract class Hub<T> : Hub {
private IHubClientAdaptor<T> _adaptor;
public new HubProxies<T> Clients => new HubProxies(_adaptor, base.Clients);
public override void Initialize(IServiceProvider services) {
_adaptor = services.GetRequiredService<IHubClientAdaptor<T>>();
}
}
public class DynamicClientProxyFactory : IClientProxyFactory<dynamic> {
public dynamic CreateProxy(IClientProxy client) => new DynamicClientProxy(client); // <-- implements DynamicObject by wrapping IClientProxy
}
public class GeneratedClientProxyFactory<T> : IClientProxyFactory<T> {
public T CreateProxy(IClientProxy client) {
// Use Reflection Emit to generate a class implementing T, then create an instance and return it.
}
}
public class MyManualClientProxyFactory : IClientProxyFactory<IChatProxy> {
public IChatProxy CreateProxy(IClientProxy client) {
// A user could just create their own adaptor manually, or our Proxy generator could do it for them?
}
}
public static class SignalRServiceCollectionExtensions {
public static void AddSignalR(this IServiceCollection services) {
// ... other stuff ...
services.AddSingleton<IClientProxyFactory<dynamic>, DynamicClientProxyFactory>();
services.AddSingleton<IClientProxyFactory<>, GeneratedClientProxyFactory<>>();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment