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[^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.QueueFirst(
new WorkItem()
140 return Task.CompletedTask;
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 this.eventQueue.QueueLast(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);
345 using CryptoStream cs =
new CryptoStream(fs, Aes, CryptoStreamMode.Write);
349 cs.FlushFinalBlock();
353 string LocalFileName = this.GetLocalFileName(FileName);
356 await this.AddBlockReference(Ref);
359 DateTime Now = DateTime.Now;
360 if (Now >= NextCheck)
362 NextCheck = Now.AddHours(1);
363 await this.DeleteExpiredBlocks(Now);
378 this.completed.TrySetResult(
true);
388 private byte[] CalcCombinationDigest(
byte[] ContentDigest,
byte[] Signature)
390 int c = ContentDigest.Length;
391 int d = Signature.Length;
392 byte[] Bin =
new byte[c + d];
394 Buffer.BlockCopy(ContentDigest, 0, Bin, 0, c);
395 Buffer.BlockCopy(Signature, 0, Bin, c, d);
397 using MemoryStream ms =
new MemoryStream();
399 ms.Write(ContentDigest, 0, ContentDigest.Length);
400 ms.Write(Signature, 0, Signature.Length);
404 return this.hashFunction(ms);
413 private string GetFullFileName(
BlockHeader Header,
byte[] Digest)
415 string FileName = Path.Combine(this.blockFolder,
416 Header.Created.Year.ToString(
"D4"),
417 Header.Created.Month.ToString(
"D2"),
418 Header.Created.Day.ToString(
"D2"));
420 if (!Directory.Exists(FileName))
421 Directory.CreateDirectory(FileName);
431 private string GetLocalFileName(
string FullFileName)
433 string LocalFileName;
435 if (FullFileName.StartsWith(
this.blockFolder))
436 LocalFileName = FullFileName[this.blockFolder.Length..];
438 LocalFileName = FullFileName;
440 return LocalFileName;
454 byte[] Digest = this.hashFunction(File);
457 byte[] Signature = this.signatureAlgorithm.Sign(File,
false);
461 Digest = this.CalcCombinationDigest(Digest, Signature);
463 string FileName = this.GetFullFileName(Reader.
Header, Digest);
465 using (ICryptoTransform Aes = this.GetAes(FileName,
true))
467 using FileStream fs =
System.IO.File.Create(FileName);
468 using CryptoStream cs =
new CryptoStream(fs, Aes, CryptoStreamMode.Write);
472 cs.FlushFinalBlock();
475 FileName = this.GetLocalFileName(FileName);
479 BlockReference.FileName = FileName;
489 public event EventHandlerAsync<BlockReferenceEventArgs>
BlockAdded =
null;
511 if (
string.IsNullOrEmpty(LocalFileName))
513 else if (Path.IsPathRooted(LocalFileName))
514 return LocalFileName;
516 return Path.Combine(this.blockFolder, LocalFileName);
519 private async Task DeleteExpiredBlocks(DateTime Now)
523 Dictionary<string, bool> Directories =
null;
528 FileName = this.GetFullFileName(Ref.
FileName);
530 if (File.Exists(FileName))
534 File.Delete(FileName);
536 Directories ??=
new Dictionary<string, bool>();
538 string Folder = Path.GetDirectoryName(FileName);
540 Directories[Folder] =
true;
544 Log.
Error(
"Unable to delete block.",
545 new KeyValuePair<string, object>(
"FileName", FileName),
546 new KeyValuePair<string, object>(
"Message", ex.Message));
552 await this.DeleteBlockReference(Ref);
555 if (!(Directories is
null))
557 foreach (
string Key
in Directories.Keys)
559 string FolderName = Key;
561 while (Directory.GetFiles(FolderName,
"*.*", SearchOption.TopDirectoryOnly).Length == 0 &&
562 Directory.GetDirectories(FolderName,
"*.*", SearchOption.TopDirectoryOnly).Length == 0)
566 Directory.Delete(FolderName,
false);
568 int i = FolderName.LastIndexOf(Path.DirectorySeparatorChar);
572 FolderName = FolderName[..i];
576 Log.
Error(
"Unable to delete folder.",
577 new KeyValuePair<string, object>(
"Folder", FolderName),
578 new KeyValuePair<string, object>(
"Message", ex.Message));
594 public event EventHandlerAsync<BlockReferenceEventArgs>
BlockDeleted =
null;
618 this.disposed =
true;
619 this.eventQueue.Dispose();
625 #region ISerializerContext
631 public string Id => this.id;
645 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
674 throw new NotSupportedException(
"Field codes not used.");
686 throw new NotSupportedException(
"Field codes not used.");
696 if (this.serializers is
null)
697 throw new ObjectDisposedException(
"Service is closing down.");
709 if (this.serializers is
null)
710 throw new ObjectDisposedException(
"Service is closing down.");
733 throw new Exception(
"Objects of type " + Type.FullName +
" must be embedded.");
744 return Guid.NewGuid();
755 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
768 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
780 throw new NotSupportedException(
"Objects must be embedded. They cannot be referenced and separately stored.");
794 public Task<byte[]>
Encrypt(
byte[] Data,
string Property,
string Collection, Guid ObjectId,
797 return Task.FromResult(
new byte[MinLength]);
808 public Task<byte[]>
Decrypt(
byte[] Data,
string Property,
string Collection, Guid ObjectId)
810 return Task.FromResult(Data);
822 return Task.CompletedTask;
832 return Task.CompletedTask;
844 return Task.CompletedTask;
858 return Task.CompletedTask;
864 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
874 this.eventQueue.QueueLast(
new WorkItem()
901 public async Task<ILedgerEnumerator<object>>
GetEnumerator(
string CollectionName)
914 BlockPageSize, Ascending ?
"Created" :
"-Created");
928 Ascending ?
"Created" :
"-Created");
944 Ascending ?
"Created" :
"-Created");
953 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
955 this.stopped =
false;
956 this.completed =
new TaskCompletionSource<bool>();
958 string[] Files = Directory.GetFiles(this.bucketFolder,
"*.bin", SearchOption.TopDirectoryOnly);
959 foreach (
string FileName
in Files)
963 string BucketName = Path.GetFileName(FileName);
964 BucketName = BucketName[..^4];
966 int i = BucketName.LastIndexOf(
'.');
969 File.Delete(FileName);
973 string Suffix = BucketName[(i + 1)..];
974 string CollectionName = BucketName[..i];
975 int MaxDays = (int)(DateTime.MaxValue - DateTime.UtcNow).TotalDays;
978 if (
int.TryParse(Suffix, out
int NrDays) && NrDays < MaxDays)
979 Expires = DateTime.UtcNow.AddDays(NrDays);
981 Expires = DateTime.MaxValue;
996 Task
_ = Task.Run(() => this.StorageTask());
1005 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
1007 this.stopped =
true;
1009 this.eventQueue.Disposed += async (Sender, e) =>
1011 this.buckets?.
Clear();
1013 this.buckets =
null;
1015 if (!(this.serializers is
null))
1018 this.serializers =
null;
1021 this.aes?.Dispose();
1025 await this.eventQueue.Terminate();
1026 await this.completed.Task;
1035 throw new ObjectDisposedException(
"The Neuro-Ledger has been disposed and does not accept more entries.");
1037 this.buckets?.
Clear();
1038 return Task.CompletedTask;
1041 internal ICryptoTransform GetAes(
string FileName,
bool Encryptor)
1043 byte[] BinFileName = Encoding.UTF8.GetBytes(FileName);
1044 int c = BinFileName.Length;
1045 byte[] Concat =
new byte[c + this.saltLength];
1047 Buffer.BlockCopy(BinFileName, 0, Concat, 0, c);
1048 Buffer.BlockCopy(this.salt, 0, Concat, c, this.saltLength);
1053 Array.Resize(ref IV, 16);
1056 return this.aes.CreateEncryptor(Key, IV);
1058 return this.aes.CreateDecryptor(Key, IV);
1080 Log.
Warning(
"Block Registry collection repaired during start-up. Scanning existing blocks in ledger to make sure block registry is up to date.");
1087 return Task.CompletedTask;
1092 return Task.CompletedTask;
1097 return Task.CompletedTask;
1100 if (NrAdded == 0 && NrUpdated == 0 && NrDeleted == 0)
1102 Log.
Notice(
"Block Registry OK. Nothing to repair.",
1103 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1104 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1105 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted));
1109 Log.
Warning(
"Block Registry repaired, based on blocks available in ledger.",
1110 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1111 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1112 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted));
1124 EventHandlerAsync<BlockReferenceEventArgs> NoChangeCallback,
1125 EventHandlerAsync<BlockReferenceEventArgs> AddedCallback,
1126 EventHandlerAsync<BlockReferenceEventArgs> UpdatedCallback,
1127 EventHandlerAsync<BlockReferenceEventArgs> DeletedCallback)
1131 IEnumerable<string> Files = Directory.EnumerateFiles(this.blockFolder,
"*.block", SearchOption.AllDirectories);
1133 foreach (
string BlockFile
in Files)
1138 string LocalFileName;
1140 if (BlockFile.StartsWith(
this.blockFolder))
1141 LocalFileName = BlockFile[this.blockFolder.Length..];
1143 LocalFileName = BlockFile;
1145 string s = Path.GetFileName(LocalFileName);
1161 else if ((i = this.Compare(Ref, Reader, LocalFileName, Digest)) != 0)
1169 Ref.FileName = LocalFileName;
1171 Ref.Bytes = Reader.
Bytes;
1172 Ref.Digest = (
byte[])Digest.Clone();
1173 Ref.Signature = (
byte[])Reader.
Signature.Clone();
1182 catch (Exception ex)
1184 Log.
Error(
"Unable to process block file.",
1185 new KeyValuePair<string, object>(
"FileName", BlockFile),
1186 new KeyValuePair<string, object>(
"Message", ex.Message));
1192 string LastObjectId =
null;
1193 const int Max = 1000;
1198 IEnumerable<BlockReference> References;
1200 if (LastObjectId is
null)
1210 if (
string.IsNullOrEmpty(Ref.
FileName))
1212 if (Ref.
Creator ==
this.externalIdentity)
1223 string FileName = this.GetFullFileName(Ref.
FileName);
1225 if (!File.Exists(FileName))
1227 if (Ref.
Creator ==
this.externalIdentity)
1235 Ref.FileName =
string.Empty;
1245 while (Count >= Max);
1277 if (Convert.ToBase64String(Ref.
Digest) != Convert.ToBase64String(Digest))
1280 if (Convert.ToBase64String(Ref.
Signature) != Convert.ToBase64String(Reader.
Signature))
1292 public static bool AreEqual(DateTime TP1, DateTime TP2)
1295 TP1.Millisecond == TP2.Millisecond &&
1296 TP1.Second == TP2.Second &&
1297 TP1.Minute == TP2.Minute &&
1298 TP1.Hour == TP2.Hour &&
1299 TP1.Day == TP2.Day &&
1300 TP1.Month == TP2.Month &&
1301 TP1.Year == TP2.Year &&
1302 TP1.Kind == TP2.Kind;
1313 List<ObjectState> ObjectsInBlock =
new List<ObjectState>();
1314 DateTime
Start = DateTime.Now;
1316 bool Cleared =
false;
1324 bool Started =
true;
1335 if (Dictionary is
null)
1342 Log.
Warning(CollectionName +
" collection repaired during start-up. Scanning existing blocks in ledger to make sure collection is up to date.");
1353 ObjectsInBlock.Reverse();
1355 Exception FirstException =
null;
1374 catch (Exception ex)
1376 FirstException ??= ex;
1391 if (!(FirstException is
null))
1393 Log.
Error(
"Unable to enumerate objects in block properly when repairing collection:\r\n\r\n" +
1394 FirstException.Message, TempBlockEnumerator.
Current.FileName,
string.Empty,
string.Empty,
1396 new KeyValuePair<string, object>(
"Collection", CollectionName));
1399 ObjectsInBlock.Clear();
1415 if (!(Dictionary is
null))
1417 Tuple<uint, uint, uint, uint> Counts = await this.
Process(Dictionary, CollectionName);
1419 NrAdded = Counts.Item1;
1420 NrUpdated = Counts.Item2;
1421 NrDeleted = Counts.Item3;
1422 NrErrors = Counts.Item4;
1429 if (!(Dictionary is
null))
1436 TimeSpan Elapsed = DateTime.Now -
Start;
1438 if (NrAdded == 0 && NrUpdated == 0 && NrDeleted == 0 && NrErrors == 0)
1440 Log.
Notice(
"Collection OK. Nothing to repair.",
1441 new KeyValuePair<string, object>(
"CollectionName", CollectionName),
1442 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1443 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1444 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted),
1445 new KeyValuePair<string, object>(
"NrErrors", NrErrors),
1446 new KeyValuePair<string, object>(
"Time", Elapsed.ToString()));
1450 Log.
Alert(
"Collection repaired, based on blocks available in ledger.",
1451 new KeyValuePair<string, object>(
"CollectionName", CollectionName),
1452 new KeyValuePair<string, object>(
"NrAdded", NrAdded),
1453 new KeyValuePair<string, object>(
"NrUpdated", NrUpdated),
1454 new KeyValuePair<string, object>(
"NrDeleted", NrDeleted),
1455 new KeyValuePair<string, object>(
"NrErrors", NrErrors),
1456 new KeyValuePair<string, object>(
"Time", Elapsed.ToString()));
1483 eAsync =
new PseudoAsyncEnumerator(e);
1485 while (await eAsync.MoveNextAsync())
1536 catch (Exception ex)
1546 await DisposableAsync.DisposeAsync();
1547 else if (e is IDisposable Disposable)
1548 Disposable.Dispose();
1556 return new Tuple<uint, uint, uint, uint>(NrAdded, NrUpdated, NrDeleted, NrErrors);
1561 private readonly IEnumerator e;
1563 public PseudoAsyncEnumerator(IEnumerator e)
1568 public object Current => this.e.Current;
1569 public bool MoveNext() => this.e.MoveNext();
1570 public Task<bool> MoveNextAsync() => Task.FromResult(this.e.MoveNext());
1571 public void Reset() => this.e.Reset();
1583 lock (this.collections)
1585 Result =
new string[this.collections.Count];
1586 this.collections.Keys.CopyTo(Result, 0);
1599 return Task.FromResult<
string[]>(this.
Collections);
1611 return this.
Export(Output, Restriction,
null);
1642 string[] BlockIds = Restriction?.
BlockIds ??
new string[] {
null };
1644 foreach (
string BlockId
in BlockIds)
1646 string[] Creators = Restriction?.
Creators ??
new string[] {
null };
1648 foreach (
string Creator
in Creators)
1650 List<Filter> Filters =
new List<Filter>()
1655 if (!
string.IsNullOrEmpty(BlockId))
1658 if (!
string.IsNullOrEmpty(Creator))
1679 if (Filters.Count > 1)
1687 while (await Blocks.MoveNextAsync())
1721 while (await e.MoveNextAsync())
1729 foreach (KeyValuePair<string, object> P
in Obj)
1735 catch (Exception ex)
1738 if (!await this.ReportException(ex, Output))
1743 Continue = await Output.
EndEntry();
1752 Continue = await Output.
EndBlock();
1761 catch (Exception ex)
1764 if (!await this.ReportException(ex, Output))
1776 catch (Exception ex)
1779 if (!await this.ReportException(ex, Output))
1793 private async Task<bool> ReportException(Exception ex,
ILedgerExport Output)
1797 if (ex is AggregateException ex2)
1799 foreach (Exception ex3
in ex2.InnerExceptions)
1818 if (!(this.externalEvents is
null) && this.externalEvents !=
ExternalEvents)
1819 throw new Exception(
"An interface for external events has already been registered.");
1831 if (!(this.externalEvents is
null) && this.externalEvents !=
ExternalEvents)
1832 throw new Exception(
"The registered interface for external events differs from the one presented.");
1834 this.externalEvents =
null;
1844 neuroLedgerClientType ??=
Types.
GetType(
"Waher.Networking.XMPP.NeuroLedger.NeuroLedgerClient");
1846 return this.externalEvents;
1850 private static Type neuroLedgerClientType =
null;
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.
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.
async Task Delete()
Deletes the file, and disposes of the object.
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
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.
Task< byte[]> Decrypt(byte[] Data, string Property, string Collection, Guid ObjectId)
Decrypts field data.
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< byte[]> Encrypt(byte[] Data, string Property, string Collection, Guid ObjectId, int MinLength)
Encrypts field data.
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 DisposeAsync()
IDisposableAsync.DisposeAsync
async Task< bool > MoveNextAsync()
Moves to next item.
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.
async Task< IObjectSerializer > GetObjectSerializer(Type Type)
Gets the object serializer corresponding to a specific type.
async Task DisposeAsync()
IDisposableAsync.DisposeAsync
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.
Static class that dynamically manages types and interfaces available in the runtime environment.
static Type GetType(string FullName)
Gets a type, given its full name.
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...
Represents an asynchronous operation to be performed.
Task< bool > Wait()
Waits for the item to be processed.
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.
Checks for an approved type in the call stack.
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 asynchronously disposable objects.
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 > ReportException(Exception Exception)
Is called when an exception has occurred.
Task< bool > StartLedger(ILedgerProvider Provider)
Is called when export of ledger is started.
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.