206 lines
4.9 KiB
C#
206 lines
4.9 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace Salmon.Core.Depth;
|
|
|
|
public class StateMachine
|
|
{
|
|
public Persistence? History { get; set; }
|
|
public EventManager? Events { get; set; }
|
|
|
|
class ImplValue
|
|
{
|
|
public object? Value { get; set; }
|
|
public DateTime When { get; set; } = DateTime.Now;
|
|
|
|
public ImplValue(object? value, DateTime? when = null)
|
|
{
|
|
Value = value;
|
|
When = when ?? DateTime.Now;
|
|
}
|
|
}
|
|
|
|
object Mutex = new object();
|
|
Dictionary<string, Dictionary<string, ImplValue>> Implementation = new ();
|
|
public bool Populated { get; private set; } = false;
|
|
|
|
public async Task<long> PopulateWithHistory()
|
|
{
|
|
Populated = true;
|
|
long count = 0;
|
|
if (History is not null)
|
|
await foreach (var i in History.GetState())
|
|
{
|
|
Push(i);
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
public void Push(Triplet triplet)
|
|
{
|
|
Push(triplet.key, triplet.predicate, triplet.value, triplet.LastFlush);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update string value in dictionary
|
|
/// Must be thread safe
|
|
/// </summary>
|
|
/// <param name="key">May not be null</param>
|
|
/// <param name="value">May be null</param>
|
|
public void Push(string key, string predicate, object? value, DateTime when)
|
|
{
|
|
if(key == null) throw new ArgumentNullException(nameof(key));
|
|
|
|
|
|
if (Get(key, predicate) == value)
|
|
return;
|
|
|
|
var implVal = new ImplValue(value, when);
|
|
|
|
lock (Mutex)
|
|
{
|
|
if(!Implementation.ContainsKey(key))
|
|
{
|
|
Dictionary<string, ImplValue> dic = new();
|
|
dic.Add(predicate, implVal);
|
|
Implementation.Add(key, dic);
|
|
}
|
|
|
|
var keyDic = Implementation[key];
|
|
if(!keyDic.TryAdd(predicate, implVal))
|
|
{
|
|
var old = keyDic[predicate];
|
|
if (old.When > when)
|
|
return;
|
|
keyDic[predicate] = implVal;
|
|
}
|
|
|
|
}
|
|
|
|
if(History is not null)
|
|
History.PushStateChange(key, predicate, value, when);
|
|
|
|
if (Events is not null)
|
|
Events.Push(Event.FromStateChange(key, value, when));
|
|
}
|
|
|
|
public IEnumerable<string> GetIds()
|
|
{
|
|
lock (Mutex)
|
|
{
|
|
if (!Populated)
|
|
PopulateWithHistory().Wait();
|
|
|
|
foreach (var kv in Implementation)
|
|
yield return kv.Key;
|
|
}
|
|
|
|
}
|
|
|
|
public IEnumerable<Triplet> Get()
|
|
{
|
|
lock (Mutex)
|
|
{
|
|
if (!Populated)
|
|
PopulateWithHistory().Wait();
|
|
|
|
foreach (var kv in Implementation)
|
|
foreach (var kvv in kv.Value)
|
|
yield return new Triplet
|
|
{
|
|
key = kv.Key,
|
|
predicate = kvv.Key,
|
|
value = kvv.Value.Value,
|
|
LastFlush = kvv.Value.When
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
public IEnumerable<Triplet> Get(string key)
|
|
{
|
|
Dictionary<string, ImplValue> dic;
|
|
|
|
|
|
lock (Mutex)
|
|
{
|
|
if (!Populated)
|
|
PopulateWithHistory().Wait();
|
|
|
|
if (!Implementation.TryGetValue(key, out dic))
|
|
yield break;
|
|
}
|
|
|
|
|
|
foreach(var kv in dic)
|
|
yield return new Triplet
|
|
{
|
|
key = key,
|
|
predicate = kv.Key,
|
|
value = kv.Value.Value,
|
|
LastFlush = kv.Value.When
|
|
};
|
|
}
|
|
|
|
public DateTime? GetLastUpdate(string key)
|
|
{
|
|
Dictionary<string, ImplValue> dic;
|
|
|
|
|
|
|
|
lock (Mutex)
|
|
{
|
|
if (!Populated)
|
|
PopulateWithHistory().Wait();
|
|
|
|
if (!Implementation.TryGetValue(key, out dic))
|
|
return null;
|
|
}
|
|
|
|
|
|
DateTime mostrecent = DateTime.MinValue;
|
|
foreach (var kv in dic)
|
|
if(kv.Value.When > mostrecent)
|
|
mostrecent = kv.Value.When;
|
|
|
|
if (mostrecent == DateTime.MinValue)
|
|
return null;
|
|
|
|
return mostrecent;
|
|
}
|
|
|
|
public object? Get(string key, string predicate)
|
|
{
|
|
lock (Mutex)
|
|
{
|
|
if (!Populated)
|
|
PopulateWithHistory().Wait();
|
|
|
|
if (Implementation.TryGetValue(key, out var value))
|
|
if (value.TryGetValue(predicate, out var ret))
|
|
return ret;
|
|
}
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
public long CountTriplets()
|
|
{
|
|
lock(Mutex)
|
|
{
|
|
if (!Populated)
|
|
PopulateWithHistory().Wait();
|
|
|
|
long c = 0;
|
|
foreach (var kv in Implementation)
|
|
foreach (var i in kv.Key)
|
|
c++;
|
|
|
|
return c;
|
|
}
|
|
|
|
}
|
|
}
|