Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
BinaryExportFormat.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Reflection;
5using System.Security.Cryptography;
6using System.Threading.Tasks;
7using Waher.Events;
10
12{
17 {
18 internal const string Preamble = "IoT Gateway Export";
19
23 public const byte TYPE_BOOLEAN = 0;
24
28 public const byte TYPE_BYTE = 1;
29
33 public const byte TYPE_INT16 = 2;
34
38 public const byte TYPE_INT32 = 3;
39
43 public const byte TYPE_INT64 = 4;
44
48 public const byte TYPE_SBYTE = 5;
49
53 public const byte TYPE_UINT16 = 6;
54
58 public const byte TYPE_UINT32 = 7;
59
63 public const byte TYPE_UINT64 = 8;
64
68 public const byte TYPE_DECIMAL = 9;
69
73 public const byte TYPE_DOUBLE = 10;
74
78 public const byte TYPE_SINGLE = 11;
79
83 public const byte TYPE_DATETIME = 12;
84
88 public const byte TYPE_TIMESPAN = 13;
89
93 public const byte TYPE_CHAR = 14;
94
98 public const byte TYPE_STRING = 15;
99
103 public const byte TYPE_ENUM = 16;
104
108 public const byte TYPE_BYTEARRAY = 17;
109
113 public const byte TYPE_GUID = 18;
114
118 public const byte TYPE_DATETIMEOFFSET = 19;
119
123 public const byte TYPE_CI_STRING = 20;
124
128 public const byte TYPE_MIN = 27;
129
133 public const byte TYPE_MAX = 28;
134
138 public const byte TYPE_NULL = 29;
139
143 public const byte TYPE_ARRAY = 30;
144
148 public const byte TYPE_OBJECT = 31;
149
150 private BinaryWriter w;
151 private Stream output;
152 private CryptoStream cs;
153 private readonly int blockSize;
154 private LinkedList<string> errors = null;
155 private LinkedList<Exception> exceptions = null;
156 private bool exportCollection = false;
157
167 public BinaryExportFormat(string FileName, DateTime Created, Stream Output, FileStream File, bool OnlySelectedCollections, Array SelectedCollections)
168 : this(FileName, Created, Output, File, null, 0, OnlySelectedCollections, SelectedCollections)
169 {
170 }
171
183 public BinaryExportFormat(string FileName, DateTime Created, Stream Output, FileStream File, CryptoStream CryptoStream, int BlockSize,
184 bool OnlySelectedCollections, Array SelectedCollections)
185 : base(FileName, Created, File, OnlySelectedCollections, SelectedCollections)
186 {
187 this.output = Output;
188 this.w = new BinaryWriter(this.output, System.Text.Encoding.UTF8);
189 this.cs = CryptoStream;
190 this.blockSize = BlockSize;
191 }
192
194 public override void Dispose()
195 {
196 if (!(this.w is null))
197 {
198 this.w.Flush();
199 this.output.Flush();
200
201 if (!(this.cs is null) && this.blockSize > 1)
202 {
203 Type T = typeof(CryptoStream);
204 int i;
205 FieldInfo FI = null;
206
207 PropertyInfo PI = T.GetProperty("_inputBufferIndex", BindingFlags.Instance | BindingFlags.NonPublic);
208 if (PI is null)
209 {
210 FI = T.GetField("_inputBufferIndex", BindingFlags.Instance | BindingFlags.NonPublic);
211 if (FI is null)
212 {
213 PI = T.GetProperty("_InputBufferIndex", BindingFlags.Instance | BindingFlags.NonPublic);
214 if (PI is null)
215 FI = T.GetField("_InputBufferIndex", BindingFlags.Instance | BindingFlags.NonPublic);
216 }
217 }
218
219 do
220 {
221 if (!(PI is null))
222 i = (int)PI.GetValue(this.cs);
223 else if (!(FI is null))
224 i = (int)FI.GetValue(this.cs);
225 else
226 i = 0;
227
228 if (i > 0)
229 {
230 this.w.Write((byte)0);
231 this.w.Flush();
232 this.output.Flush();
233 }
234 }
235 while (i != 0);
236
237 this.cs.FlushFinalBlock();
238 }
239 }
240
241 this.w?.Dispose();
242 this.w = null;
243
244 this.output?.Dispose();
245 this.output = null;
246
247 this.cs?.Dispose();
248 this.cs = null;
249
250 base.Dispose();
251 }
252
256 public override Task<bool> Start()
257 {
258 this.w.Write((byte)1); // Version.
259 this.w.Write(Preamble);
260 return Task.FromResult(true);
261 }
262
267 public override Task<bool> End()
268 {
269 if (!(this.errors is null))
270 {
271 this.w.Write((byte)4); // Errors
272
273 foreach (string Message in this.errors)
274 this.w.Write(Message);
275
276 this.w.Write(string.Empty);
277 this.errors = null;
278 }
279
280 if (!(this.exceptions is null))
281 {
282 this.w.Write((byte)5); // Exceptions
283
284 foreach (Exception ex in this.exceptions)
285 this.OutputException(ex);
286
287 this.w.Write(string.Empty);
288 this.exceptions = null;
289 }
290
291 this.w.Write((byte)0);
292 return this.UpdateClient(true);
293 }
294
295 private Task OutputException(Exception Exception)
296 {
297 this.w.Write(Exception.Message);
298 this.w.Write(Log.CleanStackTrace(Exception.StackTrace));
299
300 if (Exception is AggregateException AggregateException)
301 {
302 foreach (Exception ex in AggregateException.InnerExceptions)
303 this.OutputException(ex);
304 }
305 else if (!(Exception.InnerException is null))
306 this.OutputException(Exception.InnerException);
307
308 this.w.Write(string.Empty);
309
310 return Task.CompletedTask;
311 }
312
316 public override Task<bool> StartDatabase()
317 {
318 this.w.Write((byte)2); // Database
319 return Task.FromResult(true);
320 }
321
325 public override Task<bool> EndDatabase()
326 {
327 this.w.Write(string.Empty);
328 return this.UpdateClient(false);
329 }
330
335 public override Task<bool> StartLedger()
336 {
337 this.w.Write((byte)6); // Ledger
338 return Task.FromResult(true);
339 }
340
345 public override Task<bool> EndLedger()
346 {
347 this.w.Write(string.Empty);
348 return this.UpdateClient(false);
349 }
350
356 public override Task<bool> StartCollection(string CollectionName)
357 {
358 if (this.exportCollection = this.ExportCollection(CollectionName))
359 this.w.Write(CollectionName);
360
361 return Task.FromResult(true);
362 }
363
368 public override Task<bool> EndCollection()
369 {
370 if (this.exportCollection)
371 this.w.Write((byte)0);
372
373 return Task.FromResult(true);
374 }
375
380 public override Task<bool> StartIndex()
381 {
382 if (this.exportCollection)
383 this.w.Write((byte)1);
384
385 return Task.FromResult(true);
386 }
387
392 public override Task<bool> EndIndex()
393 {
394 if (this.exportCollection)
395 this.w.Write(string.Empty);
396
397 return Task.FromResult(true);
398 }
399
406 public override Task<bool> ReportIndexField(string FieldName, bool Ascending)
407 {
408 if (this.exportCollection)
409 {
410 this.w.Write(FieldName);
411 this.w.Write(Ascending);
412 }
413
414 return Task.FromResult(true);
415 }
416
422 public override Task<bool> StartBlock(string BlockID)
423 {
424 if (this.exportCollection)
425 {
426 this.w.Write((byte)1);
427 this.w.Write(BlockID);
428 }
429
430 return Task.FromResult(true);
431 }
432
437 public override Task<bool> EndBlock()
438 {
439 if (this.exportCollection)
440 this.w.Write((byte)3);
441
442 return Task.FromResult(true);
443 }
444
451 public override async Task<bool> BlockMetaData(string Key, object Value)
452 {
453 if (this.exportCollection)
454 {
455 this.w.Write((byte)4);
456 this.w.Write(Key);
457 await this.ReportProperty(null, Value);
458 }
459
460 return true;
461 }
462
469 public override Task<string> StartObject(string ObjectId, string TypeName)
470 {
471 if (this.exportCollection)
472 {
473 this.w.Write((byte)2);
474 this.w.Write(ObjectId);
475 this.w.Write(TypeName);
476 }
477
478 return Task.FromResult(ObjectId);
479 }
480
485 public override Task<bool> EndObject()
486 {
487 if (this.exportCollection)
488 {
489 this.w.Write(TYPE_NULL);
490 this.w.Write(string.Empty);
491 }
492
493 return this.UpdateClient(false);
494 }
495
504 public override Task<bool> StartEntry(string ObjectId, string TypeName, EntryType EntryType, DateTimeOffset EntryTimestamp)
505 {
506 if (this.exportCollection)
507 {
508 this.w.Write((byte)2);
509 this.w.Write(ObjectId);
510 this.w.Write(TypeName);
511 this.w.Write((byte)EntryType);
512
513 DateTime DT = EntryTimestamp.DateTime;
514 TimeSpan TS = EntryTimestamp.Offset;
515
516 this.w.Write((byte)DT.Kind);
517 this.w.Write(DT.Ticks);
518 this.w.Write(TS.Ticks);
519 }
520
521 return Task.FromResult(true);
522 }
523
528 public override Task<bool> EndEntry()
529 {
530 if (this.exportCollection)
531 {
532 this.w.Write(TYPE_NULL);
533 this.w.Write(string.Empty);
534 }
535
536 return this.UpdateClient(false);
537 }
538
545 public override Task<bool> ReportProperty(string PropertyName, object PropertyValue)
546 {
547 if (this.exportCollection)
548 {
549 if (PropertyValue is null)
550 {
551 this.w.Write(TYPE_NULL);
552 if (!(PropertyName is null))
553 this.w.Write(PropertyName);
554 }
555 else if (PropertyValue is Enum)
556 {
557 this.w.Write(TYPE_ENUM);
558 if (!(PropertyName is null))
559 this.w.Write(PropertyName);
560 this.w.Write(PropertyValue.ToString());
561 }
562 else
563 {
564 switch (Type.GetTypeCode(PropertyValue.GetType()))
565 {
566 case TypeCode.Boolean:
567 this.w.Write(TYPE_BOOLEAN);
568 if (!(PropertyName is null))
569 this.w.Write(PropertyName);
570 this.w.Write((bool)PropertyValue);
571 break;
572
573 case TypeCode.Byte:
574 this.w.Write(TYPE_BYTE);
575 if (!(PropertyName is null))
576 this.w.Write(PropertyName);
577 this.w.Write((byte)PropertyValue);
578 break;
579
580 case TypeCode.Char:
581 this.w.Write(TYPE_CHAR);
582 if (!(PropertyName is null))
583 this.w.Write(PropertyName);
584 this.w.Write((char)PropertyValue);
585 break;
586
587 case TypeCode.DateTime:
588 this.w.Write(TYPE_DATETIME);
589 if (!(PropertyName is null))
590 this.w.Write(PropertyName);
591
592 DateTime DT = (DateTime)PropertyValue;
593
594 this.w.Write((byte)DT.Kind);
595 this.w.Write(DT.Ticks);
596 break;
597
598 case TypeCode.Decimal:
599 this.w.Write(TYPE_DECIMAL);
600 if (!(PropertyName is null))
601 this.w.Write(PropertyName);
602 this.w.Write((decimal)PropertyValue);
603 break;
604
605 case TypeCode.Double:
606 this.w.Write(TYPE_DOUBLE);
607 if (!(PropertyName is null))
608 this.w.Write(PropertyName);
609 this.w.Write((double)PropertyValue);
610 break;
611
612 case TypeCode.Int16:
613 this.w.Write(TYPE_INT16);
614 if (!(PropertyName is null))
615 this.w.Write(PropertyName);
616 this.w.Write((short)PropertyValue);
617 break;
618
619 case TypeCode.Int32:
620 this.w.Write(TYPE_INT32);
621 if (!(PropertyName is null))
622 this.w.Write(PropertyName);
623 this.w.Write((int)PropertyValue);
624 break;
625
626 case TypeCode.Int64:
627 this.w.Write(TYPE_INT64);
628 if (!(PropertyName is null))
629 this.w.Write(PropertyName);
630 this.w.Write((long)PropertyValue);
631 break;
632
633 case TypeCode.SByte:
634 this.w.Write(TYPE_SBYTE);
635 if (!(PropertyName is null))
636 this.w.Write(PropertyName);
637 this.w.Write((sbyte)PropertyValue);
638 break;
639
640 case TypeCode.Single:
641 this.w.Write(TYPE_SINGLE);
642 if (!(PropertyName is null))
643 this.w.Write(PropertyName);
644 this.w.Write((float)PropertyValue);
645 break;
646
647 case TypeCode.String:
648 this.w.Write(TYPE_STRING);
649 if (!(PropertyName is null))
650 this.w.Write(PropertyName);
651 this.w.Write((string)PropertyValue);
652 break;
653
654 case TypeCode.UInt16:
655 this.w.Write(TYPE_UINT16);
656 if (!(PropertyName is null))
657 this.w.Write(PropertyName);
658 this.w.Write((ushort)PropertyValue);
659 break;
660
661 case TypeCode.UInt32:
662 this.w.Write(TYPE_UINT32);
663 if (!(PropertyName is null))
664 this.w.Write(PropertyName);
665 this.w.Write((uint)PropertyValue);
666 break;
667
668 case TypeCode.UInt64:
669 this.w.Write(TYPE_UINT64);
670 if (!(PropertyName is null))
671 this.w.Write(PropertyName);
672 this.w.Write((ulong)PropertyValue);
673 break;
674
675 case TypeCode.DBNull:
676 case TypeCode.Empty:
677 this.w.Write(TYPE_NULL);
678 if (!(PropertyName is null))
679 this.w.Write(PropertyName);
680 break;
681
682 case TypeCode.Object:
683 if (PropertyValue is TimeSpan TS)
684 {
685 this.w.Write(TYPE_TIMESPAN);
686 if (!(PropertyName is null))
687 this.w.Write(PropertyName);
688 this.w.Write(TS.Ticks);
689 }
690 else if (PropertyValue is DateTimeOffset DTO)
691 {
692 this.w.Write(TYPE_DATETIMEOFFSET);
693 if (!(PropertyName is null))
694 this.w.Write(PropertyName);
695
696 DT = DTO.DateTime;
697 TS = DTO.Offset;
698
699 this.w.Write((byte)DT.Kind);
700 this.w.Write(DT.Ticks);
701 this.w.Write(TS.Ticks);
702 }
703 else if (PropertyValue is CaseInsensitiveString CiString)
704 {
705 this.w.Write(TYPE_CI_STRING);
706 if (!(PropertyName is null))
707 this.w.Write(PropertyName);
708 this.w.Write(CiString.Value);
709 }
710 else if (PropertyValue is byte[] Bin)
711 {
712 this.w.Write(TYPE_BYTEARRAY);
713 if (!(PropertyName is null))
714 this.w.Write(PropertyName);
715 this.w.Write(Bin.Length);
716 this.w.Write(Bin);
717 }
718 else if (PropertyValue is Guid Id)
719 {
720 this.w.Write(TYPE_GUID);
721 if (!(PropertyName is null))
722 this.w.Write(PropertyName);
723 this.w.Write(Id.ToByteArray());
724 }
725 else if (PropertyValue is Array A)
726 {
727 this.w.Write(TYPE_ARRAY);
728 if (!(PropertyName is null))
729 this.w.Write(PropertyName);
730 this.w.Write(PropertyValue.GetType().GetElementType().FullName);
731
732 this.w.Write(A.LongLength);
733 foreach (object Obj in A)
734 this.ReportProperty(null, Obj);
735 }
736 else if (PropertyValue is GenericObject Obj)
737 {
738 this.w.Write(TYPE_OBJECT);
739 if (!(PropertyName is null))
740 this.w.Write(PropertyName);
741 this.w.Write(Obj.TypeName);
742
743 foreach (KeyValuePair<string, object> P in Obj)
744 this.ReportProperty(P.Key, P.Value);
745
746 this.w.Write(TYPE_NULL);
747 this.w.Write(string.Empty);
748 }
749 else
750 throw new Exception("Unhandled property value type: " + PropertyValue.GetType().FullName);
751 break;
752
753 default:
754 throw new Exception("Unhandled property value type: " + PropertyValue.GetType().FullName);
755 }
756 }
757 }
758
759 return Task.FromResult(true);
760 }
761
767 public override Task<bool> ReportError(string Message)
768 {
769 if (!string.IsNullOrEmpty(Message))
770 {
771 if (this.errors is null)
772 this.errors = new LinkedList<string>();
773
774 this.errors.AddLast(Message);
775 }
776
777 return Task.FromResult(true);
778 }
779
785 public override Task<bool> ReportException(Exception Exception)
786 {
787 if (this.exceptions is null)
788 this.exceptions = new LinkedList<Exception>();
789
790 this.exceptions.AddLast(Exception);
791
792 return Task.FromResult(true);
793 }
794
799 public override Task<bool> StartFiles()
800 {
801 this.w.Write((byte)3); // Files
802 return Task.FromResult(true);
803 }
804
809 public override Task<bool> EndFiles()
810 {
811 this.w.Write(string.Empty);
812 return Task.FromResult(true);
813 }
814
821 public override async Task<bool> ExportFile(string FileName, Stream File)
822 {
823 this.w.Write(FileName);
824 this.w.Write(File.Length);
825 this.w.Flush();
826
827 await File.CopyToAsync(this.output);
828
829 return true;
830 }
831
832 }
833}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
Definition: Log.cs:184
override async Task< bool > ExportFile(string FileName, Stream File)
Export file.
override Task< string > StartObject(string ObjectId, string TypeName)
Is called when an object is started.
override Task< bool > StartCollection(string CollectionName)
Is called when a collection is started.
BinaryExportFormat(string FileName, DateTime Created, Stream Output, FileStream File, CryptoStream CryptoStream, int BlockSize, bool OnlySelectedCollections, Array SelectedCollections)
Binary File export
override Task< bool > ReportException(Exception Exception)
Is called when an exception has occurred.
const byte TYPE_MIN
Represents the smallest possible value for the field type being searched or filtered.
override Task< bool > ReportProperty(string PropertyName, object PropertyValue)
Is called when a property is reported.
override Task< bool > EndLedger()
Is called when export of ledger is finished.
const byte TYPE_MAX
Represents the largest possible value for the field type being searched or filtered.
const byte TYPE_CI_STRING
Represents a CaseInsensitiveString
override Task< bool > EndIndex()
Is called when an index in a collection is finished.
override Task< bool > EndCollection()
Is called when a collection is finished.
override Task< bool > EndFiles()
Ends export of files.
override Task< bool > StartDatabase()
Is called when export of database is started.
override Task< bool > EndBlock()
Is called when a block in a collection is finished.
override Task< bool > StartLedger()
Is called when export of ledger is started.
override Task< bool > EndObject()
Is called when an object is finished.
override Task< bool > StartBlock(string BlockID)
Is called when a block in a collection is started.
override Task< bool > EndDatabase()
Is called when export of database is finished.
override Task< bool > EndEntry()
Is called when an entry is finished.
override Task< bool > StartFiles()
Starts export of files.
BinaryExportFormat(string FileName, DateTime Created, Stream Output, FileStream File, bool OnlySelectedCollections, Array SelectedCollections)
Binary File export
override async Task< bool > BlockMetaData(string Key, object Value)
Reports block meta-data.
override Task< bool > StartEntry(string ObjectId, string TypeName, EntryType EntryType, DateTimeOffset EntryTimestamp)
Is called when an entry is started.
override Task< bool > ReportIndexField(string FieldName, bool Ascending)
Is called when a field in an index is reported.
override Task< bool > StartIndex()
Is called when an index in a collection is started.
override Task< bool > ReportError(string Message)
Is called when an error is reported.
Abstract base class for export formats.
Definition: ExportFormat.cs:14
Task< bool > UpdateClient(bool ForceUpdate)
If any clients should be updated about export status.
bool ExportCollection(string CollectionName)
Checks if a collection is to be exported or not.
Definition: ExportFormat.cs:91
Represents a case-insensitive string.
Generic object. Contains a sequence of properties.
EntryType
Ledger entry type.
Definition: ILedgerEntry.cs:9