PosterUtils.cs 6.7 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. public static class PosterUtils
  12. {
  13. private class EngineType
  14. {
  15. public Type Engine { get; set; }
  16. public Type Poster { get; set; }
  17. }
  18. private static EngineType[]? _posterEngines;
  19. private static Type[]? _posters = null;
  20. public static Type[] GetPosters()
  21. {
  22. _posters ??= CoreUtils.TypeList(
  23. AppDomain.CurrentDomain.GetAssemblies(),
  24. x => x.IsClass
  25. && !x.IsAbstract
  26. && !x.IsGenericType
  27. && x.HasInterface(typeof(IPoster<,>))).ToArray();
  28. return _posters;
  29. }
  30. private static EngineType[] GetPosterEngines()
  31. {
  32. _posterEngines ??= CoreUtils.TypeList(
  33. AppDomain.CurrentDomain.GetAssemblies(),
  34. x => x.IsClass
  35. && !x.IsAbstract
  36. && x.GetTypeInfo().GenericTypeParameters.Length == 1
  37. && x.HasInterface(typeof(IPosterEngine<,,>))
  38. ).Select(x => new EngineType
  39. {
  40. Engine = x,
  41. Poster = x.GetInterfaceDefinition(typeof(IPosterEngine<,,>))!.GenericTypeArguments[1].GetGenericTypeDefinition()
  42. }).ToArray();
  43. return _posterEngines;
  44. }
  45. private static PostableSettings FixPostableSettings<TPostable>(PostableSettings settings)
  46. where TPostable : Entity, IPostable
  47. {
  48. if (string.IsNullOrWhiteSpace(settings.PostableType))
  49. {
  50. settings.PostableType = typeof(TPostable).EntityName();
  51. }
  52. return settings;
  53. }
  54. public static PostableSettings LoadPostableSettings<T>()
  55. where T : Entity, IPostable
  56. {
  57. return FixPostableSettings<T>(new GlobalConfiguration<PostableSettings>(typeof(T).Name).Load());
  58. }
  59. public static void SavePostableSettings<T>(PostableSettings settings)
  60. where T : Entity, IPostable
  61. {
  62. new GlobalConfiguration<PostableSettings>(typeof(T).Name).Save(FixPostableSettings<T>(settings));
  63. }
  64. private static TSettings FixPosterSettings<TPostable, TSettings>(TSettings settings)
  65. where TPostable : IPostable
  66. where TSettings : PosterSettings, new()
  67. {
  68. if (string.IsNullOrWhiteSpace(settings.PostableType))
  69. {
  70. settings.PostableType = typeof(TPostable).EntityName();
  71. }
  72. return settings;
  73. }
  74. private static MethodInfo _loadPosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public)
  75. .Where(x => x.Name == nameof(LoadPosterSettings) && x.IsGenericMethod)
  76. .Single();
  77. private static MethodInfo _savePosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public)
  78. .Where(x => x.Name == nameof(SavePosterSettings) && x.IsGenericMethod)
  79. .Single();
  80. public static TSettings LoadPosterSettings<TPostable, TSettings>()
  81. where TPostable : IPostable
  82. where TSettings : PosterSettings, new()
  83. {
  84. return FixPosterSettings<TPostable, TSettings>(new GlobalConfiguration<TSettings>(typeof(TPostable).Name).Load());
  85. }
  86. public static PosterSettings LoadPosterSettings(Type TPostable, Type TSettings)
  87. {
  88. return (_loadPosterSettingsMethod.MakeGenericMethod(TPostable, TSettings).Invoke(null, Array.Empty<object>()) as PosterSettings)!;
  89. }
  90. public static void SavePosterSettings<TPostable, TSettings>(TSettings settings)
  91. where TPostable : IPostable
  92. where TSettings : PosterSettings, new()
  93. {
  94. new GlobalConfiguration<TSettings>(typeof(TPostable).Name).Save(FixPosterSettings<TPostable, TSettings>(settings));
  95. }
  96. public static void SavePosterSettings(Type TPostable, Type TSettings, PosterSettings settings)
  97. {
  98. _savePosterSettingsMethod.MakeGenericMethod(TPostable, TSettings).Invoke(null, new object[] { settings });
  99. }
  100. /// <summary>
  101. /// Get the <see cref="IPosterEngine{TPostable,TPoster,TSettings}"/> for <typeparamref name="T"/>
  102. /// based on the current <see cref="PostableSettings"/> for <typeparamref name="T"/>.
  103. /// </summary>
  104. /// <typeparam name="T"></typeparam>
  105. /// <returns></returns>
  106. public static Type GetEngine<T>()
  107. where T : Entity, IPostable, IRemotable, IPersistent, new()
  108. {
  109. var settings = LoadPostableSettings<T>();
  110. if (string.IsNullOrWhiteSpace(settings.PosterType))
  111. {
  112. throw new MissingSettingsException(typeof(T));
  113. }
  114. var poster = GetPosters()?.FirstOrDefault(x => x.EntityName() == settings.PosterType)!;
  115. return (GetPosterEngines().FirstOrDefault(x => poster.HasInterface(x.Poster))?.Engine
  116. ?? throw new Exception("No poster for the given settings.")).MakeGenericType(typeof(T));
  117. }
  118. public static IPosterEngine<T> CreateEngine<T>()
  119. where T : Entity, IPostable, IRemotable, IPersistent, new()
  120. {
  121. return (Activator.CreateInstance(GetEngine<T>()) as IPosterEngine<T>)!;
  122. }
  123. /// <summary>
  124. /// Process <paramref name="model"/> with the currently set <see cref="IPosterEngine{TPostable, TPoster, TSettings}"/>
  125. /// for <typeparamref name="T"/>.
  126. /// </summary>
  127. /// <typeparam name="T">The type of <paramref name="model"/> that needs to be processed.</typeparam>
  128. /// <param name="model"></param>
  129. /// <exception cref="EmptyPostException">If there are no items to post. In this case, nothing happens.</exception>
  130. /// <exception cref="RepostedException">If any of the <typeparamref name="T"/> have already been processed. In this case, nothing happens.</exception>
  131. /// <exception cref="MissingSettingsException">If the <see cref="PostableSettings"/> for <typeparamref name="T"/> do not exist.</exception>
  132. /// <exception cref="PostCancelledException">If the post has been cancelled by the user.</exception>
  133. /// <returns><see langword="true"/> if post was successful.</returns>
  134. ///
  135. public static bool Process<T>(IDataModel<T> model)
  136. where T : Entity, IPostable, IRemotable, IPersistent, new()
  137. {
  138. return CreateEngine<T>().Process(model);
  139. }
  140. }
  141. }