ScheduledEvent.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. using Comal.Classes;
  2. using InABox.Core;
  3. using InABox.Database;
  4. using InABox.Scripting;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Runtime.Serialization;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. namespace PRS.Shared.Events;
  12. public class ScheduledEventDayOfWeek : BaseObject
  13. {
  14. [EditorSequence(1)]
  15. [Editable(Editable.Disabled)]
  16. public DayOfWeek DayOfWeek { get; set; }
  17. [EditorSequence(2)]
  18. [TimeOfDayEditor]
  19. public TimeSpan StartTime { get; set; } = TimeSpan.Zero;
  20. [EditorSequence(3)]
  21. [TimeOfDayEditor]
  22. public TimeSpan EndTime { get; set; } = new TimeSpan(23, 59, 59);
  23. [EditorSequence(4)]
  24. public bool Enabled { get; set; } = true;
  25. public ScheduledEventDayOfWeek()
  26. {
  27. }
  28. public ScheduledEventDayOfWeek(DayOfWeek dayOfWeek)
  29. {
  30. DayOfWeek = dayOfWeek;
  31. }
  32. static ScheduledEventDayOfWeek()
  33. {
  34. DefaultColumns.Add<ScheduledEventDayOfWeek>(x => x.DayOfWeek);
  35. DefaultColumns.Add<ScheduledEventDayOfWeek>(x => x.StartTime);
  36. DefaultColumns.Add<ScheduledEventDayOfWeek>(x => x.EndTime);
  37. }
  38. }
  39. /// <summary>
  40. /// Properties class to manage the timing of a scheduled event.
  41. /// </summary>
  42. /// <remarks>
  43. /// <para>
  44. /// This is fairly complex. First, we have the <see cref="Frequency"/> and <see cref="Period"/> properties. These function as expected.
  45. /// If <see cref="Frequency"/> is 3, and <see cref="Period"/> is <see cref="SchedulePeriod.Hour"/>, the event happens every three hours. Similarly,
  46. /// if <see cref="Frequency"/> is 4, and <see cref="Period"/> is <see cref="SchedulePeriod.Month"/>, the event happens every four months.
  47. /// </para>
  48. /// <para>
  49. /// However, the other properties are dependent on <see cref="Period"/>. If <see cref="Period"/> is <see cref="SchedulePeriod.Minute"/>,
  50. /// <see cref="SchedulePeriod.Hour"/> or <see cref="SchedulePeriod.Day"/> (that is, anything a day or smaller), the <see cref="DayOfWeekSettings"/>
  51. /// is used, which says which days of the week the schedule should occur, and at what time on those days.
  52. /// If the period is <see cref="SchedulePeriod.Day"/>, then only the <see cref="ScheduledEventDayOfWeek.StartTime"/> is used, and the event occurs
  53. /// at that time. Otherwise, the event occurs at regular intervals according to the frequency and period, beginning at
  54. /// <see cref="ScheduledEventDayOfWeek.StartTime"/> and running until <see cref="ScheduledEventDayOfWeek.EndTime"/>.
  55. /// </para>
  56. /// <para>
  57. /// Alternatively, if the period is greater than a day, <see cref="NextSchedule"/> is used, and whenever the schedule executes, it is updated by the
  58. /// frequency and period <i>from the due date</i>, and not from when the schedule actually occurred.
  59. /// </para>
  60. /// </remarks>
  61. public class ScheduledEventProperties : BaseObject
  62. {
  63. [EditorSequence(1)]
  64. public int Frequency { get; set; } = 1;
  65. [EditorSequence(2)]
  66. public SchedulePeriod Period { get; set; } = SchedulePeriod.Hour;
  67. [EditorSequence(3)]
  68. public DateTime NextSchedule { get; set; }
  69. [EditorSequence(4)]
  70. [Editable(Editable.Disabled)]
  71. [TimestampEditor]
  72. public DateTime LastExecution { get; set; }
  73. [EmbeddedListEditor(typeof(ScheduledEventDayOfWeek), AddRows = false)]
  74. public List<ScheduledEventDayOfWeek> DayOfWeekSettings { get; set; } = new()
  75. {
  76. new(DayOfWeek.Monday),
  77. new(DayOfWeek.Tuesday),
  78. new(DayOfWeek.Wednesday),
  79. new(DayOfWeek.Thursday),
  80. new(DayOfWeek.Friday),
  81. new(DayOfWeek.Saturday),
  82. new(DayOfWeek.Sunday),
  83. };
  84. [OnDeserializing]
  85. private void OnDeserialisingMethod(StreamingContext context)
  86. {
  87. DayOfWeekSettings.Clear();
  88. }
  89. }
  90. public class ScheduledEvent : IEvent<ScheduledEventDataModel>, IPropertiesEvent<ScheduledEventProperties>
  91. {
  92. public ScheduledEventProperties Properties { get; set; } = new();
  93. public IEventDataModelDefinition DataModelDefinition()
  94. {
  95. return new ScheduledEventDataModelDefinition();
  96. }
  97. public Notification GenerateNotification(ScheduledEventDataModel model)
  98. {
  99. var notification = new Notification();
  100. notification.Title = $"Scheduled event {model.Event.Code}: {model.Event.Description} has run.";
  101. notification.Description = $"Scheduled event {model.Event.Code}: {model.Event.Description} has run.";
  102. return notification;
  103. }
  104. public ScheduledEventProperties GetProperties()
  105. {
  106. return Properties;
  107. }
  108. public void SetProperties(ScheduledEventProperties properties)
  109. {
  110. Properties = properties;
  111. }
  112. }
  113. public class ScheduledEventDataModelDefinition : IEventDataModelDefinition
  114. {
  115. public IEventVariable? GetVariable(string name)
  116. {
  117. return null;
  118. }
  119. public IEnumerable<IEventVariable> GetVariables()
  120. {
  121. return [];
  122. }
  123. }
  124. public class ScheduledEventDataModel(Event ev) : IEventDataModel
  125. {
  126. public Event Event { get; set; } = ev;
  127. public bool TryGetVariable(string name, out object? value)
  128. {
  129. value = null;
  130. return false;
  131. }
  132. }
  133. #region Triggers
  134. [Caption("Custom Script")]
  135. public class ScriptScheduledEventTrigger : IEventTrigger<ScheduledEvent, ScheduledEventDataModel>
  136. {
  137. public string Description => "Custom Script";
  138. private ScriptDocument? _scriptDocument;
  139. private ScriptDocument? ScriptDocument
  140. {
  141. get
  142. {
  143. if(_scriptDocument is null && Script is not null)
  144. {
  145. _scriptDocument = new(Script);
  146. _scriptDocument.Compile();
  147. }
  148. return _scriptDocument;
  149. }
  150. }
  151. private string? _script;
  152. public string? Script
  153. {
  154. get => _script;
  155. set
  156. {
  157. if(_script != value)
  158. {
  159. _script = value;
  160. _scriptDocument = null;
  161. }
  162. }
  163. }
  164. public IEnumerable<string> ReferencedVariables => [];
  165. public string DefaultScript()
  166. {
  167. return @"using PRS.Shared.Events;
  168. public class Module
  169. {
  170. public bool Check(ScheduledEventDataModel model)
  171. {
  172. // Return true if the requirements are met for this event trigger.
  173. return true;
  174. }
  175. }";
  176. }
  177. public bool Check(ScheduledEventDataModel dataModel)
  178. {
  179. if (ScriptDocument is null) return false;
  180. return ScriptDocument.Execute(methodname: "Check", parameters: [dataModel]);
  181. }
  182. }
  183. #endregion
  184. #region Actions
  185. [Caption("Custom Script")]
  186. public class ScriptScheduledEventAction : IEventAction<ScheduledEvent>
  187. {
  188. private ScriptDocument? _scriptDocument;
  189. private ScriptDocument? ScriptDocument
  190. {
  191. get
  192. {
  193. if(_scriptDocument is null && Script is not null)
  194. {
  195. _scriptDocument = new(Script);
  196. _scriptDocument.SetValue("Result", null);
  197. _scriptDocument.Compile();
  198. }
  199. return _scriptDocument;
  200. }
  201. }
  202. private string? _script;
  203. public string? Script
  204. {
  205. get => _script;
  206. set
  207. {
  208. if(_script != value)
  209. {
  210. _script = value;
  211. _scriptDocument = null;
  212. }
  213. }
  214. }
  215. public IEnumerable<string> ReferencedVariables => [];
  216. public string Description => "Custom Script";
  217. public string DefaultScript()
  218. {
  219. return @"using PRS.Shared.Events;
  220. public class Module
  221. {
  222. public object? Result { get; set; }
  223. public bool Execute(ScheduledEventDataModel model)
  224. {
  225. // Do anything you want, and then save return-value to 'Result', or leave it as 'null' if no return value is needed.
  226. return true;
  227. }
  228. }";
  229. }
  230. public object? Execute(IEventDataModel dataModel)
  231. {
  232. if (ScriptDocument is null) return null;
  233. var model = dataModel.RootModel<ScheduledEventDataModel>();
  234. if(ScriptDocument.Execute(methodname: "Execute", parameters: [model]))
  235. {
  236. return ScriptDocument.GetValue("Result");
  237. }
  238. else
  239. {
  240. return null;
  241. }
  242. }
  243. }
  244. #endregion