using SQLite;
using System;
using System.Threading;
using ZeroLevel.Services.Serialization;
namespace ZeroLevel.SqLite
{
public sealed class PacketRecord
{
[PrimaryKey, AutoIncrement]
public long Id { get; set; }
[Indexed]
public long Timestamp { get; set; }
public byte[] Data { get; set; }
}
///
/// Промежуточное/временное хранилище пакетов данных, для случаев сбоя доставок через шину данных
///
public sealed class SqLitePacketBuffer
: BaseSqLiteDB
where T : IBinarySerializable
{
private sealed class PacketBufferRecord
{
public int Id { get; set; }
public byte[] Body { get; set; }
}
#region Fields
private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
#endregion Fields
public SqLitePacketBuffer(string database_file_path)
: base(database_file_path)
{
CreateTable();
}
public void Push(T frame)
{
long id = -1;
_rwLock.EnterWriteLock();
var creationTime = DateTime.Now.Ticks;
try
{
id = Append(new PacketRecord
{
Data = MessageSerializer.Serialize(frame),
Timestamp = creationTime
}).Id;
}
catch (Exception ex)
{
Log.Error(ex, $"[SqLitePacketBuffer] Fault insert record in buffer storage.");
}
finally
{
_rwLock.ExitWriteLock();
}
}
public bool Pop(Func pop_callback)
{
bool success = false;
long id = -1;
_rwLock.EnterReadLock();
try
{
var record = Single(r => r.Timestamp);
id = record.Id;
var body = record.Data;
try
{
success = pop_callback(MessageSerializer.Deserialize(body));
}
catch (Exception ex)
{
Log.Error(ex, "Fault handle buffered data");
}
}
catch (Exception ex)
{
Log.Error(ex, "[SqLitePacketBuffer] Fault preload datafrom db");
}
finally
{
_rwLock.ExitReadLock();
}
if (success)
{
RemoveRecordById(id);
}
return success;
}
private void RemoveRecordById(long id)
{
_rwLock.EnterWriteLock();
try
{
Delete(r => r.Id == id);
}
catch (Exception ex)
{
Log.Error(ex, $"[SqLitePacketBuffer] Fault remove record by id '{id}'");
}
finally
{
_rwLock.ExitWriteLock();
}
}
protected override void DisposeStorageData()
{
}
}
}