Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MeteringTopology.cs
1using System;
2using System.Collections.Generic;
3using System.Threading.Tasks;
4using Waher.Events;
13
15{
21 public delegate Task NewMomentaryValuesHandler(IThingReference Reference, IEnumerable<Field> Values);
22
28 {
32 public const string SourceID = "MeteringTopology";
33
34 private static readonly Dictionary<string, MeteringNode> nodes = new Dictionary<string, MeteringNode>();
35 private static Root root = null;
36 private static MeteringTopology instance = null;
37
38 private DateTime lastChanged;
39
45 {
46 this.lastChanged = RuntimeSettings.Get(SourceID + ".LastChanged", DateTime.MinValue);
47
48 if (instance is null)
49 instance = this;
50 }
51
55 string IDataSource.SourceID
56 {
57 get { return SourceID; }
58 }
59
63 public IEnumerable<IDataSource> ChildSources
64 {
65 get { return null; }
66 }
67
71 public bool HasChildren
72 {
73 get { return false; }
74 }
75
79 public DateTime LastChanged
80 {
81 get => this.lastChanged;
82 internal set
83 {
84 if (this.lastChanged != value)
85 {
86 this.lastChanged = value;
87 Task _ = RuntimeSettings.SetAsync("MeteringTopology.LastChanged", value);
88 }
89 }
90 }
91
97 public Task<string> GetNameAsync(Language Language)
98 {
99 return Language.GetStringAsync(typeof(MeteringTopology), 13, "Metering Topology");
100 }
101
107 public async Task<INode> GetNodeAsync(IThingReference NodeRef)
108 {
109 return await GetNode(NodeRef);
110 }
111
117 public static Task<MeteringNode> GetNode(string NodeId)
118 {
119 return GetNode(new ThingReference(NodeId, SourceID));
120 }
121
127 public static async Task<MeteringNode> GetNode(IThingReference NodeRef)
128 {
129 if (NodeRef is null || NodeRef.SourceId != SourceID || !string.IsNullOrEmpty(NodeRef.Partition))
130 return null;
131
132 lock (nodes)
133 {
134 if (nodes.TryGetValue(NodeRef.NodeId, out MeteringNode Node))
135 return Node;
136 }
137
138 foreach (MeteringNode Node2 in await Database.Find<MeteringNode>(new FilterFieldEqualTo("NodeId", NodeRef.NodeId)))
139 {
140 lock (nodes)
141 {
142 if (nodes.TryGetValue(NodeRef.NodeId, out MeteringNode Node))
143 return Node;
144 else
145 {
146 nodes[NodeRef.NodeId] = Node2;
147 return Node2;
148 }
149 }
150 }
151
152 return null;
153 }
154
155 internal static MeteringNode RegisterNode(MeteringNode Node)
156 {
157 if (Node.SourceId == SourceID && string.IsNullOrEmpty(Node.Partition))
158 {
159 lock (nodes)
160 {
161 if (nodes.TryGetValue(Node.NodeId, out MeteringNode Node2))
162 return Node2;
163 else
164 {
165 nodes[Node.NodeId] = Node;
166 return Node;
167 }
168 }
169 }
170 else
171 return Node;
172 }
173
174 internal static MeteringNode RegisterNewNodeId(MeteringNode Node, string OldId)
175 {
176 if (Node.SourceId != SourceID || !string.IsNullOrEmpty(Node.Partition))
177 return Node;
178
179 lock (nodes)
180 {
181 if (!nodes.TryGetValue(OldId, out MeteringNode Node2) || Node2 != Node)
182 return Node;
183
184 if (nodes.TryGetValue(Node.NodeId, out Node2))
185 return Node2;
186
187 nodes.Remove(OldId);
188 nodes[Node.NodeId] = Node;
189
190 return Node;
191 }
192 }
193
194 internal static void UnregisterNode(MeteringNode Node)
195 {
196 if (Node.SourceId == SourceID && string.IsNullOrEmpty(Node.Partition))
197 {
198 lock (nodes)
199 {
200 if (nodes.TryGetValue(Node.NodeId, out MeteringNode Node2) && Node == Node2)
201 nodes.Remove(Node.NodeId);
202 }
203 }
204 }
205
211 public Task<bool> CanViewAsync(RequestOrigin Caller)
212 {
213 return Task.FromResult(true); // TODO: Check user privileges
214 }
215
219 public IEnumerable<INode> RootNodes
220 {
221 get
222 {
223 if (root is null)
224 LoadRoot().Wait();
225
226 return new INode[] { root };
227 }
228 }
229
233 public static Root Root
234 {
235 get
236 {
237 if (root is null)
238 LoadRoot().Wait();
239
240 return root;
241 }
242 }
243
244 private static async Task LoadRoot()
245 {
246 Root Result = null;
247
248 foreach (MeteringNode Node in await Database.Find<MeteringNode>(new FilterFieldEqualTo("ParentId", Guid.Empty)))
249 {
250 if (Node is Root Root)
251 {
252 if (Result is null)
253 Result = Root;
254 else
255 await Database.Delete(Node);
256 }
257 }
258
259 if (Result is null)
260 {
261 Result = new Root()
262 {
263 NodeId = await (await Translator.GetDefaultLanguageAsync()).GetStringAsync(typeof(MeteringTopology), 14, "Root")
264 };
265
266 await Database.Insert(Result);
267
269 await NewEvent(new NodeAdded()
270 {
272 NodeType = Result.GetType().FullName,
273 Sniffable = Result is ICommunicationLayer,
274 DisplayName = await Result.GetTypeNameAsync(Language),
275 HasChildren = Result.HasChildren,
276 ChildrenOrdered = Result.ChildrenOrdered,
277 IsReadable = Result.IsReadable,
278 IsControllable = Result.IsControllable,
279 HasCommands = Result.HasCommands,
280 ParentId = string.Empty,
281 ParentPartition = string.Empty,
282 Updated = Result.Updated,
283 State = Result.State,
284 NodeId = Result.NodeId,
285 Partition = Result.Partition,
286 LogId = NodeAdded.EmptyIfSame(Result.LogId, Result.NodeId),
287 LocalId = NodeAdded.EmptyIfSame(Result.LocalId, Result.NodeId),
288 SourceId = Result.SourceId,
289 Timestamp = DateTime.Now
290 });
291 }
292
293 lock (nodes)
294 {
295 nodes[Result.NodeId] = Result;
296 }
297
298 root = Result;
299 }
300
306 public static async Task<int> DeleteOldEvents(TimeSpan MaxAge)
307 {
308 if (MaxAge <= TimeSpan.Zero)
309 throw new ArgumentException("Age must be positive.", nameof(MaxAge));
310
311 DateTime Limit = DateTime.Now.Subtract(MaxAge);
312 int NrEvents = 0;
313 bool Deleted;
314
315 do
316 {
317 Deleted = false;
318
319 foreach (SourceEvent Event in await Database.FindDelete<SourceEvent>(0, 100, new FilterAnd(
320 new FilterFieldEqualTo("SourceId", SourceID), new FilterFieldLesserOrEqualTo("Timestamp", Limit))))
321 {
322 NrEvents++;
323 Deleted = true;
324 }
325 }
326 while (Deleted);
327
328 if (NrEvents > 0)
329 {
330 KeyValuePair<string, object>[] Tags = new KeyValuePair<string, object>[]
331 {
332 new KeyValuePair<string, object>("Limit", Limit),
333 new KeyValuePair<string, object>("NrEvents", NrEvents)
334 };
335
336 if (NrEvents == 1)
337 Log.Informational("Deleting 1 metering topology event from the database.", SourceID, Tags);
338 else
339 Log.Informational("Deleting " + NrEvents.ToString() + " metering topology events from the database.", SourceID, Tags);
340 }
341
342 return NrEvents;
343 }
344
348 public event EventHandlerAsync<SourceEvent> OnEvent = null;
349
350 internal static async Task NewEvent(SourceEvent Event)
351 {
353 await instance?.OnEvent?.Raise(instance, Event);
354 }
355
361 public static Task NewMomentaryValues(IThingReference Reference, IEnumerable<Field> Values)
362 {
364 if (h is null)
365 return Task.CompletedTask;
366 else
367 return h(Reference, Values);
368 }
369
374
379 public static async Task<int> DeleteOrphans()
380 {
381 int Result = 0;
382
383 foreach (MeteringNode Node in await Database.Find<MeteringNode>())
384 {
385 if (Node.ParentId == Guid.Empty)
386 continue;
387
388 MeteringNode ParentNode = await Database.TryLoadObject<MeteringNode>(Node.ParentId);
389 if (ParentNode is null)
390 {
391 await Database.Delete(Node);
392 Result++;
393
394 lock (nodes)
395 {
396 nodes.Remove(Node.NodeId);
397 }
398 }
399 }
400
401 return Result;
402 }
403
404 }
405}
Class representing an event.
Definition: Event.cs:10
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
Definition: Log.cs:334
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static Task< IEnumerable< object > > FindDelete(string Collection, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
Definition: Database.cs:879
static async Task InsertLazy(object Object)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
Definition: Database.cs:156
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:717
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:247
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:95
static Task< object > TryLoadObject(string CollectionName, object ObjectId)
Tries to load an object given its Object ID ObjectId and its collection name CollectionName .
Definition: Database.cs:1079
This filter selects objects that conform to all child-filters provided.
Definition: FilterAnd.cs:10
This filter selects objects that have a named field equal to a given value.
This filter selects objects that have a named field lesser or equal to a given value.
Contains information about a language.
Definition: Language.cs:17
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Definition: Language.cs:209
Basic access point for runtime language localization.
Definition: Translator.cs:16
static async Task< Language > GetDefaultLanguageAsync()
Gets the default language.
Definition: Translator.cs:223
Static class managing persistent settings.
static string Get(string Key, string DefaultValue)
Gets a string-valued setting.
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
Base class for all metering nodes.
Definition: MeteringNode.cs:28
virtual bool IsControllable
If the node can be controlled.
async Task< Parameter[]> GetDisplayableParameterAraryAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
virtual bool IsReadable
If the node can be read.
bool HasChildren
If the source has any child sources.
NodeState State
Current overall state of the node.
virtual string LogId
If provided, an ID for the node, as it would appear or be used in system logs. Can be null,...
virtual string LocalId
If provided, an ID for the node, but unique locally between siblings. Can be null,...
virtual bool HasCommands
If the node has registered commands or not.
DateTime Updated
When node was last updated. If it has not been updated, value will be DateTime.MinValue.
string SourceId
Optional ID of source containing node.
string Partition
Optional partition in which the Node ID is unique.
virtual bool ChildrenOrdered
If the children of the node have an intrinsic order (true), or if the order is not important (false).
Guid ParentId
Object ID of parent node in persistence layer.
Definition: MeteringNode.cs:99
Defines the Metering Topology data source. This data source contains a tree structure of persistent r...
IEnumerable< IDataSource > ChildSources
Child sources. If no child sources are available, null is returned.
IEnumerable< INode > RootNodes
Root node references. If no root nodes are available, null is returned.
DateTime LastChanged
When the source was last updated.
static Task NewMomentaryValues(IThingReference Reference, IEnumerable< Field > Values)
Reports newly measured values.
async Task< INode > GetNodeAsync(IThingReference NodeRef)
Gets the node, given a reference to it.
static Task< MeteringNode > GetNode(string NodeId)
Gets a node from the Metering Topology
EventHandlerAsync< SourceEvent > OnEvent
Event raised when a data source event has been raised.
Task< bool > CanViewAsync(RequestOrigin Caller)
If the data source is visible to the caller.
static async Task< int > DeleteOrphans()
Deletes orphaned nodes in the metering topology source.
MeteringTopology()
Defines the Metering Topology data source. This data source contains a tree structure of persistent r...
static async Task< int > DeleteOldEvents(TimeSpan MaxAge)
Deletes old data source events.
bool HasChildren
If the source has any child sources.
const string SourceID
Source ID for the metering topology data source.
Task< string > GetNameAsync(Language Language)
Gets the name of data source.
static NewMomentaryValuesHandler OnNewMomentaryValues
Event raised when a node in the metering topology reports a new momentary value.
static async Task< MeteringNode > GetNode(IThingReference NodeRef)
Gets a node from the Metering Topology
Class for the root node of the Metering topology.
Definition: Root.cs:11
override Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
Definition: Root.cs:25
Tokens available in request.
Definition: RequestOrigin.cs:9
static readonly RequestOrigin Empty
Empty request origin.
static string EmptyIfSame(string Id1, string Id2)
Returns Id1 if different, string.Empty if the same.
Definition: NodeAdded.cs:93
Abstract base class for all data source events.
Definition: SourceEvent.cs:13
Contains a reference to a thing
Interface for observable classes implementing communication protocols.
Interface for datasources that are published through the concentrator interface.
Definition: IDataSource.cs:14
Interface for nodes that are published through the concentrator interface.
Definition: INode.cs:49
Interface for thing references.
string Partition
Optional partition in which the Node ID is unique.
string SourceId
Optional ID of source containing node.
delegate Task NewMomentaryValuesHandler(IThingReference Reference, IEnumerable< Field > Values)
Delegate for new momentary values event handlers.