123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- using InABox.Clients;
- using InABox.Configuration;
- using InABox.Core.Postable;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Text;
- namespace InABox.Core
- {
- public interface IGlobalSettingsPosterEngine
- {
- IGlobalPosterSettings GetGlobalSettings();
- void SaveGlobalSettings(IGlobalPosterSettings settings);
- }
- /// <summary>
- /// Marks an <see cref="IPosterEngine{TPostable}"/> as having global settings, not specific to certain entities.
- /// </summary>
- /// <typeparam name="TGlobalSettings"></typeparam>
- public interface IGlobalSettingsPosterEngine<TPoster, TGlobalSettings> : IGlobalSettingsPosterEngine
- where TPoster : IGlobalSettingsPoster<TGlobalSettings>
- where TGlobalSettings : BaseObject, IGlobalPosterSettings, new()
- {
- new TGlobalSettings GetGlobalSettings() => PosterUtils.LoadGlobalPosterSettings<TGlobalSettings>();
- void SaveGlobalSettings(TGlobalSettings settings) => PosterUtils.SaveGlobalPosterSettings(settings);
- IGlobalPosterSettings IGlobalSettingsPosterEngine.GetGlobalSettings() => GetGlobalSettings();
- void IGlobalSettingsPosterEngine.SaveGlobalSettings(IGlobalPosterSettings settings)
- {
- if(settings is TGlobalSettings globalSettings)
- {
- SaveGlobalSettings(globalSettings);
- }
- }
- }
- public interface IPosterEngine<TPostable>
- where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
- {
- IPostResult<TPostable>? Process(IDataModel<TPostable> model);
- }
- public interface IPosterEngine<TPostable, TPoster, TSettings> : IPosterEngine<TPostable>
- where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
- where TPoster : IPoster<TPostable, TSettings>
- where TSettings : PosterSettings, new()
- {
- }
- /// <summary>
- /// A base class for all <see cref="IPosterEngine{TPostable}"/>. A concrete instance of this will be loaded by
- /// <see cref="PosterUtils.Process{T}(IDataModel{T})"/>; a new instance is guaranteed to be created each time that method is called.
- /// </summary>
- /// <typeparam name="TPostable"></typeparam>
- /// <typeparam name="TPoster"></typeparam>
- /// <typeparam name="TSettings"></typeparam>
- public abstract class PosterEngine<TPostable, TPoster, TSettings> : IPosterEngine<TPostable, TPoster, TSettings>
- where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
- where TPoster : class, IPoster<TPostable, TSettings>
- where TSettings : PosterSettings, new()
- {
- protected TPoster Poster;
- public PosterEngine()
- {
- Poster = CreatePoster();
- }
- private static readonly Type? PosterType = PosterUtils.GetPoster(typeof(TPoster));
- protected virtual TPoster CreatePoster()
- {
- var poster = (Activator.CreateInstance(PosterType!) as TPoster)!;
- poster.Settings = GetSettings();
- if(this is IGlobalSettingsPosterEngine globalSettingsEngine && poster is IGlobalSettingsPoster globalSettingsPoster)
- {
- globalSettingsPoster.GlobalSettings = globalSettingsEngine.GetGlobalSettings();
- }
- return poster;
- }
- private TSettings? _settings;
- protected TSettings GetSettings()
- {
- _settings ??= PosterUtils.LoadPosterSettings<TPostable, TSettings>();
- return _settings;
- }
- protected void SaveSettings(TSettings settings)
- {
- _settings = settings;
- PosterUtils.SavePosterSettings<TPostable, TSettings>(_settings);
- }
- /// <summary>
- /// Returns the <see cref="TSettings.Script"/>, if <see cref="TSettings.ScriptEnabled"/> is <see langword="true"/>;
- /// otherwise, returns <see langword="null"/>.
- /// </summary>
- protected string? GetScript()
- {
- var settings = GetSettings();
- return settings.ScriptEnabled ? settings.Script : null;
- }
- protected abstract IPostResult<TPostable> DoProcess(IDataModel<TPostable> model);
- /// <summary>
- /// Process the <paramref name="model"/> before loading;
- /// </summary>
- /// <param name="model"></param>
- /// <returns><see langword="false"/> if the processing must be cancelled.</returns>
- public abstract bool BeforePost(IDataModel<TPostable> model);
- /// <summary>
- /// Prior to saving the <typeparamref name="TPostable"/> entities, make any necessary changes to those entities.
- /// This is only called if <see cref="Process(IDataModel{TPostable})"/> returned <see langword="true"/>.
- /// </summary>
- /// <param name="model"></param>
- /// <param name="result">The result object returned by <see cref="DoProcess(IDataModel{TPostable})"/></param>
- public abstract void AfterPost(IDataModel<TPostable> model, IPostResult<TPostable> result);
- private static void SetFailed(IList<TPostable> entities)
- {
- foreach (var post in entities)
- {
- post.PostedStatus = PostedStatus.PostFailed;
- post.PostedNote = "Post failed.";
- }
- new Client<TPostable>().Save(entities, "Post failed by user.");
- }
- public IPostResult<TPostable>? Process(IDataModel<TPostable> model)
- {
- if (!BeforePost(model))
- {
- return null;
- }
- // Add posted flags; if the columns is null, then we don't need to worry, because it will be loaded.
- model.GetColumns<TPostable>()?.Add(x => x.PostedStatus)
- .Add(x => x.Posted)
- .Add(x => x.PostedNote);
- model.LoadModel();
- var data = model.GetTable<TPostable>();
- if (!data.Rows.Any())
- {
- throw new EmptyPostException();
- }
- if(data.Rows.Any(x => x.Get<TPostable, PostedStatus>(x => x.PostedStatus) == PostedStatus.Posted))
- {
- throw new RepostedException();
- }
- try
- {
- var result = DoProcess(model);
- AfterPost(model, result);
- Client.Save(result.PostedEntities, "Posted by user.");
- foreach (var (type, fragments) in result.Fragments)
- {
- Client.Create(type).Save(fragments.Cast<Entity>(), "");
- }
- return result;
- }
- catch (PostCancelledException)
- {
- var entities = data.ToObjects<TPostable>().ToList();
- SetFailed(entities);
- throw;
- }
- catch (MissingSettingException)
- {
- throw;
- }
- catch (PostFailedMessageException)
- {
- throw;
- }
- catch(Exception e)
- {
- Logger.Send(LogType.Error, "", $"Post Failed: {CoreUtils.FormatException(e)}");
- var entities = data.ToObjects<TPostable>().ToList();
- SetFailed(entities);
- throw;
- }
- }
- }
- public interface IPullerEngine<TPostable>
- where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
- {
- IPullResult<TPostable>? Pull();
- }
- public interface IPullerEngine<TPostable, TPoster> : IPullerEngine<TPostable>
- where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
- {
- IPullResult<TPostable> DoPull();
- IPullResult<TPostable>? IPullerEngine<TPostable>.Pull()
- {
- try
- {
- var result = DoPull();
- return result;
- }
- catch (PullCancelledException)
- {
- throw;
- }
- catch (MissingSettingException)
- {
- throw;
- }
- catch (PullFailedMessageException)
- {
- throw;
- }
- catch(Exception e)
- {
- Logger.Send(LogType.Error, "", $"Post Failed: {CoreUtils.FormatException(e)}");
- throw;
- }
- }
- }
- }
|