Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
TimedEventNode.cs
1using System;
3using System.Threading.Tasks;
4using Waher.Content;
5using Waher.Events;
11
13{
17 public abstract class TimedEventNode : EventNode
18 {
19 private static readonly Scheduler pendingEvents = new Scheduler();
20
21 private DateTime timepointUtc = DateTime.MaxValue;
22 private Duration recurrence = Duration.Zero;
23
28 : base()
29 {
30 }
31
37 public abstract Task<EventTimepointUtc> GetEventTimepointUtc(EvaluationArguments Arguments);
38
42 public class EventTimepointUtc
43 {
48 {
49 this.CurrentUtc = DateTime.UtcNow;
50 this.NextUtc = DateTime.MaxValue;
51 this.Duration = Duration.Zero;
52 }
53
58 public EventTimepointUtc(DateTime Next)
59 {
60 this.CurrentUtc = DateTime.UtcNow;
61 this.NextUtc = Next.Kind == DateTimeKind.Utc ? Next : Next.ToUniversalTime();
62 this.Duration = Duration.Zero;
63 }
64
70 {
71 this.CurrentUtc = DateTime.UtcNow;
72 this.NextUtc = this.CurrentUtc + Duration;
73 this.Duration = Duration;
74 }
75
81 public EventTimepointUtc(DateTime Next, Duration Duration)
82 {
83 this.CurrentUtc = DateTime.UtcNow;
84 this.NextUtc = Next.Kind == DateTimeKind.Utc ? Next : Next.ToUniversalTime();
85 this.Duration = Duration;
86 }
87
94 public EventTimepointUtc(DateTime Current, DateTime Next, Duration Duration)
95 {
96 this.CurrentUtc = Current.Kind == DateTimeKind.Utc ? Current : Current.ToUniversalTime();
97 this.NextUtc = Next.Kind == DateTimeKind.Utc ? Next : Next.ToUniversalTime();
98 this.Duration = Duration;
99 }
100
104 public DateTime CurrentUtc { get; }
105
109 public DateTime NextUtc { get; }
110
114 public Duration Duration { get; }
115 }
116
126 public override async Task<EventHandlerReference> Register(int EventIndex,
128 {
129 EventTimepointUtc TP = await this.GetEventTimepointUtc(Arguments);
130
131 this.timepointUtc = TP.NextUtc;
132 this.recurrence = Event.HasNewState ? Duration.Zero : TP.Duration;
133
134 if (this.timepointUtc == DateTime.MaxValue)
135 return null;
136
137 if (this.timepointUtc <= DateTime.UtcNow)
138 return new EventHandlerReference(null, true);
139
140 TimepointEventHandler Handler = new TimepointEventHandler(Arguments, EventIndex, this.timepointUtc, this.recurrence);
141 await Database.Insert(Handler);
142
143 this.timepointUtc = pendingEvents.Add(this.timepointUtc, this.EventElapsed, Handler);
144
145 bool SuppressSamples;
146
147 try
148 {
149 SuppressSamples = await Event.GetSuppressSample(Arguments);
150 }
151 catch (Exception ex)
152 {
153 Log.Exception(ex);
154 SuppressSamples = false;
155 }
156
157 if (!SuppressSamples)
158 this.AddIntervalToProfiler(TP, Arguments.Profiler);
159
160 return null;
161 }
162
167 public async Task ReregisterOnStart(TimepointEventHandler Handler)
168 {
169 EventTimepointUtc TP = new EventTimepointUtc(Handler.Timepoint, Handler.Recurrence);
170
171 this.timepointUtc = Handler.Timepoint;
172 this.recurrence = Handler.Recurrence;
173
174 if (this.timepointUtc <= DateTime.UtcNow)
175 await this.EventElapsed(Handler);
176 else if (this.timepointUtc < DateTime.MaxValue)
177 this.timepointUtc = pendingEvents.Add(this.timepointUtc, this.EventElapsed, Handler);
178 }
179
180 private void AddIntervalToProfiler(EventTimepointUtc TP, Profiler Profiler)
181 {
182 if (Profiler is null)
183 return;
184
185 string Label;
186
187 if (TP.Duration > Duration.Zero)
188 Label = TP.Duration.ToString();
189 else
190 {
191 TimeSpan TS = TP.NextUtc - TP.CurrentUtc;
192 double d = TS.TotalDays;
193 if (d > 1)
194 Label = d.ToString("F2") + " days";
195 else
196 {
197 d = TS.TotalHours;
198 if (d > 1)
199 Label = d.ToString("F2") + " h";
200 else
201 {
202 d = TS.TotalMinutes;
203 if (d > 1)
204 Label = d.ToString("F2") + " min";
205 else
206 {
207 d = TS.TotalSeconds;
208 if (d > 1)
209 Label = d.ToString("F2") + " s";
210 else
211 {
212 d = TS.TotalMilliseconds;
213 Label = d.ToString("F2") + " ms";
214 }
215 }
216 }
217 }
218 }
219
220 if (TP.NextUtc != DateTime.MaxValue)
221 Profiler.Interval(TP.CurrentUtc, TP.NextUtc, Label);
222 }
223
228 public void Register(TimepointEventHandler Handler)
229 {
230 this.recurrence = Handler.Recurrence;
231 this.timepointUtc = pendingEvents.Add(Handler.Timepoint, this.EventElapsed, Handler);
232 }
233
239 public override Task Unregister(int EventIndex, EvaluationArguments Arguments)
240 {
241 if (this.timepointUtc != DateTime.MaxValue)
242 {
243 pendingEvents.Remove(this.timepointUtc);
244 this.timepointUtc = DateTime.MaxValue;
245 this.recurrence = Duration.Zero;
246 }
247
248 return Task.CompletedTask; // Do nothing by default.
249 }
250
251 private Task EventElapsed(object State)
252 {
253 return this.EventElapsed((TimepointEventHandler)State);
254 }
255
260 public async Task EventElapsed(TimepointEventHandler Handler)
261 {
262 StateMachineProcessor.EventRecord Record = null;
263 Duration Recurrence = Handler.Recurrence;
264 bool Recurring = Recurrence > Duration.Zero;
265 DateTime From = Handler.Timepoint;
266
267 try
268 {
269 Record = await StateMachineProcessor.ProcessEvent(Handler, null, null);
270
271 if (Recurring && !(Record is null))
272 {
273 DateTime UtcNow = DateTime.UtcNow;
274
275 do
276 {
277 Handler.Timepoint += Recurrence;
278 }
279 while (Handler.Timepoint <= UtcNow);
280
281 this.recurrence = Recurrence;
282 this.timepointUtc = pendingEvents.Add(Handler.Timepoint, this.EventElapsed, Handler);
283
284 if (!Record.SuppressSamples)
285 this.AddIntervalToProfiler(new EventTimepointUtc(From, Handler.Timepoint, Recurrence), Record.CacheRecord.Profiler);
286
287 await Database.Update(Handler);
288 }
289 else
290 await Database.Delete(Handler);
291 }
292 catch (KeyNotFoundException)
293 {
294 // Already deleted, since state changed.
295 }
296 catch (Exception ex)
297 {
298 Log.Exception(ex);
299
300 if (!(Record.CacheRecord.Profiler is null) && !Record.SuppressSamples)
301 {
302 int NoteNr = Record.CacheRecord.Profiler.AddNote(ex);
303 Record.CacheRecord.Profiler?.Exception(ex, "Note" + NoteNr);
304 }
305 }
306 }
307
311 internal static void ClearPendingEvents()
312 {
313 pendingEvents.Clear();
314 }
315 }
316}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:1211
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:1291
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:97
Class that keeps track of events and timing.
Definition: Profiler.cs:68
void Interval(DateTime From, DateTime To, string Label)
Records an interval in the main thread.
Definition: Profiler.cs:311
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
Definition: Scheduler.cs:14
Contains information required for evaluating script in a state-machine.
Abstract base class for State-Machine event nodes.
Definition: EventNode.cs:11
Contains information about when a timed event elapses, in UTC time coordinates.
EventTimepointUtc(Duration Duration)
Contains information about when a timed event elapses.
EventTimepointUtc(DateTime Next, Duration Duration)
Contains information about when a timed event elapses.
EventTimepointUtc(DateTime Next)
Contains information about when a timed event elapses.
EventTimepointUtc(DateTime Current, DateTime Next, Duration Duration)
Contains information about when a timed event elapses.
Abstract base class for timed State-Machine event nodes.
abstract Task< EventTimepointUtc > GetEventTimepointUtc(EvaluationArguments Arguments)
Gets the timepoint for when the event elapses.
TimedEventNode()
Abstract base class for timed State-Machine event nodes.
override async Task< EventHandlerReference > Register(int EventIndex, EvaluationArguments Arguments, OnEvent Event)
Registers the event
async Task EventElapsed(TimepointEventHandler Handler)
Method called when event elapses.
async Task ReregisterOnStart(TimepointEventHandler Handler)
Re-registers the event on module start.
override Task Unregister(int EventIndex, EvaluationArguments Arguments)
Registers the event
void Register(TimepointEventHandler Handler)
Registers an existing event handler.
Action executed when entering a state.
Definition: OnEvent.cs:19
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:14
static readonly Duration Zero
Zero value
Definition: Duration.cs:577