2using System.Collections;
3using System.Collections.Generic;
5using System.Security.Cryptography;
7using System.Threading.Tasks;
28 private const int BlockPageSize = 10;
30 private readonly
byte[] salt;
31 private readonly
string id;
32 private readonly
string folder;
33 private readonly
string bucketFolder;
34 private readonly
string blockFolder;
35 private readonly
string defaultCollectionName;
36 private readonly
string externalIdentity;
37 private readonly
int saltLength;
38 private readonly
int maxBlockSize;
39 private readonly
bool debug;
43 private readonly SortedDictionary<string, bool> collections =
new SortedDictionary<string, bool>();
44 private TaskCompletionSource<bool> completed =
new TaskCompletionSource<bool>();
47 private AesCryptoServiceProvider aes;
49 private bool disposed =
false;
50 private bool stopped =
false;
69 this.id = Guid.NewGuid().ToString().Replace(
"-",
string.Empty);
70 this.folder = Path.GetFullPath(Folder);
71 this.bucketFolder = Path.Combine(this.folder,
"Buckets");
72 this.blockFolder = Path.Combine(this.folder,
"Blocks");
74 this.saltLength = this.salt.Length;
76 this.maxBlockSize = MaxBlockSize;
83 this.aes =
new AesCryptoServiceProvider()
87 Mode = CipherMode.CBC,
88 Padding = PaddingMode.Zeros
91 if (!
string.IsNullOrEmpty(this.folder) && this.folder[this.folder.Length - 1] != Path.DirectorySeparatorChar)
92 this.folder += Path.DirectorySeparatorChar;
94 if (!Directory.Exists(
this.folder))
95 Directory.CreateDirectory(this.folder);
97 if (!Directory.Exists(
this.bucketFolder))
98 Directory.CreateDirectory(this.bucketFolder);
100 if (!Directory.Exists(
this.blockFolder))
101 Directory.CreateDirectory(this.blockFolder);
103 this.blockFolder += Path.DirectorySeparatorChar;
106 this.buckets.Removed += this.Buckets_Removed;
108 Task _ = this.LoadCollections();
111 private async Task LoadCollections()
115 if (!
string.IsNullOrEmpty(s))
117 lock (this.collections)
119 foreach (
string Collection
in s.Split(
CommonTypes.
CRLF, StringSplitOptions.RemoveEmptyEntries))
120 this.collections[Collection] =
true;
127 if (!this.disposed && !this.stopped)
132 this.eventQueue.AddFirst(
new WorkItem()
140 return Task.CompletedTask;
143 private class WorkItem
147 public object Object;
170 private async Task StorageTask()
175 Type LastType =
null;
177 DateTime NextCheck = DateTime.Now.AddMinutes(1);
179 while (!((Item = await this.eventQueue.Wait()) is
null))
189 object Object = Item.Object;
190 Type T = Object.GetType();
192 string CollectionName;
194 bool DynamicArchiveTime;
195 int? ArchivingTimeDays;
198 Serializer = LastSerializer;
203 LastSerializer = Serializer;
212 if (
string.IsNullOrEmpty(CollectionName))
213 CollectionName = this.defaultCollectionName;
215 BucketName = CollectionName;
217 if (ArchivingTimeDays.HasValue && ArchivingTimeDays.Value !=
int.MaxValue)
218 BucketName +=
"." + ArchivingTimeDays.Value.ToString();
222 if (ArchivingTimeDays.HasValue && ArchivingTimeDays.Value <= 0)
230 await Serializer.
Serialize(Output,
false,
false, Object,
null);
239 ObjectId = await Serializer.
GetObjectId(Object,
false,
null);
247 Log.
Alert(
"Unable to store object in ledger.",
248 new KeyValuePair<string, object>(
"Type", T.FullName),
249 new KeyValuePair<string, object>(
"Collection", CollectionName),
250 new KeyValuePair<string, object>(
"ObjectId", ObjectId.HasValue ? ObjectId.Value.ToString() :
string.Empty),
251 new KeyValuePair<string, object>(
"Message", ex.Message),
252 new KeyValuePair<string, object>(
"StackTrace", ex.StackTrace),
253 new KeyValuePair<string, object>(
"JSON",
JSON.
Encode(Object,
true)));
256 if (!(Binary is
null))
262 if (ArchivingTimeDays.HasValue && ArchivingTimeDays.Value <
int.MaxValue)
266 Expires = DateTime.UtcNow.AddDays(ArchivingTimeDays.Value);
268 catch (ArgumentOutOfRangeException ex)
270 Expires = DateTime.MaxValue;
272 Log.
Error(
"Invalid archiving time encountered.", T.FullName,
"Neuro-Ledger",
273 new KeyValuePair<string, object>(
"Type", T.FullName),
274 new KeyValuePair<string, object>(
"ArchivingTimeDays", ArchivingTimeDays.Value),
275 new KeyValuePair<string, object>(
"Message", ex.Message));
279 Expires = DateTime.MaxValue;
283 Bucket = await
Bucket.
Create(Path.Combine(
this.bucketFolder, BucketName +
".bin"), CollectionName, Expires,
this);
292 await this.eventQueue.AddLast(Item);
293 await Task.Delay(10);
302 lock (this.collections)
304 if (!this.collections.ContainsKey(CollectionName))
306 this.collections[CollectionName] =
true;
315 StringBuilder sb =
new StringBuilder();
318 sb.AppendLine(Collection);
325 this.buckets.
Remove(BucketName);
334 byte[] Digest =
Bucket.
Hash(this.hashFunction);
335 byte[] Signature =
Bucket.
Sign(this.signatureAlgorithm);
338 Digest =
this.CalcCombinationDigest(Digest, Signature);
340 string FileName = this.GetFullFileName(
Bucket.
Header, Digest);
342 using (ICryptoTransform Aes = this.GetAes(FileName,
true))
344 using (FileStream fs = File.Create(FileName))
346 using (CryptoStream cs =
new CryptoStream(fs, Aes, CryptoStreamMode.Write))
349 cs.FlushFinalBlock();
355 string LocalFileName = this.GetLocalFileName(FileName);
358 await this.AddBlockReference(Ref);
361 DateTime Now = DateTime.Now;
362 if (Now >= NextCheck)
364 NextCheck = Now.AddHours(1);
365 await this.DeleteExpiredBlocks(Now);
380 this.completed.TrySetResult(
true);
390 private byte[] CalcCombinationDigest(
byte[] ContentDigest,
byte[] Signature)
392 int c = ContentDigest.Length;
393 int d = Signature.Length;
394 byte[] Bin =
new byte[c + d];
396 Array.Copy(ContentDigest, 0, Bin, 0, c);
397 Array.Copy(Signature, 0, Bin, c, d);
399 using (MemoryStream ms =
new MemoryStream())
401 ms.Write(ContentDigest, 0, ContentDigest.Length);
402 ms.Write(Signature, 0, Signature.Length);
406 return this.hashFunction(ms);
416 private string GetFullFileName(
BlockHeader Header,
byte[] Digest)
418 string FileName = Path.Combine(this.blockFolder,
419 Header.
Created.Year.ToString(
"D4"),
420 Header.
Created.Month.ToString(
"D2"),
421 Header.
Created.Day.ToString(
"D2"));
423 if (!Directory.Exists(FileName))
424 Directory.CreateDirectory(FileName);
434 private string GetLocalFileName(
string FullFileName)
436 string LocalFileName;
438 if (FullFileName.StartsWith(
this.blockFolder))
439 LocalFileName = FullFileName.Substring(this.blockFolder.Length);
441 LocalFileName = FullFileName;
443 return LocalFileName;
457 byte[] Digest = this.hashFunction(File);
460 byte[] Signature = this.signatureAlgorithm.Sign(File);
464 Digest = this.CalcCombinationDigest(Digest, Signature);
466 string FileName = this.GetFullFileName(Reader.
Header, Digest);
468 using (ICryptoTransform Aes = this.GetAes(FileName,
true))
470 using (FileStream fs = System.IO.File.Create(FileName))
472 using (CryptoStream cs =
new CryptoStream(fs, Aes, CryptoStreamMode.Write))
476 cs.FlushFinalBlock();
481 FileName = this.GetLocalFileName(FileName);
485 BlockReference.FileName = FileName;
495 public event EventHandlerAsync<BlockReferenceEventArgs>
BlockAdded =
null;
517 if (
string.IsNullOrEmpty(LocalFileName))
519 else if (Path.IsPathRooted(LocalFileName))
520 return LocalFileName;
522 return Path.Combine(this.blockFolder, LocalFileName);
525 private async Task DeleteExpiredBlocks(DateTime Now)
529 Dictionary<string, bool> Directories =
null;
534 FileName = this.GetFullFileName(Ref.
FileName);
536 if (File.Exists(FileName))
540 File.Delete(FileName);
542 if (Directories is
null)
543 Directories =
new Dictionary<string, bool>();
545 string Folder = Path.GetDirectoryName(FileName);
547 Directories[Folder] =
true;
551 Log.
Error(
"Unable to delete block.",
552 new KeyValuePair<string, object>(
"FileName", FileName),
553 new KeyValuePair<string, object>(
"Message", ex.Message));
559 await this.DeleteBlockReference(Ref);
562 if (!(Directories is
null))
564 foreach (
string Key
in Directories.Keys)
566 string FolderName = Key;
568 while (Directory.GetFiles(FolderName,
"*.*", SearchOption.TopDirectoryOnly).Length == 0 &&
569 Directory.GetDirectories(FolderName,
"*.*", SearchOption.TopDirectoryOnly).Length == 0)
573 Directory.Delete(FolderName,
false);
575 int i = FolderName.LastIndexOf(Path.DirectorySeparatorChar);
579 FolderName = FolderName.Substring(0, i);
583 Log.
Error(
"Unable to delete folder.",
584 new KeyValuePair<string, object>(
"Folder", FolderName),
585 new KeyValuePair<string, object>(
"Message", ex.Message));
601 public event EventHandlerAsync<BlockReferenceEventArgs>
BlockDeleted =
null;
625 this.disposed =
true;
626 this.eventQueue.Dispose();
632 #region ISerializerContext
638 public string Id => this.id;
652 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
659 public bool Debug => this.debug;
681 throw new NotSupportedException(
"Field codes not used.");
693 throw new NotSupportedException(
"Field codes not used.");
703 if (this.serializers is
null)
704 throw new ObjectDisposedException(
"Service is closing down.");
716 if (this.serializers is
null)
717 throw new ObjectDisposedException(
"Service is closing down.");
740 throw new Exception(
"Objects of type " + Type.FullName +
" must be embedded.");
751 return Guid.NewGuid();
762 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
775 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
787 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
799 return Task.CompletedTask;
809 return Task.CompletedTask;
821 return Task.CompletedTask;
835 return Task.CompletedTask;
841 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
851 this.eventQueue.AddLast(
new WorkItem()
878 public async Task<ILedgerEnumerator<object>>
GetEnumerator(
string CollectionName)
891 BlockPageSize, Ascending ?
"Created" :
"-Created");
905 Ascending ?
"Created" :
"-Created");
921 Ascending ?
"Created" :
"-Created");
930 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
932 this.stopped =
false;
933 this.completed =
new TaskCompletionSource<bool>();
935 string[] Files = Directory.GetFiles(this.bucketFolder,
"*.bin", SearchOption.TopDirectoryOnly);
936 foreach (
string FileName
in Files)
940 string BucketName = Path.GetFileName(FileName);
941 BucketName = BucketName.Substring(0, BucketName.Length - 4);
943 int i = BucketName.LastIndexOf(
'.');
946 File.Delete(FileName);
950 string Suffix = BucketName.Substring(i + 1);
951 string CollectionName = BucketName.Substring(0, i);
954 if (
int.TryParse(Suffix, out
int NrDays))
955 Expires = DateTime.UtcNow.AddDays(NrDays);
957 Expires = DateTime.MaxValue;
972 Task _ = Task.Run(() => this.StorageTask());
981 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
985 this.eventQueue.Disposed += (Sender, e) =>
987 this.buckets?.
Clear();
992 this.serializers =
null;
998 await this.eventQueue.Terminate();
999 await this.completed.Task;
1008 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
1010 this.buckets?.
Clear();
1011 return Task.CompletedTask;
1014 internal ICryptoTransform GetAes(
string FileName,
bool Encryptor)
1016 byte[] BinFileName = Encoding.UTF8.GetBytes(FileName);
1017 int c = BinFileName.Length;
1018 byte[] Concat =
new byte[c + this.saltLength];
1020 Array.Copy(BinFileName, 0, Concat, 0, c);
1021 Array.Copy(this.salt, 0, Concat, c, this.saltLength);
1026 Array.Resize(ref IV, 16);
1029 return this.aes.CreateEncryptor(Key, IV);
1031 return this.aes.CreateDecryptor(Key, IV);
1053 Log.
Warning(
"Block Registry collection repaired during start-up. Scanning existing blocks in ledger to make sure block registry is up to date.");
1060 return Task.CompletedTask;
1065 return Task.CompletedTask;
1070 return Task.CompletedTask;
1073 if (NrAdded == 0 && NrUpdated == 0 && NrDeleted == 0)
1075 Log.
Notice(
"Block Registry OK. Nothing to repair.",
1076 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1077 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1078 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted));
1082 Log.
Warning(
"Block Registry repaired, based on blocks available in ledger.",
1083 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1084 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1085 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted));
1097 EventHandlerAsync<BlockReferenceEventArgs> NoChangeCallback,
1098 EventHandlerAsync<BlockReferenceEventArgs> AddedCallback,
1099 EventHandlerAsync<BlockReferenceEventArgs> UpdatedCallback,
1100 EventHandlerAsync<BlockReferenceEventArgs> DeletedCallback)
1104 IEnumerable<string> Files = Directory.EnumerateFiles(this.blockFolder,
"*.block", SearchOption.AllDirectories);
1105 IEnumerator<string> e = Files.GetEnumerator();
1107 while (e.MoveNext())
1109 string BlockFile = e.Current;
1114 string LocalFileName;
1116 if (BlockFile.StartsWith(
this.blockFolder))
1117 LocalFileName = BlockFile.Substring(this.blockFolder.Length);
1119 LocalFileName = BlockFile;
1121 string s = Path.GetFileName(LocalFileName);
1122 s = s.Substring(0, s.Length - 6);
1137 else if ((i = this.Compare(Ref, Reader, LocalFileName, Digest)) != 0)
1145 Ref.FileName = LocalFileName;
1147 Ref.Bytes = Reader.
Bytes;
1148 Ref.Digest = (
byte[])Digest.Clone();
1149 Ref.Signature = (
byte[])Reader.
Signature.Clone();
1158 catch (Exception ex)
1160 Log.
Error(
"Unable to process block file.",
1161 new KeyValuePair<string, object>(
"FileName", BlockFile),
1162 new KeyValuePair<string, object>(
"Message", ex.Message));
1168 string LastObjectId =
null;
1169 const int Max = 1000;
1174 IEnumerable<BlockReference> References;
1176 if (LastObjectId is
null)
1186 if (
string.IsNullOrEmpty(Ref.
FileName))
1188 if (Ref.
Creator ==
this.externalIdentity)
1199 string FileName = this.GetFullFileName(Ref.
FileName);
1201 if (!File.Exists(FileName))
1203 if (Ref.
Creator ==
this.externalIdentity)
1211 Ref.FileName =
string.Empty;
1221 while (Count >= Max);
1253 if (Convert.ToBase64String(Ref.
Digest) != Convert.ToBase64String(Digest))
1256 if (Convert.ToBase64String(Ref.
Signature) != Convert.ToBase64String(Reader.
Signature))
1268 public static bool AreEqual(DateTime TP1, DateTime TP2)
1271 TP1.Millisecond == TP2.Millisecond &&
1272 TP1.Second == TP2.Second &&
1273 TP1.Minute == TP2.Minute &&
1274 TP1.Hour == TP2.Hour &&
1275 TP1.Day == TP2.Day &&
1276 TP1.Month == TP2.Month &&
1277 TP1.Year == TP2.Year &&
1278 TP1.Kind == TP2.Kind;
1289 List<ObjectState> ObjectsInBlock =
new List<ObjectState>();
1290 DateTime
Start = DateTime.Now;
1292 bool Cleared =
false;
1309 if (Dictionary is
null)
1316 Log.
Warning(CollectionName +
" collection repaired during start-up. Scanning existing blocks in ledger to make sure collection is up to date.");
1327 ObjectsInBlock.Reverse();
1329 Exception FirstException =
null;
1348 catch (Exception ex)
1350 if (FirstException is
null)
1351 FirstException = ex;
1363 if (!(FirstException is
null))
1365 Log.
Error(
"Unable to enumerate objects in block properly when repairing collection:\r\n\r\n" +
1366 FirstException.Message, TempBlockEnumerator.
Current.FileName,
string.Empty,
string.Empty,
1368 new KeyValuePair<string, object>(
"Collection", CollectionName));
1371 ObjectsInBlock.Clear();
1386 if (!(Dictionary is
null))
1388 Tuple<uint, uint, uint, uint> Counts = await this.
Process(Dictionary, CollectionName);
1390 NrAdded = Counts.Item1;
1391 NrUpdated = Counts.Item2;
1392 NrDeleted = Counts.Item3;
1393 NrErrors = Counts.Item4;
1400 if (!(Dictionary is
null))
1407 TimeSpan Elapsed = DateTime.Now -
Start;
1409 if (NrAdded == 0 && NrUpdated == 0 && NrDeleted == 0 && NrErrors == 0)
1411 Log.
Notice(
"Collection OK. Nothing to repair.",
1412 new KeyValuePair<string, object>(
"CollectionName", CollectionName),
1413 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1414 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1415 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted),
1416 new KeyValuePair<string, object>(
"NrErrors", NrErrors),
1417 new KeyValuePair<string, object>(
"Time", Elapsed.ToString()));
1421 Log.
Alert(
"Collection repaired, based on blocks available in ledger.",
1422 new KeyValuePair<string, object>(
"CollectionName", CollectionName),
1423 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1424 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1425 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted),
1426 new KeyValuePair<string, object>(
"NrErrors", NrErrors),
1427 new KeyValuePair<string, object>(
"Time", Elapsed.ToString()));
1454 eAsync =
new PseudoAsyncEnumerator(e);
1456 while (await eAsync.MoveNextAsync())
1507 catch (Exception ex)
1516 if (e is IDisposable Disposable)
1517 Disposable.Dispose();
1525 return new Tuple<uint, uint, uint, uint>(NrAdded, NrUpdated, NrDeleted, NrErrors);
1530 private readonly IEnumerator e;
1532 public PseudoAsyncEnumerator(IEnumerator e)
1537 public object Current => this.e.Current;
1538 public bool MoveNext() => this.e.MoveNext();
1539 public Task<bool> MoveNextAsync() => Task.FromResult(this.e.MoveNext());
1540 public void Reset() => this.e.Reset();
1552 lock (this.collections)
1554 Result =
new string[this.collections.Count];
1555 this.collections.Keys.CopyTo(Result, 0);
1568 return Task.FromResult<
string[]>(this.
Collections);
1580 return this.
Export(Output, Restriction,
null);
1611 string[] BlockIds = Restriction?.
BlockIds ??
new string[] {
null };
1613 foreach (
string BlockId
in BlockIds)
1615 string[] Creators = Restriction?.
Creators ??
new string[] {
null };
1617 foreach (
string Creator
in Creators)
1619 List<Filter> Filters =
new List<Filter>()
1624 if (!
string.IsNullOrEmpty(BlockId))
1627 if (!
string.IsNullOrEmpty(Creator))
1648 if (Filters.Count > 1)
1700 foreach (KeyValuePair<string, object> P
in Obj)
1706 catch (Exception ex)
1709 if (!await this.ReportException(ex, Output))
1714 Continue = await Output.
EndEntry();
1725 Continue = await Output.
EndBlock();
1735 catch (Exception ex)
1738 if (!await this.ReportException(ex, Output))
1750 catch (Exception ex)
1753 if (!await this.ReportException(ex, Output))
1767 private async Task<bool> ReportException(Exception ex,
ILedgerExport Output)
1771 if (ex is AggregateException ex2)
1773 foreach (Exception ex3
in ex2.InnerExceptions)
1792 if (!(this.externalEvents is
null) && this.externalEvents !=
ExternalEvents)
1793 throw new Exception(
"An interface for external events has already been registered.");
1805 if (!(this.externalEvents is
null) && this.externalEvents !=
ExternalEvents)
1806 throw new Exception(
"The registered interface for external events differs from the one presented.");
1808 this.externalEvents =
null;
1819 return this.externalEvents;
Helps with parsing of commong data types.
static readonly char[] CRLF
Contains the CR LF character sequence.
Helps with common JSON-related tasks.
static string Encode(string s)
Encodes a string for inclusion in JSON.
Static class managing the application event log. Applications and services log events on this static ...
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
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.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
static void Alert(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an alert event.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IPersistentDictionary > GetDictionary(string Collection)
Gets a persistent dictionary containing objects in a collection.
static Task EndBulk()
Ends bulk-processing of data. Must be called once for every call to StartBulk.
static IDatabaseProvider Provider
Registered database provider.
static Task StartBulk()
Starts bulk-proccessing of data. Must be followed by a call to EndBulk.
static async Task Update(object Object)
Updates an object in the database.
static async Task Delete(object Object)
Deletes an object in the database.
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
static async Task< PaginatedEnumerator< object > > Enumerate(string Collection, int PageSize, params string[] SortOrder)
Finds the first page of objects in a given collection.
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
This filter selects objects that have a named field greater or equal to a given value.
This filter selects objects that have a named field greater than a given value.
This filter selects objects that have a named field lesser or equal to a given value.
This filter selects objects that have a named field lesser than a given value.
Base class for all filter classes.
Contains basic ledger export restrictions.
string[] Creators
Creators to export. If null, all relevant creators will be exported.
DateTime? MinCreated
Minimum value (if provided) of when a ledger block of information was created.
DateTime? MaxCreated
Maximum value (if provided) of when a ledger block of information was created.
string[] BlockIds
Blocks to export. If null, all relevant blocks will be exported.
bool MaxCreatedIncluded
If MaxCreated is included
string[] CollectionNames
Collections to export. If null, all collections will be exported.
bool MinCreatedIncluded
If MinCreated is included
Static interface for ledger persistence. In order to work, a ledger provider has to be assigned to it...
static Task< string[]> GetCollections()
Gets an array of available collections.
Reads objects in a block.
static async Task< BlockReader > CreateAsync(string FileName, NeuroLedgerProvider Provider)
Creates a block reader.
string CollectionName
Collection name.
ulong Bytes
Size of block, in bytes
byte[] Signature
Signature of block.
BlockHeader Header
Block Header
Event arguments for block reference events.
Represents the construction of a block file.
BlockHeader Header
Block Header
long Length
Length of bucket file.
void Delete()
Deletes the file, and disposes of the object.
static async Task< Bucket > Create(string FileName, string CollectionName, DateTime Expires, NeuroLedgerProvider Provider)
Represents the construction of a block file.
bool HasEntries
If entries has been written to the bucket.
async Task< long > WriteEntry(EntryType EntryType, byte[] Binary)
Writes an entry to the bucket.
byte[] Sign(ISignatureAlgorithm Algorithm)
Signs the contents of the file.
async Task CopyTo(Stream Destination, byte[] Signature)
Copies the content of the bucket to an output stream.
byte[] Hash(HashFunctionStream HashFunction)
Calculates a hash digest of the contents of the file.
Optimizes a persistent IPersistentDictionary using a cache.
void DeleteAndDispose()
TODO
Task AddAsync(string key, object value)
TODO
async Task< bool > ContainsKeyAsync(string key)
TODO
async Task< IEnumerator< KeyValuePair< string, object > > > GetEnumeratorAsync()
TODO
DateTime Timestamp
Timestamp of entry.
async Task< ObjectSerializer > GetObjectSerializerEx(Type Type)
Gets the object serializer corresponding to a specific object.
async Task< bool > Export(ILedgerExport Output, LedgerExportRestriction Restriction, ProfilerThread Thread)
Performs an export of the entire ledger.
async Task RepairRegistry(EventHandlerAsync< BlockReferenceEventArgs > NoChangeCallback, EventHandlerAsync< BlockReferenceEventArgs > AddedCallback, EventHandlerAsync< BlockReferenceEventArgs > UpdatedCallback, EventHandlerAsync< BlockReferenceEventArgs > DeletedCallback)
Make sure block reference objects match existing blocks.
HashFunctionStream HashFunction
Hash function used for calculating block digests.
Task< IObjectSerializer > GetObjectSerializer(Type Type)
Gets the object serializer corresponding to a specific type.
string[] Collections
Array of collections archived in the ledger.
async Task< ILedgerEnumerator< object > > GetEnumerator(string CollectionName)
Gets an eumerator for objects in a collection.
string BucketFolder
Bucket folder
Task< ulong > GetFieldCode(string Collection, string FieldName)
Gets the code for a specific field in a collection.
string ExternalIdentity
External identity.
EventHandlerAsync< BlockReferenceEventArgs > BlockAdded
Event raised when a new block is added.
string Id
An ID of the serialization context. It's unique, and constant during the life-time of the application...
Task UpdatedEntry(object Object)
Updates an entry in the ledger.
Task< object > TryLoadObject(Type T, Guid ObjectId, EmbeddedObjectSetter EmbeddedSetter)
Tries to load an object given its Object ID ObjectId and its base type T .
void Dispose()
IDisposable.Dispose
Task< string[]> GetCollections()
Gets an array of available collections.
Task NewEntry(object Object)
Adds an entry to the ledger.
async Task AddBlockFile(Stream File, BlockReference BlockReference)
Adds a block file to the ledger.
async Task< PaginatedEnumerator< BlockReference > > GetCollectionBlockEnumerator(string Collection, bool Ascending)
Gets a block enumerator for blocks pertaining to a given collection. Enumerates blocks in order of cr...
static bool AreEqual(DateTime TP1, DateTime TP2)
Compares two timestamps, to the millisecond (but not tick) level.
bool Debug
If the provider is run in debug mode.
NeuroLedgerProvider(string Folder, TimeSpan CollectionTime, int MaxBlockSize, byte[] Salt, string DefaultCollectionName, string ExternalIdentity, ISignatureAlgorithm SignatureAlgorithm, HashFunctionStream HashFunction, bool Debug)
Neuro-Ledger provider.
string GetFullFileName(string LocalFileName)
Gets the full file name of a file hosted by the Neuro-Ledger, given its local file name.
async Task< ILedgerEnumerator< T > > GetEnumerator< T >()
Gets an eumerator for objects of type T .
ILedgerExternalEvents ExternalEvents
Interface for reporting external events.
async Task RepairCollection(string CollectionName)
Repairs a database collection based on contents in the corresponding ledger.
Task< ObjectSerializer > GetObjectSerializerEx(object Object)
Gets the object serializer corresponding to a specific object.
bool NormalizedNames
If normalized names are to be used or not. Normalized names reduces the number of bytes required to s...
ISignatureAlgorithm SignatureAlgorithm
Signature Algorithm used for calculating block signatures.
Task Flush()
Persists any pending changes.
string BlockFolder
Block folder
Task ClearedCollection(string Collection)
Clears a collection in the ledger.
EventHandlerAsync< BlockReferenceEventArgs > BlockDeleted
Event raised when a block has been deleted.
int TimeoutMilliseconds
Timeout, in milliseconds, for asynchronous operations.
static Task< BlockReference > FindReference(byte[] Digest)
Finds a BlockReference object related to a block, given its digest.
string DefaultCollectionName
Default collection name.
async Task Start()
Called when processing starts.
async Task Stop()
Called when processing ends.
Task< bool > Export(ILedgerExport Output, LedgerExportRestriction Restriction)
Performs an export of the entire ledger.
async Task< PaginatedEnumerator< BlockReference > > GetCreatorBlockEnumerator(string Creator, bool Ascending)
Gets a block enumerator for blocks pertaining to a given collection. Enumerates blocks in order of cr...
async Task< PaginatedEnumerator< BlockReference > > GetBlockEnumerator(bool Ascending)
Gets a block enumerator. Enumerates blocks in order of creation.
Guid CreateGuid()
Creates a new GUID.
Task< IObjectSerializer > GetObjectSerializerNoCreate(Type Type)
Gets the object serializer corresponding to a specific type, if one exists.
Task< T > TryLoadObject< T >(Guid ObjectId, EmbeddedObjectSetter EmbeddedSetter)
Tries to load an object given its Object ID ObjectId and its base type T .
Task< string > GetFieldName(string Collection, ulong FieldCode)
Gets the name of a field in a collection, given its code.
async Task< Tuple< uint, uint, uint, uint > > Process(CachedStringDictionary Records, string CollectionName)
Processes an ordered set of records containing ObjectState objects in a cached string dictionary (for...
Task DeletedEntry(object Object)
Deletes an entry in the ledger.
void Unregister(ILedgerExternalEvents ExternalEvents)
Unregisters a recipient of external events.
void Register(ILedgerExternalEvents ExternalEvents)
Registers a recipient of external events.
Task< Guid > SaveNewObject(object Value, object State)
Saves an unsaved object, and returns a new GUID identifying the saved object.
async Task RepairRegistry()
Make sure block reference objects match existing blocks.
Enumeratres through objects available in a series of blocks.
T Current
Gets the element in the collection at the current position of the enumerator.
async Task< bool > MoveNextAsync()
Advances the enumerator to the next element of the collection.
Entry CurrentEntry
Current encoded entry.
static async Task< ObjectEnumerator< T > > Create(IAsyncEnumerator< BlockReference > BlockEnumerator, NeuroLedgerProvider Provider)
Creates an object enumerator from a block enumerator.
Represents an object state.
GenericObject Object
Object
Contains a reference to a block in the ledger.
ulong Bytes
Size of block, in bytes.
bool AccessDenied
If access to the block was denied.
byte[] Digest
Digest of block
byte[] Signature
Signature of block
string FileName
Local filename of block
Paginated object enumerator.
async Task< bool > MoveNextAsync()
Moves to next item.
void Dispose()
IDisposable.Dispose
Manages binary serialization of data.
byte[] GetSerialization()
Gets the binary serialization.
Generic object. Contains a sequence of properties.
string TypeName
Type name.
override bool Equals(object obj)
Serializes a class, taking into account attributes defined in Attributes.
virtual async Task< Guid > GetObjectId(object Value, bool InsertIfNotFound, object State)
Gets the Object ID for a given object.
bool ArchiveObjects
If objects of this type can be archived.
bool ArchiveTimeDynamic
If each object contains the information for how long time it can be archived.
virtual async Task Serialize(ISerializer Writer, bool WriteTypeCode, bool Embedded, object Value, object State)
Serializes a value.
virtual int GetArchivingTimeDays(object Object)
Number of days to archive objects of this type. If equal to int.MaxValue, no limit is defined.
virtual Task< string > CollectionName(object Object)
Name of collection objects of this type is to be stored in, if available. If not available,...
Maintains a set of serializers.
Task< IObjectSerializer > GetObjectSerializerNoCreate(Type Type)
Gets the object serializer corresponding to a specific type, if one exists.
void Dispose()
IDisposable.Dispose
async Task< IObjectSerializer > GetObjectSerializer(Type Type)
Gets the object serializer corresponding to a specific type.
Implements an in-memory cache.
void Dispose()
IDisposable.Dispose
bool Remove(KeyType Key)
Removes an item from the cache.
bool TryGetValue(KeyType Key, out ValueType Value)
Tries to get a value from the cache.
void Add(KeyType Key, ValueType Value)
Adds an item to the cache.
void Clear()
Clears the cache.
Event arguments for cache item removal events.
ValueType Value
Value of item that was removed.
Class that keeps track of events and timing for one thread.
void Start()
Processing starts.
void Exception(System.Exception Exception)
Exception occurred
void Stop()
Processing starts.
void Idle()
Thread goes idle.
void NewState(string State)
Thread changes state.
Asynchronous First-in-First-out (FIFO) Queue, for use when transporting items of type T between task...
Static class managing persistent settings.
static async Task< string > GetAsync(string Key, string DefaultValue)
Gets a string-valued setting.
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
Static class containing methods that can be used to make sure calls are made from appropriate locatio...
static void CallFromSource(params string[] Sources)
Makes sure the call is made from one of the listed sources.
Contains methods for simple hash calculations.
static byte[] StringToBinary(string s)
Parses a hex string.
static string BinaryToString(byte[] Data)
Converts an array of bytes to a string with their hexadecimal representations (in lower case).
static byte[] ComputeHMACSHA256Hash(byte[] Key, byte[] Data)
Computes the HMAC-SHA-256 hash of a block of binary data.
static byte[] ComputeSHA256Hash(byte[] Data)
Computes the SHA-256 hash of a block of binary data.
Interface for asynchronous enumerators.
Task Update(object Object)
Updates an object in the database.
Task< object > TryLoadObject(string CollectionName, object ObjectId)
Tries to load an object given its Object ID ObjectId and its collection name CollectionName .
Task Delete(object Object)
Deletes an object in the database.
Task Clear(string CollectionName)
Clears a collection of all objects.
Task Insert(object Object)
Inserts an object into the database.
Interface for proxy for reporting changes to the ledger from external sources.
Interface for ledger providers that can be plugged into the static Ledger class.
Persistent dictionary that can contain more entries than possible in the internal memory.
Task ClearAsync()
Clears the dictionary.
Interface for ledger exports.
Task< bool > EndCollection()
Is called when a collection is finished.
Task< bool > ReportProperty(string PropertyName, object PropertyValue)
Is called when a property is reported.
Task< bool > StartCollection(string CollectionName)
Is called when a collection is started.
Task< bool > EndLedger()
Is called when export of ledger is finished.
Task< bool > StartLedger()
Is called when export of ledger is started.
Task< bool > ReportException(Exception Exception)
Is called when an exception has occurred.
Task< bool > BlockMetaData(string Key, object Value)
Reports block meta-data.
Task< bool > EndBlock()
Is called when a block in a collection is finished.
Task< bool > StartEntry(string ObjectId, string TypeName, EntryType EntryType, DateTimeOffset EntryTimestamp)
Is called when an entry is started.
Task< bool > StartBlock(string BlockID)
Is called when a block in a collection is started.
Task< bool > EndEntry()
Is called when an entry is finished.
Interface for digital signature algorithms.
BlockStatus
Status of the block.
delegate void EmbeddedObjectSetter(object EmbeddedObject)
Delegate for embedded object value setter methods. Is used when loading embedded objects.
EntryType
Ledger entry type.
delegate byte[] HashFunctionStream(Stream Data)
Delegate to hash function.
HashFunction
Hash method enumeration.