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;
3using System.IO;
4using System.Reflection;
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
317 public override Task<bool> StartDatabase(IDatabaseProvider Provider)
318 {
319 this.w.Write((byte)2); // Database
320 return Task.FromResult(true);
321 }
322
326 public override Task<bool> EndDatabase()
327 {
328 this.w.Write(string.Empty);
329 return this.UpdateClient(false);
330 }
331
337 public override Task<bool> StartLedger(ILedgerProvider Provider)
338 {
339 this.w.Write((byte)6); // Ledger
340 return Task.FromResult(true);
341 }
342
347 public override Task<bool> EndLedger()
348 {
349 this.w.Write(string.Empty);
350 return this.UpdateClient(false);
351 }
352
358 public override Task<bool> StartCollection(string CollectionName)
359 {
360 if (this.exportCollection = this.ExportCollection(CollectionName))
361 this.w.Write(CollectionName);
362
363 return Task.FromResult(true);
364 }
365
370 public override Task<bool> EndCollection()
371 {
372 if (this.exportCollection)
373 this.w.Write((byte)0);
374
375 return Task.FromResult(true);
376 }
377
382 public override Task<bool> StartIndex()
383 {
384 if (this.exportCollection)
385 this.w.Write((byte)1);
386
387 return Task.FromResult(true);
388 }
389
394 public override Task<bool> EndIndex()
395 {
396 if (this.exportCollection)
397 this.w.Write(string.Empty);
398
399 return Task.FromResult(true);
400 }
401
408 public override Task<bool> ReportIndexField(string FieldName, bool Ascending)
409 {
410 if (this.exportCollection)
411 {
412 this.w.Write(FieldName);
413 this.w.Write(Ascending);
414 }
415
416 return Task.FromResult(true);
417 }
418
424 public override Task<bool> StartBlock(string BlockID)
425 {
426 if (this.exportCollection)
427 {
428 this.w.Write((byte)1);
429 this.w.Write(BlockID);
430 }
431
432 return Task.FromResult(true);
433 }
434
439 public override Task<bool> EndBlock()
440 {
441 if (this.exportCollection)
442 this.w.Write((byte)3);
443
444 return Task.FromResult(true);
445 }
446
453 public override async Task<bool> BlockMetaData(string Key, object Value)
454 {
455 if (this.exportCollection)
456 {
457 this.w.Write((byte)4);
458 this.w.Write(Key);
459 await this.ReportProperty(null, Value);
460 }
461
462 return true;
463 }
464
471 public override Task<string> StartObject(string ObjectId, string TypeName)
472 {
473 if (this.exportCollection)
474 {
475 this.w.Write((byte)2);
476 this.w.Write(ObjectId);
477 this.w.Write(TypeName);
478 }
479
480 return Task.FromResult(ObjectId);
481 }
482
487 public override Task<bool> EndObject()
488 {
489 if (this.exportCollection)
490 {
491 this.w.Write(TYPE_NULL);
492 this.w.Write(string.Empty);
493 }
494
495 return this.UpdateClient(false);
496 }
497
506 public override Task<bool> StartEntry(string ObjectId, string TypeName, EntryType EntryType, DateTimeOffset EntryTimestamp)
507 {
508 if (this.exportCollection)
509 {
510 this.w.Write((byte)2);
511 this.w.Write(ObjectId);
512 this.w.Write(TypeName);
513 this.w.Write((byte)EntryType);
514
515 DateTime DT = EntryTimestamp.DateTime;
516 TimeSpan TS = EntryTimestamp.Offset;
517
518 this.w.Write((byte)DT.Kind);
519 this.w.Write(DT.Ticks);
520 this.w.Write(TS.Ticks);
521 }
522
523 return Task.FromResult(true);
524 }
525
530 public override Task<bool> EndEntry()
531 {
532 if (this.exportCollection)
533 {
534 this.w.Write(TYPE_NULL);
535 this.w.Write(string.Empty);
536 }
537
538 return this.UpdateClient(false);
539 }
540
547 public override Task<bool> ReportProperty(string PropertyName, object PropertyValue)
548 {
549 if (this.exportCollection)
550 {
551 if (PropertyValue is null)
552 {
553 this.w.Write(TYPE_NULL);
554 if (!(PropertyName is null))
555 this.w.Write(PropertyName);
556 }
557 else if (PropertyValue is Enum)
558 {
559 this.w.Write(TYPE_ENUM);
560 if (!(PropertyName is null))
561 this.w.Write(PropertyName);
562 this.w.Write(PropertyValue.ToString());
563 }
564 else
565 {
566 switch (Type.GetTypeCode(PropertyValue.GetType()))
567 {
568 case TypeCode.Boolean:
569 this.w.Write(TYPE_BOOLEAN);
570 if (!(PropertyName is null))
571 this.w.Write(PropertyName);
572 this.w.Write((bool)PropertyValue);
573 break;
574
575 case TypeCode.Byte:
576 this.w.Write(TYPE_BYTE);
577 if (!(PropertyName is null))
578 this.w.Write(PropertyName);
579 this.w.Write((byte)PropertyValue);
580 break;
581
582 case TypeCode.Char:
583 this.w.Write(TYPE_CHAR);
584 if (!(PropertyName is null))
585 this.w.Write(PropertyName);
586 this.w.Write((char)PropertyValue);
587 break;
588
589 case TypeCode.DateTime:
590 this.w.Write(TYPE_DATETIME);
591 if (!(PropertyName is null))
592 this.w.Write(PropertyName);
593
594 DateTime DT = (DateTime)PropertyValue;
595
596 this.w.Write((byte)DT.Kind);
597 this.w.Write(DT.Ticks);
598 break;
599
600 case TypeCode.Decimal:
601 this.w.Write(TYPE_DECIMAL);
602 if (!(PropertyName is null))
603 this.w.Write(PropertyName);
604 this.w.Write((decimal)PropertyValue);
605 break;
606
607 case TypeCode.Double:
608 this.w.Write(TYPE_DOUBLE);
609 if (!(PropertyName is null))
610 this.w.Write(PropertyName);
611 this.w.Write((double)PropertyValue);
612 break;
613
614 case TypeCode.Int16:
615 this.w.Write(TYPE_INT16);
616 if (!(PropertyName is null))
617 this.w.Write(PropertyName);
618 this.w.Write((short)PropertyValue);
619 break;
620
621 case TypeCode.Int32:
622 this.w.Write(TYPE_INT32);
623 if (!(PropertyName is null))
624 this.w.Write(PropertyName);
625 this.w.Write((int)PropertyValue);
626 break;
627
628 case TypeCode.Int64:
629 this.w.Write(TYPE_INT64);
630 if (!(PropertyName is null))
631 this.w.Write(PropertyName);
632 this.w.Write((long)PropertyValue);
633 break;
634
635 case TypeCode.SByte:
636 this.w.Write(TYPE_SBYTE);
637 if (!(PropertyName is null))
638 this.w.Write(PropertyName);
639 this.w.Write((sbyte)PropertyValue);
640 break;
641
642 case TypeCode.Single:
643 this.w.Write(TYPE_SINGLE);
644 if (!(PropertyName is null))
645 this.w.Write(PropertyName);
646 this.w.Write((float)PropertyValue);
647 break;
648
649 case TypeCode.String:
650 this.w.Write(TYPE_STRING);
651 if (!(PropertyName is null))
652 this.w.Write(PropertyName);
653 this.w.Write((string)PropertyValue);
654 break;
655
656 case TypeCode.UInt16:
657 this.w.Write(TYPE_UINT16);
658 if (!(PropertyName is null))
659 this.w.Write(PropertyName);
660 this.w.Write((ushort)PropertyValue);
661 break;
662
663 case TypeCode.UInt32:
664 this.w.Write(TYPE_UINT32);
665 if (!(PropertyName is null))
666 this.w.Write(PropertyName);
667 this.w.Write((uint)PropertyValue);
668 break;
669
670 case TypeCode.UInt64:
671 this.w.Write(TYPE_UINT64);
672 if (!(PropertyName is null))
673 this.w.Write(PropertyName);
674 this.w.Write((ulong)PropertyValue);
675 break;
676
677 case TypeCode.DBNull:
678 case TypeCode.Empty:
679 this.w.Write(TYPE_NULL);
680 if (!(PropertyName is null))
681 this.w.Write(PropertyName);
682 break;
683
684 case TypeCode.Object:
685 if (PropertyValue is TimeSpan TS)
686 {
687 this.w.Write(TYPE_TIMESPAN);
688 if (!(PropertyName is null))
689 this.w.Write(PropertyName);
690 this.w.Write(TS.Ticks);
691 }
692 else if (PropertyValue is DateTimeOffset DTO)
693 {
694 this.w.Write(TYPE_DATETIMEOFFSET);
695 if (!(PropertyName is null))
696 this.w.Write(PropertyName);
697
698 DT = DTO.DateTime;
699 TS = DTO.Offset;
700
701 this.w.Write((byte)DT.Kind);
702 this.w.Write(DT.Ticks);
703 this.w.Write(TS.Ticks);
704 }
705 else if (PropertyValue is CaseInsensitiveString CiString)
706 {
707 this.w.Write(TYPE_CI_STRING);
708 if (!(PropertyName is null))
709 this.w.Write(PropertyName);
710 this.w.Write(CiString.Value);
711 }
712 else if (PropertyValue is byte[] Bin)
713 {
714 this.w.Write(TYPE_BYTEARRAY);
715 if (!(PropertyName is null))
716 this.w.Write(PropertyName);
717 this.w.Write(Bin.Length);
718 this.w.Write(Bin);
719 }
720 else if (PropertyValue is Guid Id)
721 {
722 this.w.Write(TYPE_GUID);
723 if (!(PropertyName is null))
724 this.w.Write(PropertyName);
725 this.w.Write(Id.ToByteArray());
726 }
727 else if (PropertyValue is Array A)
728 {
729 this.w.Write(TYPE_ARRAY);
730 if (!(PropertyName is null))
731 this.w.Write(PropertyName);
732 this.w.Write(PropertyValue.GetType().GetElementType().FullName);
733
734 this.w.Write(A.LongLength);
735 foreach (object Obj in A)
736 this.ReportProperty(null, Obj);
737 }
738 else if (PropertyValue is GenericObject Obj)
739 {
740 this.w.Write(TYPE_OBJECT);
741 if (!(PropertyName is null))
742 this.w.Write(PropertyName);
743 this.w.Write(Obj.TypeName);
744
745 foreach (KeyValuePair<string, object> P in Obj)
746 this.ReportProperty(P.Key, P.Value);
747
748 this.w.Write(TYPE_NULL);
749 this.w.Write(string.Empty);
750 }
751 else
752 throw new Exception("Unhandled property value type: " + PropertyValue.GetType().FullName);
753 break;
754
755 default:
756 throw new Exception("Unhandled property value type: " + PropertyValue.GetType().FullName);
757 }
758 }
759 }
760
761 return Task.FromResult(true);
762 }
763
769 public override Task<bool> ReportError(string Message)
770 {
771 if (!string.IsNullOrEmpty(Message))
772 {
773 if (this.errors is null)
774 this.errors = new LinkedList<string>();
775
776 this.errors.AddLast(Message);
777 }
778
779 return Task.FromResult(true);
780 }
781
787 public override Task<bool> ReportException(Exception Exception)
788 {
789 if (this.exceptions is null)
790 this.exceptions = new LinkedList<Exception>();
791
792 this.exceptions.AddLast(Exception);
793
794 return Task.FromResult(true);
795 }
796
801 public override Task<bool> StartFiles()
802 {
803 this.w.Write((byte)3); // Files
804 return Task.FromResult(true);
805 }
806
811 public override Task<bool> EndFiles()
812 {
813 this.w.Write(string.Empty);
814 return Task.FromResult(true);
815 }
816
823 public override async Task<bool> ExportFile(string FileName, Stream File)
824 {
825 this.w.Write(FileName);
826 this.w.Write(File.Length);
827 this.w.Flush();
828
829 await File.CopyToAsync(this.output);
830
831 return true;
832 }
833
834 }
835}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
Definition: Log.cs:194
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 > StartLedger(ILedgerProvider Provider)
Is called when export of ledger is started.
override Task< bool > EndBlock()
Is called when a block in a collection is finished.
override Task< bool > EndObject()
Is called when an object is finished.
override Task< bool > StartDatabase(IDatabaseProvider Provider)
Is called when export of database is started.
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.
Interface for database providers that can be plugged into the static Database class.
Interface for ledger providers that can be plugged into the static Ledger class.
EntryType
Ledger entry type.
Definition: ILedgerEntry.cs:9