PosterUtils.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using InABox.Configuration;
  2. using InABox.Core.Postable;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Runtime;
  8. using System.Text;
  9. namespace InABox.Core
  10. {
  11. namespace Postable
  12. {
  13. public class MissingSettingsException : Exception
  14. {
  15. public Type PostableType { get; }
  16. public MissingSettingsException(Type postableType) : base($"No PostableSettings for ${postableType}")
  17. {
  18. PostableType = postableType;
  19. }
  20. }
  21. }
  22. public static class PosterUtils
  23. {
  24. private class EngineType
  25. {
  26. public Type Engine { get; set; }
  27. public Type Poster { get; set; }
  28. }
  29. private static EngineType[]? _posterEngines;
  30. private static Type[]? _posters = null;
  31. public static Type[] GetPosters()
  32. {
  33. _posters ??= CoreUtils.TypeList(
  34. AppDomain.CurrentDomain.GetAssemblies(),
  35. x => x.IsClass
  36. && !x.IsAbstract
  37. && !x.IsGenericType
  38. && x.HasInterface(typeof(IPoster<,>))).ToArray();
  39. return _posters;
  40. }
  41. private static EngineType[] GetPosterEngines()
  42. {
  43. _posterEngines ??= CoreUtils.TypeList(
  44. AppDomain.CurrentDomain.GetAssemblies(),
  45. x => x.IsClass
  46. && !x.IsAbstract
  47. && x.GetTypeInfo().GenericTypeParameters.Length == 1
  48. && x.HasInterface(typeof(IPosterEngine<,,>))
  49. ).Select(x => new EngineType
  50. {
  51. Engine = x,
  52. Poster = x.GetInterfaceDefinition(typeof(IPosterEngine<,,>))!.GenericTypeArguments[1].GetGenericTypeDefinition()
  53. }).ToArray();
  54. return _posterEngines;
  55. }
  56. private static PostableSettings FixPostableSettings<TPostable>(PostableSettings settings)
  57. where TPostable : Entity, IPostable
  58. {
  59. if (string.IsNullOrWhiteSpace(settings.PostableType))
  60. {
  61. settings.PostableType = typeof(TPostable).EntityName();
  62. }
  63. return settings;
  64. }
  65. public static PostableSettings LoadPostableSettings<T>()
  66. where T : Entity, IPostable
  67. {
  68. return FixPostableSettings<T>(new GlobalConfiguration<PostableSettings>(typeof(T).Name).Load());
  69. }
  70. public static void SavePostableSettings<T>(PostableSettings settings)
  71. where T : Entity, IPostable
  72. {
  73. new GlobalConfiguration<PostableSettings>(typeof(T).Name).Save(FixPostableSettings<T>(settings));
  74. }
  75. private static TSettings FixPosterSettings<TPostable, TSettings>(TSettings settings)
  76. where TPostable : IPostable
  77. where TSettings : PosterSettings, new()
  78. {
  79. if (string.IsNullOrWhiteSpace(settings.PostableType))
  80. {
  81. settings.PostableType = typeof(TPostable).EntityName();
  82. }
  83. return settings;
  84. }
  85. private static MethodInfo _loadPosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public)
  86. .Where(x => x.Name == nameof(LoadPosterSettings) && x.IsGenericMethod)
  87. .Single();
  88. private static MethodInfo _savePosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public)
  89. .Where(x => x.Name == nameof(SavePosterSettings) && x.IsGenericMethod)
  90. .Single();
  91. public static TSettings LoadPosterSettings<TPostable, TSettings>()
  92. where TPostable : IPostable
  93. where TSettings : PosterSettings, new()
  94. {
  95. return FixPosterSettings<TPostable, TSettings>(new GlobalConfiguration<TSettings>(typeof(TPostable).Name).Load());
  96. }
  97. public static PosterSettings LoadPosterSettings(Type TPostable, Type TSettings)
  98. {
  99. return (_loadPosterSettingsMethod.MakeGenericMethod(TPostable, TSettings).Invoke(null, Array.Empty<object>()) as PosterSettings)!;
  100. }
  101. public static void SavePosterSettings<TPostable, TSettings>(TSettings settings)
  102. where TPostable : IPostable
  103. where TSettings : PosterSettings, new()
  104. {
  105. new GlobalConfiguration<TSettings>(typeof(TPostable).Name).Save(FixPosterSettings<TPostable, TSettings>(settings));
  106. }
  107. public static void SavePosterSettings(Type TPostable, Type TSettings, PosterSettings settings)
  108. {
  109. _savePosterSettingsMethod.MakeGenericMethod(TPostable, TSettings).Invoke(null, new object[] { settings });
  110. }
  111. /// <summary>
  112. /// Get the <see cref="IPosterEngine{TPostable,TPoster,TSettings}"/> for <typeparamref name="T"/>
  113. /// based on the current <see cref="PostableSettings"/> for <typeparamref name="T"/>.
  114. /// </summary>
  115. /// <typeparam name="T"></typeparam>
  116. /// <returns></returns>
  117. public static Type GetEngine<T>()
  118. where T : Entity, IPostable, IRemotable, IPersistent, new()
  119. {
  120. var settings = LoadPostableSettings<T>();
  121. if (string.IsNullOrWhiteSpace(settings.PosterType))
  122. {
  123. throw new MissingSettingsException(typeof(T));
  124. }
  125. var poster = GetPosters()?.FirstOrDefault(x => x.EntityName() == settings.PosterType)!;
  126. return (GetPosterEngines().FirstOrDefault(x => poster.HasInterface(x.Poster))?.Engine
  127. ?? throw new Exception("No poster for the given settings.")).MakeGenericType(typeof(T));
  128. }
  129. public static IPosterEngine<T> CreateEngine<T>()
  130. where T : Entity, IPostable, IRemotable, IPersistent, new()
  131. {
  132. return (Activator.CreateInstance(GetEngine<T>()) as IPosterEngine<T>)!;
  133. }
  134. public static bool Process<T>(IEnumerable<T> entities)
  135. where T : Entity, IPostable, IRemotable, IPersistent, new()
  136. {
  137. return CreateEngine<T>().Process(entities);
  138. }
  139. }
  140. }