Add project files.

This commit is contained in:
Daniel Clark
2022-11-01 15:26:08 +00:00
parent daa7b59f22
commit 7e4f880821
408 changed files with 16863 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
using Microsoft.Extensions.Hosting;
namespace TheXamlGuy.Framework.Core
{
public class AppServices : IHostedService
{
private readonly IMediator mediator;
private readonly IDisposer disposer;
private readonly IInitialization initialization;
public AppServices(IMediator mediator,
IDisposer disposer,
IInitialization initialization)
{
this.mediator = mediator;
this.disposer = disposer;
this.initialization = initialization;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
mediator.Handle<Started>();
await initialization.InitializeAsync();
}
public Task StopAsync(CancellationToken cancellationToken)
{
disposer.Dispose(this);
return Task.CompletedTask;
}
}
}
+77
View File
@@ -0,0 +1,77 @@
using System;
using System.Collections;
using System.Linq;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;
namespace TheXamlGuy.Framework.Core
{
public class Disposer : IDisposer
{
private readonly ConditionalWeakTable<object, CompositeDisposable> subjects = new();
public void Add(object subject, params object[] objects)
{
CompositeDisposable disposables = subjects.GetOrCreateValue(subject);
foreach (IDisposable disposable in objects.OfType<IDisposable>())
{
disposables.Add(disposable);
}
foreach (object notDisposable in objects.Where(x => x is not IDisposable))
{
disposables.Add(Disposable.Create(() => FromNotDisposable(notDisposable)));
}
}
private void FromNotDisposable(object target)
{
if (target is IEnumerable enumerableTarget)
{
foreach (object? item in enumerableTarget)
{
FromNotDisposable(item);
}
}
if (target is IDisposable disposableTarget)
{
disposableTarget.Dispose();
}
if (target is not IDisposable)
{
Dispose(target);
}
}
public TDisposable Replace<TDisposable>(object subject, IDisposable disposer, TDisposable replacement) where TDisposable : IDisposable
{
CompositeDisposable disposables = subjects.GetOrCreateValue(subject);
if (disposer is not null)
{
disposables.Remove(disposer);
}
disposables.Add(replacement);
return replacement;
}
public void Remove(object subject, IDisposable disposer)
{
CompositeDisposable disposables = subjects.GetOrCreateValue(subject);
if (disposer is not null)
{
disposables.Remove(disposer);
}
}
public void Dispose(object subject)
{
if (subjects.TryGetValue(subject, out CompositeDisposable? disposables))
{
disposables?.Dispose();
}
}
}
}
@@ -0,0 +1,54 @@
using System.Collections.Concurrent;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reactive.Subjects;
namespace TheXamlGuy.Framework.Core
{
public class EventAggregator : IEventAggregator
{
private readonly ConcurrentDictionary<Type, object> subjects;
public EventAggregator(IEventAggregatorInvoker invoker)
{
subjects = new ConcurrentDictionary<Type, object>();
Dispatcher = new SynchronizationContextScheduler(SynchronizationContext.Current!);
Invoker = invoker;
Current = new EventAggregatorCurrent(this);
}
protected EventAggregator(EventAggregator eventAggregator)
{
subjects = eventAggregator.subjects;
Dispatcher = eventAggregator.Dispatcher;
Invoker = eventAggregator.Invoker;
Current = eventAggregator.Current;
}
public IEventAggregator Current { get; }
public IScheduler Dispatcher { get; }
public IEventAggregatorInvoker Invoker { get; }
public virtual IObservable<TEvent> GetEvent<TEvent>()
{
return GetObservable<TEvent>().Skip(1);
}
public virtual ISubject<TEvent> GetSubject<TEvent>()
{
return (ISubject<TEvent>)subjects.GetOrAdd(typeof(TEvent), x => new BehaviorSubject<TEvent>(default!));
}
public virtual void Publish<TEvent>(TEvent domainEvent)
{
GetSubject<TEvent>().OnNext(domainEvent);
}
protected virtual IObservable<TEvent> GetObservable<TEvent>()
{
return GetSubject<TEvent>().AsObservable();
}
}
}
@@ -0,0 +1,17 @@
using System.Reactive.Linq;
namespace TheXamlGuy.Framework.Core
{
public class EventAggregatorCurrent : EventAggregator
{
public EventAggregatorCurrent(EventAggregator eventAggregator) : base(eventAggregator)
{
}
public override IObservable<TEvent> GetEvent<TEvent>()
{
return GetObservable<TEvent>().Skip(0).Where(x => x != null);
}
}
}
@@ -0,0 +1,27 @@
using System.Reflection;
namespace TheXamlGuy.Framework.Core
{
public class EventAggregatorInvoker : IEventAggregatorInvoker
{
private readonly IScope scope;
public EventAggregatorInvoker(IScope scope)
{
this.scope = scope;
}
public void Invoke<TEvent>(object target, TEvent item, MethodInfo methodInfo)
{
using (scope.Enter<TEvent>(target))
{
methodInfo.Invoke(target, new object[] { item! });
}
}
public bool IsInvoking<TEvent>(object target)
{
return scope.IsActive<TEvent>(target);
}
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace TheXamlGuy.Framework.Core
{
public interface ICachable
{
}
}
+15
View File
@@ -0,0 +1,15 @@
using System;
namespace TheXamlGuy.Framework.Core
{
public interface IDisposer
{
void Add(object subject, params object[] objects);
TDisposable Replace<TDisposable>(object subject, IDisposable disposer, TDisposable replacement) where TDisposable : IDisposable;
void Remove(object subject, IDisposable disposer);
void Dispose(object subject);
}
}
@@ -0,0 +1,20 @@
using System.Reactive.Concurrency;
using System.Reactive.Subjects;
namespace TheXamlGuy.Framework.Core
{
public interface IEventAggregator
{
IEventAggregator Current { get; }
IScheduler Dispatcher { get; }
IEventAggregatorInvoker Invoker { get; }
IObservable<TEvent> GetEvent<TEvent>();
ISubject<TEvent> GetSubject<TEvent>();
void Publish<TEvent>(TEvent args);
}
}
@@ -0,0 +1,11 @@
using System.Reflection;
namespace TheXamlGuy.Framework.Core
{
public interface IEventAggregatorInvoker
{
void Invoke<TEvent>(object target, TEvent item, MethodInfo methodInfo);
bool IsInvoking<TEvent>(object target);
}
}
@@ -0,0 +1,6 @@
namespace TheXamlGuy.Framework.Core;
public interface IHasSensorPlacement
{
SensorPlacement Placement { get; }
}
@@ -0,0 +1,7 @@
namespace TheXamlGuy.Framework.Core
{
public interface IInitialization
{
Task InitializeAsync();
}
}
@@ -0,0 +1,7 @@
namespace TheXamlGuy.Framework.Core
{
public interface IInitializer
{
Task InitializeAsync();
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace TheXamlGuy.Framework.Core
{
public interface IKeepAlive
{
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace TheXamlGuy.Framework.Core
{
public interface IMediator
{
void Handle(object request, params object[] parameters);
TResponse? Handle<TResponse>(object request, params object[] parameters);
Task HandleAsync(object request, params object[] parameters);
Task HandleAsync(object request, CancellationToken cancellationToken, params object[] parameters);
Task<TResponse?> HandleAsync<TResponse>(object request, params object[] parameters);
Task<TResponse?> HandleAsync<TResponse>(object request, CancellationToken cancellationToken, params object[] parameters);
}
}
+11
View File
@@ -0,0 +1,11 @@
using System;
namespace TheXamlGuy.Framework.Core
{
public interface IScope
{
IDisposable Enter<T>(object target);
bool IsActive<T>(object target);
}
}
@@ -0,0 +1,9 @@
using System;
namespace TheXamlGuy.Framework.Core
{
public interface IServiceCreator<I>
{
object Create(Func<Type, object[], object> creator, params object[] parameters);
}
}
@@ -0,0 +1,9 @@
namespace TheXamlGuy.Framework.Core
{
public interface IServiceFactory
{
T? Get<T>(Type type);
T Create<T>(Type type, params object?[] parameters);
}
}
@@ -0,0 +1,6 @@
namespace TheXamlGuy.Framework.Core;
public interface ITwoStateSensor
{
SensorState State { get; }
}
@@ -0,0 +1,23 @@
namespace TheXamlGuy.Framework.Core
{
public class Initialization : IInitialization
{
private readonly Func<IEnumerable<IInitializer?>> factory;
public Initialization(Func<IEnumerable<IInitializer?>> factory)
{
this.factory = factory;
}
public async Task InitializeAsync()
{
foreach (IInitializer? initializer in factory())
{
if (initializer is not null)
{
await initializer.InitializeAsync();
}
}
}
}
}
+64
View File
@@ -0,0 +1,64 @@
namespace TheXamlGuy.Framework.Core;
public class Mediator : IMediator
{
private readonly IServiceFactory serviceFactory;
public Mediator(IServiceFactory serviceFactory)
{
this.serviceFactory = serviceFactory;
}
public void Handle(object request, params object[] parameters)
{
if (GetHandler(typeof(IMediatorHandler<>).MakeGenericType(request.GetType()), parameters) is { } handler)
{
handler.Handle((dynamic)request);
}
}
public TResponse? Handle<TResponse>(object request, params object[] parameters)
{
if (GetHandler(typeof(IMediatorHandler<,>).MakeGenericType(typeof(TResponse), request.GetType()), parameters) is { } handler)
{
return handler.Handle((dynamic)request);
}
return default;
}
public Task HandleAsync(object request, CancellationToken cancellationToken, params object[] parameters)
{
if (GetHandler(typeof(IMediatorAsyncHandler<>).MakeGenericType(request.GetType()), parameters) is { } handler)
{
return handler.Handle((dynamic)request, cancellationToken);
}
return Task.CompletedTask;
}
public Task HandleAsync(object request, params object[] parameters)
{
return HandleAsync(request, CancellationToken.None, parameters);
}
public Task<TResponse?> HandleAsync<TResponse>(object request, CancellationToken cancellationToken, params object[] parameters)
{
if (GetHandler(typeof(IMediatorAsyncHandler<,>).MakeGenericType(typeof(TResponse), request.GetType()), parameters) is { } handler)
{
return handler.Handle((dynamic)request, cancellationToken);
}
return Task.FromResult<TResponse?>(default);
}
public Task<TResponse?> HandleAsync<TResponse>(object request, params object[] parameters)
{
return HandleAsync<TResponse?>(request, CancellationToken.None, parameters);
}
private dynamic? GetHandler(Type type, params object[] parameters)
{
return parameters.Length == 0 ? serviceFactory.Get<object>(type) : serviceFactory.Create<object>(type, parameters);
}
}
+22
View File
@@ -0,0 +1,22 @@
using System;
using System.Collections.Concurrent;
using System.Reactive.Disposables;
namespace TheXamlGuy.Framework.Core
{
public class Scope : IScope
{
private readonly ConcurrentDictionary<object, bool> scopes = new ConcurrentDictionary<object, bool>();
public IDisposable Enter<T>(object target)
{
scopes.TryAdd(Tuple.Create(target, typeof(T)), true);
return Disposable.Create(() => scopes.TryRemove(Tuple.Create(target, typeof(T)), out bool value));
}
public bool IsActive<T>(object target)
{
return scopes.ContainsKey(Tuple.Create(target, typeof(T)));
}
}
}
@@ -0,0 +1,9 @@
namespace TheXamlGuy.Framework.Core;
public enum SensorPlacement
{
Left = 0,
Top = 1,
Right = 3,
Bottom = 4,
}
+7
View File
@@ -0,0 +1,7 @@
namespace TheXamlGuy.Framework.Core;
public enum SensorState
{
Off = 0,
On = 1
}
@@ -0,0 +1,10 @@
namespace TheXamlGuy.Framework.Core
{
public class ServiceCreator<I, T> : IServiceCreator<I>
{
public virtual object Create(Func<Type, object[], object> creator, params object[] parameters)
{
return creator(typeof(T), parameters);
}
}
}
@@ -0,0 +1,25 @@
namespace TheXamlGuy.Framework.Core;
public class ServiceFactory : IServiceFactory
{
private readonly Func<Type, object?> factory;
private readonly Func<Type, object?[], object> creator;
public ServiceFactory(Func<Type, object?> factory, Func<Type, object?[], object> creator)
{
this.factory = factory;
this.creator = creator;
}
public T? Get<T>(Type type)
{
T? value = (T?)factory(type);
return value;
}
public T Create<T>(Type type, params object?[] parameters)
{
dynamic? lookup = factory(typeof(IServiceCreator<>).MakeGenericType(type));
return lookup is not null ? (T)lookup.Create(creator, parameters) : (T)creator(type, parameters);
}
}
@@ -0,0 +1,25 @@
using System.Reflection;
namespace TheXamlGuy.Framework.Core
{
internal class ServiceFactoryDescriptor
{
private readonly IServiceFactory serviceFactory;
public ServiceFactoryDescriptor(IServiceFactory serviceFactory)
{
this.serviceFactory = serviceFactory;
}
public object? Create(Type type)
{
MethodInfo? methodInfo = typeof(ServiceFactoryDescriptor).GetMethod(nameof(Create), BindingFlags.NonPublic | BindingFlags.Instance);
return methodInfo?.MakeGenericMethod(type).Invoke(this, new object[] { type });
}
private T Create<T>(Type type)
{
return serviceFactory.Create<T>(type);
}
}
}
+4
View File
@@ -0,0 +1,4 @@
namespace TheXamlGuy.Framework.Core
{
public record Started;
}