Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
PersistVariable.cs
1using System;
2using System.Text;
3using System.Threading.Tasks;
4using System.Xml;
5using Waher.Content;
10using Waher.Script;
14
16{
21 {
22 private Name variableName;
23 private HeaderValue value;
24 private OnlyIfChanged onlyIfChanged;
25
30 : base()
31 {
32 }
33
37 public Name VariableName => this.variableName;
38
42 public HeaderValue Value => this.value;
43
47 public OnlyIfChanged OnlyIfChanged => this.onlyIfChanged;
48
51 [DefaultValueNull]
52 public string Name { get; set; }
53
57 public override string LocalName => nameof(PersistVariable);
58
63 public override IStateMachineNode Create()
64 {
65 return new PersistVariable();
66 }
67
72 public override async Task Parse(XmlElement Xml)
73 {
74 this.Name = XML.Attribute(Xml, "name");
75
76 await base.Parse(Xml);
77
78 if (string.IsNullOrEmpty(this.Name))
79 this.ConvertValueAttributeToElement<Name>(Xml, true);
80
81 this.ConvertValueAttributeToElement<HeaderValue>(Xml, true);
82 this.ConvertValueAttributeToElement<OnlyIfChanged>(Xml, false);
83 }
84
88 protected override void OnChildNodesUpdated()
89 {
90 base.OnChildNodesUpdated();
91
92 if (string.IsNullOrEmpty(this.Name))
93 this.variableName = this.GetValueElement<Name>();
94
95 this.value = this.GetValueElement<HeaderValue>();
96 this.onlyIfChanged = this.GetValueElement<OnlyIfChanged>();
97 }
98
103 public override async Task Execute(EvaluationArguments Arguments)
104 {
105 object Value = await this.value.Evaluate(Arguments);
106 bool OnlyIfChanged;
107 ProfilerThread Thread;
108
109 if (this.onlyIfChanged is null)
110 OnlyIfChanged = false;
111 else if (await this.onlyIfChanged.Evaluate(Arguments) is bool b)
112 OnlyIfChanged = b;
113 else
114 throw new Exception("OnlyIfChanged must be a boolean value.");
115
116 string Name = this.Name;
117
118 if (string.IsNullOrEmpty(Name))
119 {
120 if (this.variableName is null)
121 throw new Exception("Variable name not defined.");
122
123 Name = (await this.variableName.Evaluate(Arguments))?.ToString();
124 if (string.IsNullOrEmpty(Name))
125 throw new Exception("Variable name not defined.");
126 }
127
128 if (OnlyIfChanged &&
129 Arguments.Variables.TryGetVariable(Name, out Waher.Script.Variable Current) &&
130 !((Value is null) ^ (Current.ValueObject is null)) &&
131 (Value?.Equals(Current.ValueObject) ?? true))
132 {
133 return;
134 }
135
136 Arguments.UpdateVariable(Name, Value);
137
139 {
140 Variable = Name,
141 Timestamp = DateTime.UtcNow,
142 Value = Value,
143 StateMachineId = Arguments.Machine.StateMachineId,
144 Expires = Arguments.Machine.Expires,
145 ArchiveOptional = Arguments.Machine.ArchiveOptional,
146 ArchiveRequired = Arguments.Machine.ArchiveRequired
147 });
148
149 if (!(Arguments.Profiler is null))
150 {
151 if (IsSample(Value, out double Sample))
152 {
153 Thread = Arguments.Profiler.GetThread(Name, ProfilerThreadType.Analog);
154 Thread.NewSample(Sample);
155 }
156 else if (Value is IPhysicalQuantity PQ)
157 {
159 Thread = Arguments.Profiler.GetThread(Name + " " + Q.Unit.ToString(), ProfilerThreadType.Analog);
160 Thread.NewSample(Q.Magnitude);
161 }
162 else
163 {
164 Thread = Arguments.Profiler.GetThread(Name, ProfilerThreadType.Sequential);
165
166 if (Value is null)
167 Thread.Idle();
168 else
169 {
170 Type T = Value?.GetType() ?? typeof(object);
171 string Label;
172 int NoteIndex;
173
174 if (T.IsValueType)
175 {
176 Label = Expression.ToString(Value);
177
178 if (Label.Length > 10)
179 {
180 NoteIndex = Thread.Profiler.AddNote(Label);
181 Label = "Note" + NoteIndex.ToString();
182 }
183 }
184 else if (Value is string s)
185 {
186 if (s.Length > 10)
187 {
188 NoteIndex = Thread.Profiler.AddNote(s);
189 Label = "Note" + NoteIndex.ToString();
190 }
191 else
192 Label = s.Replace('"', '\'');
193 }
194 else
195 {
196 StringBuilder sb = new StringBuilder();
197
198 sb.AppendLine("@startjson");
199 sb.AppendLine(JSON.Encode(Value, true));
200 sb.Append("@endjson");
201
202 NoteIndex = Thread.Profiler.AddNote(sb.ToString());
203 Label = "Note" + NoteIndex.ToString();
204 }
205
206 Thread.NewState(Label);
207 }
208 }
209 }
210 }
211
212 private static bool IsSample(object Value, out double Sample)
213 {
214 if (Value is null)
215 {
216 Sample = 0;
217 return false;
218 }
219 else if (Value is double d)
220 {
221 Sample = d;
222 return true;
223 }
224 else if (Value is decimal dec)
225 {
226 Sample = (double)dec;
227 return true;
228 }
229 else if (Value is float fl)
230 {
231 Sample = fl;
232 return true;
233 }
234 else if (Value is sbyte i8)
235 {
236 Sample = i8;
237 return true;
238 }
239 else if (Value is short i16)
240 {
241 Sample = i16;
242 return true;
243 }
244 else if (Value is int i32)
245 {
246 Sample = i32;
247 return true;
248 }
249 else if (Value is long i64)
250 {
251 Sample = i64;
252 return true;
253 }
254 else if (Value is byte ui8)
255 {
256 Sample = ui8;
257 return true;
258 }
259 else if (Value is ushort ui16)
260 {
261 Sample = ui16;
262 return true;
263 }
264 else if (Value is uint ui32)
265 {
266 Sample = ui32;
267 return true;
268 }
269 else if (Value is ulong ui64)
270 {
271 Sample = ui64;
272 return true;
273 }
274 else
275 {
276 Sample = 0;
277 return false;
278 }
279 }
280 }
281}
Helps with common JSON-related tasks.
Definition: JSON.cs:14
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:507
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:95
ProfilerThread GetThread(string Name, ProfilerThreadType Type)
Gets a profiler thread. If none is available, a new is created.
Definition: Profiler.cs:144
int AddNote(object Note)
Adds a note to the profile.
Definition: Profiler.cs:678
Class that keeps track of events and timing for one thread.
void NewSample(double Sample)
A new sample value has been recored
Profiler Profiler
Profiler reference.
void NewState(string State)
Thread changes state.
Class managing a script expression.
Definition: Expression.cs:39
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
Definition: Expression.cs:4496
PhysicalQuantity ToPhysicalQuantity()
Converts underlying object to a physical quantity.
Contains information about a variable.
Definition: Variable.cs:10
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Definition: Variables.cs:52
Abstract base class for State-Machine action nodes.
Definition: ActionNode.cs:9
Limits an action to only cases where a value has changed.
Definition: OnlyIfChanged.cs:9
override IStateMachineNode Create()
Creates a new node of the corresponding type.
override void OnChildNodesUpdated()
Method called whenever ChildNodes is updated.
override async Task Execute(EvaluationArguments Arguments)
Evaluates the action node
override async Task Parse(XmlElement Xml)
Parses the State-machine node.
OnlyIfChanged OnlyIfChanged
Only persist values if they have changed.
Contains information required for evaluating script in a state-machine.
StateMachine Machine
Reference to state-machine definition.
void UpdateVariable(string Name, object Value)
Updates a variable.
Task< object > Evaluate(EvaluationArguments Arguments)
Evaluates the value node.
Definition: Value.cs:146
Variable definition in a State-Machine
Definition: Variable.cs:13
CaseInsensitiveString StateMachineId
ID of State Machine.
Definition: StateMachine.cs:51
Duration? ArchiveOptional
Duration after which token expires, and the required archiving time, the token can optionally be arch...
Definition: StateMachine.cs:98
DateTime Expires
When state-machine expires
Definition: StateMachine.cs:66
Class representing a sample of a state machine variable over time.
Interface for objects that can be represented as a physical quantity.
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.
ProfilerThreadType
Type of profiler thread.
Definition: App.xaml.cs:4