/Horizon/Database/SnapshotDatabase.cs/SnapshotDatabase.cs |
@@ -6,6 +6,8 @@ |
using System.Globalization; |
using System.IO; |
using System.IO.Compression; |
using System.Runtime.CompilerServices; |
using System.Security.AccessControl; |
using System.Security.Cryptography; |
using System.Threading; |
using System.Threading.Tasks; |
@@ -45,6 +47,12 @@ |
private const string RemoveSnapshotFromHashSql = |
"DELETE FROM \"Snapshots\" WHERE Hash = @hash"; |
|
private const string GetTransferSnapshotFromHashSql = |
"SELECT \"Name\", \"Path\", \"Time\", \"Data\", \"Shot\", \"Color\", \"Hash\", \"Note\" FROM \"Snapshots\" WHERE Hash = @hash"; |
|
private const string SetTransferSnapshotSql = |
"INSERT INTO \"Snapshots\" ( \"Name\", \"Path\", \"Time\", \"Data\", \"Shot\", \"Color\", \"Hash\", \"Note\" ) VALUES ( @name, @path, @time, zeroblob(@dataLength), zeroblob(@shotLength), @color, @hash, @note )"; |
|
private const string RemoveScreenshotFromHashSql = |
"UPDATE \"Snapshots\" SET Shot = null WHERE Hash = @hash"; |
|
@@ -89,6 +97,8 @@ |
|
public event EventHandler<SnapshotCreateEventArgs> SnapshotCreate; |
|
public event EventHandler<SnapshotCreateEventArgs> SnapshotTransferReceived; |
|
public event EventHandler<SnapshotRevertEventArgs> SnapshotRevert; |
|
#endregion |
@@ -96,22 +106,33 @@ |
#region Private Delegates, Events, Enums, Properties, Indexers and Fields |
|
private readonly CancellationTokenSource _cancellationTokenSource; |
private readonly SemaphoreSlim _databaseLock; |
private readonly SQLiteConnectionStringBuilder _sqliteConnectionStringBuilder; |
|
private SemaphoreSlim _snapshotSemaphore; |
|
#endregion |
|
#region Constructors, Destructors and Finalizers |
|
public SnapshotDatabase() |
private SnapshotDatabase() |
{ |
_cancellationTokenSource = new CancellationTokenSource(); |
_cancellationToken = _cancellationTokenSource.Token; |
Directory.CreateDirectory(Constants.DatabaseDirectory); |
|
_snapshotSemaphore = new SemaphoreSlim(1, 1); |
_databaseLock = new SemaphoreSlim(1, 1); |
|
Directory.CreateDirectory(Constants.DatabaseDirectory); |
_sqliteConnectionStringBuilder = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
} |
|
public SnapshotDatabase(CancellationToken cancellationToken) : this() |
{ |
_cancellationTokenSource = new CancellationTokenSource(); |
var localCancellationToken = _cancellationTokenSource.Token; |
var combinedCancellationTokenSource = |
CancellationTokenSource.CreateLinkedTokenSource(localCancellationToken, cancellationToken); |
_cancellationToken = combinedCancellationTokenSource.Token; |
|
CreateDatabase(_cancellationToken).ContinueWith(async createDatabaseTask => |
{ |
try |
@@ -122,14 +143,14 @@ |
{ |
await SetAutoVacuum(_cancellationToken); |
} |
catch |
catch (Exception exception) |
{ |
Log.Error("Unable to set auto vacuum for database."); |
Log.Error(exception, "Unable to set auto vacuum for database."); |
} |
} |
catch |
catch (Exception exception) |
{ |
Log.Error("Unable to create database;"); |
Log.Error(exception, "Unable to create database;"); |
} |
}).Wait(_cancellationToken); |
} |
@@ -137,9 +158,6 @@ |
public void Dispose() |
{ |
_cancellationTokenSource.Cancel(); |
|
_snapshotSemaphore?.Dispose(); |
_snapshotSemaphore = null; |
} |
|
#endregion |
@@ -146,7 +164,7 @@ |
|
#region Public Methods |
|
public async Task DeleteScreenshot(string hash, CancellationToken cancellationToken) |
public async Task DeleteScreenshotAsync(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
@@ -153,17 +171,18 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveScreenshotFromHashSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveScreenshotFromHashSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
@@ -172,464 +191,769 @@ |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task NormalizeTime(string hash, CancellationToken cancellationToken) |
public async Task NormalizeTimeAsync(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var readSQLiteCommand = new SQLiteCommand(RetrieveTimeFromHash, sqliteConnection)) |
{ |
readSQLiteCommand.Parameters.AddRange(new[] |
using (var readSQLiteCommand = new SQLiteCommand(RetrieveTimeFromHash, sqliteConnection)) |
{ |
new SQLiteParameter("@hash", hash) |
}); |
readSQLiteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
readSQLiteCommand.Prepare(); |
readSQLiteCommand.Prepare(); |
|
using (var sqlDataReader = await readSQLiteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
using (var sqlDataReader = await readSQLiteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
try |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
try |
{ |
var time = (string)sqlDataReader["Time"]; |
|
// Skip if already ISO 8601 |
if (DateTime.TryParseExact(time, |
"yyyy-MM-ddTHH:mm:ss.fff", |
CultureInfo.InvariantCulture, |
DateTimeStyles.None, out _)) |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
continue; |
} |
var time = (string)sqlDataReader["Time"]; |
|
if (!DateTime.TryParse(time, out var dateTime)) |
{ |
dateTime = DateTime.Now; |
} |
// Skip if already ISO 8601 |
if (DateTime.TryParseExact(time, |
"yyyy-MM-ddTHH:mm:ss.fff", |
CultureInfo.InvariantCulture, |
DateTimeStyles.None, out _)) |
{ |
continue; |
} |
|
using (var writeSQLiteCommand = |
new SQLiteCommand(UpdateTimeFromHash, sqliteConnection, dbTransaction)) |
{ |
writeSQLiteCommand.Parameters.AddRange(new[] |
if (!DateTime.TryParse(time, out var dateTime)) |
{ |
new SQLiteParameter("@time", dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff")), |
new SQLiteParameter("@hash", hash) |
}); |
dateTime = DateTime.Now; |
} |
|
writeSQLiteCommand.Prepare(); |
using (var writeSQLiteCommand = |
new SQLiteCommand(UpdateTimeFromHash, sqliteConnection, dbTransaction)) |
{ |
writeSQLiteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@time", |
dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff")), |
new SQLiteParameter("@hash", hash) |
}); |
|
await writeSQLiteCommand.ExecuteNonQueryAsync(cancellationToken); |
writeSQLiteCommand.Prepare(); |
|
await writeSQLiteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
} |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
dbTransaction.Commit(); |
throw; |
} |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<long> CountSnapshots(CancellationToken cancellationToken) |
public async Task<long> CountSnapshotsAsync(CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(CountSnapshotsSql, sqliteConnection)) |
{ |
long count = 0; |
|
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(CountSnapshotsSql, sqliteConnection)) |
{ |
long count = 0; |
sqliteCommand.Prepare(); |
|
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
if (!(sqlDataReader[0] is long dbCount)) |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
count = -1; |
break; |
if (!(sqlDataReader[0] is long dbCount)) |
{ |
count = -1; |
break; |
} |
|
count = dbCount; |
} |
|
count = dbCount; |
return count; |
} |
|
return count; |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<IEnumerable<Snapshot>> LoadSnapshots(CancellationToken cancellationToken) |
public async IAsyncEnumerable<Snapshot> LoadSnapshotsAsync([EnumeratorCancellation] CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrieveSnapshotsSql, sqliteConnection)) |
{ |
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
//var snapshots = new List<Snapshot>(); |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
var name = (string)sqlDataReader["Name"]; |
var path = (string)sqlDataReader["Path"]; |
var time = (string)sqlDataReader["Time"]; |
var hash = (string)sqlDataReader["Hash"]; |
|
var color = Color.Empty; |
|
if (!(sqlDataReader["Color"] is DBNull)) |
{ |
var dbColor = Convert.ToInt32(sqlDataReader["Color"]); |
|
switch (dbColor) |
{ |
case 0: |
color = Color.Empty; |
break; |
default: |
color = Color.FromArgb(dbColor); |
break; |
} |
} |
|
yield return new Snapshot(name, path, time, hash, color); |
} |
} |
} |
} |
} |
finally |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
_databaseLock.Release(); |
} |
} |
|
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrieveSnapshotsSql, sqliteConnection)) |
public async Task ApplyTransferSnapshotAsync(TransferSnapshot transferSnapshot, CancellationToken cancellationToken) |
{ |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
sqliteCommand.Prepare(); |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
var color = Color.Empty; |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
var snapshots = new List<Snapshot>(); |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
try |
{ |
var name = (string)sqlDataReader["Name"]; |
var path = (string)sqlDataReader["Path"]; |
var time = (string)sqlDataReader["Time"]; |
var hash = (string)sqlDataReader["Hash"]; |
using (var dataMemoryStream = new MemoryStream()) |
{ |
using (var dataZipStream = |
new GZipStream(dataMemoryStream, CompressionMode.Compress, true)) |
{ |
dataMemoryStream.Position = 0L; |
await dataZipStream.WriteAsync(transferSnapshot.Data, 0, |
transferSnapshot.Data.Length, cancellationToken); |
dataZipStream.Close(); |
|
var color = Color.Empty; |
using (var bitmapMemoryStream = new MemoryStream()) |
{ |
bitmapMemoryStream.Position = 0L; |
using (var bitmapZipStream = |
new GZipStream(bitmapMemoryStream, CompressionMode.Compress, |
true)) |
{ |
using (var transferImageStream = new MemoryStream(transferSnapshot.Shot)) |
{ |
transferImageStream.Position = 0L; |
await transferImageStream.CopyToAsync(bitmapZipStream); |
bitmapZipStream.Close(); |
bitmapMemoryStream.Position = 0L; |
|
if (!(sqlDataReader["Color"] is DBNull)) |
{ |
var dbColor = Convert.ToInt32(sqlDataReader["Color"]); |
var a = bitmapMemoryStream.ToArray(); |
|
switch (dbColor) |
{ |
case 0: |
color = Color.Empty; |
break; |
default: |
color = Color.FromArgb(dbColor); |
break; |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(SetTransferSnapshotSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@name", transferSnapshot.Name), |
new SQLiteParameter("@path", transferSnapshot.Path), |
new SQLiteParameter("@time", transferSnapshot.Time), |
new SQLiteParameter("@dataLength", |
dataMemoryStream.Length), |
new SQLiteParameter("@shotLength", |
bitmapMemoryStream.Length), |
new SQLiteParameter("@hash", transferSnapshot.Hash), |
new SQLiteParameter("@note", transferSnapshot.Note) |
}); |
|
var numeric = transferSnapshot.Color; |
switch (numeric) |
{ |
case 0: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", DBNull.Value)); |
color = Color.Empty; |
break; |
default: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", numeric)); |
color = Color.FromArgb(transferSnapshot.Color); |
break; |
} |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
|
// Insert the data blobs. |
using (var sqliteCommand = |
new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Prepare(); |
|
var rowId = |
(long)await sqliteCommand.ExecuteScalarAsync( |
cancellationToken); |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", |
"Snapshots", |
"Data", |
rowId, |
false)) |
{ |
var fileMemoryStreamData = dataMemoryStream.ToArray(); |
|
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
} |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", |
"Snapshots", |
"Shot", |
rowId, |
false)) |
{ |
var bitmapMemoryStreamData = |
bitmapMemoryStream.ToArray(); |
|
sqliteBlob.Write(bitmapMemoryStreamData, |
bitmapMemoryStreamData.Length, |
0); |
} |
} |
|
dbTransaction.Commit(); |
|
SnapshotTransferReceived?.Invoke(this, |
new SnapshotCreateSuccessEventArgs( |
transferSnapshot.Name, |
transferSnapshot.Time, |
transferSnapshot.Path, |
color, |
transferSnapshot.Hash) |
); |
} |
} |
} |
} |
} |
} |
catch (SQLiteException exception) |
{ |
dbTransaction.Rollback(); |
|
snapshots.Add(new Snapshot(name, path, time, hash, color)); |
if (exception.ResultCode != SQLiteErrorCode.Constraint) |
{ |
SnapshotTransferReceived?.Invoke(this, |
new SnapshotCreateFailureEventArgs( |
transferSnapshot.Name, |
transferSnapshot.Path, |
color, |
exception) |
); |
} |
|
throw; |
} |
catch (Exception exception) |
{ |
dbTransaction.Rollback(); |
|
return snapshots; |
SnapshotTransferReceived?.Invoke(this, |
new SnapshotCreateFailureEventArgs( |
transferSnapshot.Name, |
transferSnapshot.Path, |
color, |
exception) |
); |
|
throw; |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task CreateSnapshot(string name, string path, Color color, CancellationToken cancellationToken) |
|
public async Task<TransferSnapshot> GenerateTransferSnapshotAsync(string hash, CancellationToken cancellationToken) |
{ |
await _snapshotSemaphore.WaitAsync(cancellationToken); |
|
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(GetTransferSnapshotFromHashSql, sqliteConnection)) |
{ |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
{ |
using (var md5 = MD5.Create()) |
sqliteCommand.Parameters.AddRange(new[] |
{ |
using (var hashMemoryStream = new MemoryStream()) |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
//var snapshots = new List<Snapshot>(); |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read, |
FileShare.Read, |
cancellationToken)) |
var name = (string)sqlDataReader["Name"]; |
var path = (string)sqlDataReader["Path"]; |
var time = (string)sqlDataReader["Time"]; |
|
var color = Color.Empty; |
|
if (!(sqlDataReader["Color"] is DBNull)) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(hashMemoryStream); |
var dbColor = Convert.ToInt32(sqlDataReader["Color"]); |
|
hashMemoryStream.Position = 0L; |
var hash = md5.ComputeHash(hashMemoryStream); |
var hashHex = BitConverter.ToString(hash).Replace("-", "") |
.ToLowerInvariant(); |
switch (dbColor) |
{ |
case 0: |
color = Color.Empty; |
break; |
default: |
color = Color.FromArgb(dbColor); |
break; |
} |
} |
|
using (var fileMemoryStream = new MemoryStream()) |
var note = string.Empty; |
|
if (!(sqlDataReader["Note"] is DBNull)) |
{ |
note = (string)sqlDataReader["Note"]; |
} |
|
Bitmap shot = null; |
|
if (!(sqlDataReader["Shot"] is DBNull)) |
{ |
var readStream = sqlDataReader.GetStream(4); |
|
readStream.Position = 0L; |
|
using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
using (var fileZipStream = |
new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) |
using (var image = Image.FromStream(zipStream)) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(fileZipStream); |
fileZipStream.Close(); |
shot = new Bitmap(image); |
} |
} |
} |
|
var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff"); |
byte[] data = null; |
if (!(sqlDataReader["Data"] is DBNull)) |
{ |
using (var readStream = sqlDataReader.GetStream(3)) |
{ |
using (var memoryStream = new MemoryStream()) |
{ |
readStream.Position = 0L; |
|
fileMemoryStream.Position = 0L; |
await readStream.CopyToAsync(memoryStream); |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(SnapshotFileNoScreenshotSql, sqliteConnection, |
dbTransaction)) |
memoryStream.Position = 0L; |
|
using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@name", name), |
new SQLiteParameter("@time", time), |
new SQLiteParameter("@path", path), |
new SQLiteParameter("@dataLength", |
fileMemoryStream.Length), |
new SQLiteParameter("@hash", hashHex) |
}); |
// Do not dispose the returned stream and leave it up to callers to dispose. |
var outputStream = new MemoryStream(); |
|
var numeric = color.ToArgb(); |
switch (numeric) |
{ |
case 0: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", null)); |
break; |
default: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", numeric)); |
break; |
} |
await zipStream.CopyToAsync(outputStream); |
|
sqliteCommand.Prepare(); |
outputStream.Position = 0L; |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
data = outputStream.ToArray(); |
} |
} |
} |
} |
|
// Insert the data blobs. |
using (var sqliteCommand = |
new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, |
dbTransaction)) |
return new TransferSnapshot(name, path, time, hash, color, shot, note, data); |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
|
return null; |
} |
|
public async Task CreateSnapshotAsync(string name, string path, Color color, CancellationToken cancellationToken) |
{ |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
{ |
using (var md5 = MD5.Create()) |
{ |
using (var hashMemoryStream = new MemoryStream()) |
{ |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read, |
FileShare.Read, |
cancellationToken)) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(hashMemoryStream); |
|
hashMemoryStream.Position = 0L; |
var hash = md5.ComputeHash(hashMemoryStream); |
var hashHex = BitConverter.ToString(hash).Replace("-", "") |
.ToLowerInvariant(); |
|
using (var fileMemoryStream = new MemoryStream()) |
{ |
using (var fileZipStream = |
new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) |
{ |
sqliteCommand.Prepare(); |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(fileZipStream); |
fileZipStream.Close(); |
|
var rowId = |
(long)await sqliteCommand.ExecuteScalarAsync(cancellationToken); |
var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff"); |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", "Data", |
rowId, |
false)) |
fileMemoryStream.Position = 0L; |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(SnapshotFileNoScreenshotSql, sqliteConnection, |
dbTransaction)) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@name", name), |
new SQLiteParameter("@time", time), |
new SQLiteParameter("@path", path), |
new SQLiteParameter("@dataLength", |
fileMemoryStream.Length), |
new SQLiteParameter("@hash", hashHex) |
}); |
|
sqliteBlob.Write(fileMemoryStreamData, fileMemoryStreamData.Length, |
0); |
var numeric = color.ToArgb(); |
switch (numeric) |
{ |
case 0: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", DBNull.Value)); |
break; |
default: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", numeric)); |
break; |
} |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
} |
|
dbTransaction.Commit(); |
// Insert the data blobs. |
using (var sqliteCommand = |
new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Prepare(); |
|
SnapshotCreate?.Invoke(this, |
new SnapshotCreateSuccessEventArgs(name, time, path, color, |
hashHex)); |
var rowId = |
(long)await sqliteCommand.ExecuteScalarAsync(cancellationToken); |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", |
"Data", |
rowId, |
false)) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
|
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
} |
} |
|
dbTransaction.Commit(); |
|
SnapshotCreate?.Invoke(this, |
new SnapshotCreateSuccessEventArgs(name, time, path, color, |
hashHex)); |
} |
} |
} |
} |
} |
} |
} |
catch (SQLiteException exception) |
{ |
dbTransaction.Rollback(); |
catch (SQLiteException exception) |
{ |
dbTransaction.Rollback(); |
|
if (exception.ResultCode != SQLiteErrorCode.Constraint) |
if (exception.ResultCode != SQLiteErrorCode.Constraint) |
{ |
SnapshotCreate?.Invoke(this, |
new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
} |
|
throw; |
} |
catch (Exception exception) |
{ |
dbTransaction.Rollback(); |
|
SnapshotCreate?.Invoke(this, |
new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
|
throw; |
} |
|
throw; |
} |
catch (Exception exception) |
{ |
dbTransaction.Rollback(); |
|
SnapshotCreate?.Invoke(this, new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
|
throw; |
} |
finally |
{ |
_snapshotSemaphore.Release(); |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task CreateSnapshot(string name, string path, |
public async Task CreateSnapshotAsync(string name, string path, |
Bitmap shot, Color color, CancellationToken cancellationToken) |
{ |
await _snapshotSemaphore.WaitAsync(cancellationToken); |
|
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
using (var md5 = MD5.Create()) |
try |
{ |
using (var hashMemoryStream = new MemoryStream()) |
using (var md5 = MD5.Create()) |
{ |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read, |
FileShare.Read, |
cancellationToken)) |
using (var hashMemoryStream = new MemoryStream()) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(hashMemoryStream); |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read, |
FileShare.Read, |
cancellationToken)) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(hashMemoryStream); |
|
hashMemoryStream.Position = 0L; |
var hash = md5.ComputeHash(hashMemoryStream); |
var hashHex = BitConverter.ToString(hash).Replace("-", "") |
.ToLowerInvariant(); |
hashMemoryStream.Position = 0L; |
var hash = md5.ComputeHash(hashMemoryStream); |
var hashHex = BitConverter.ToString(hash).Replace("-", "") |
.ToLowerInvariant(); |
|
using (var fileMemoryStream = new MemoryStream()) |
{ |
using (var fileZipStream = |
new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) |
using (var fileMemoryStream = new MemoryStream()) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(fileZipStream); |
fileZipStream.Close(); |
using (var fileZipStream = |
new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) |
{ |
fileStream.Position = 0L; |
await fileStream.CopyToAsync(fileZipStream); |
fileZipStream.Close(); |
|
using (var bitmapMemoryStream = new MemoryStream()) |
{ |
using (var bitmapZipStream = |
new GZipStream(bitmapMemoryStream, CompressionMode.Compress, |
true)) |
using (var bitmapMemoryStream = new MemoryStream()) |
{ |
shot.Save(bitmapZipStream, ImageFormat.Bmp); |
bitmapZipStream.Close(); |
using (var bitmapZipStream = |
new GZipStream(bitmapMemoryStream, CompressionMode.Compress, |
true)) |
{ |
shot.Save(bitmapZipStream, ImageFormat.Bmp); |
bitmapZipStream.Close(); |
|
var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff"); |
var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff"); |
|
fileMemoryStream.Position = 0L; |
bitmapMemoryStream.Position = 0L; |
fileMemoryStream.Position = 0L; |
bitmapMemoryStream.Position = 0L; |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(SnapshotFileSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(SnapshotFileSql, sqliteConnection, |
dbTransaction)) |
{ |
new SQLiteParameter("@name", name), |
new SQLiteParameter("@time", time), |
new SQLiteParameter("@path", path), |
new SQLiteParameter("@shotLength", |
bitmapMemoryStream.Length), |
new SQLiteParameter("@dataLength", |
fileMemoryStream.Length), |
new SQLiteParameter("@hash", hashHex) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@name", name), |
new SQLiteParameter("@time", time), |
new SQLiteParameter("@path", path), |
new SQLiteParameter("@shotLength", |
bitmapMemoryStream.Length), |
new SQLiteParameter("@dataLength", |
fileMemoryStream.Length), |
new SQLiteParameter("@hash", hashHex) |
}); |
|
var numeric = color.ToArgb(); |
switch (numeric) |
{ |
case 0: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", null)); |
break; |
default: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", numeric)); |
break; |
var numeric = color.ToArgb(); |
switch (numeric) |
{ |
case 0: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", DBNull.Value)); |
break; |
default: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", numeric)); |
break; |
} |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
|
sqliteCommand.Prepare(); |
// Insert the data blobs. |
using (var sqliteCommand = |
new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
var rowId = |
(long)await sqliteCommand.ExecuteScalarAsync( |
cancellationToken); |
|
// Insert the data blobs. |
using (var sqliteCommand = |
new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Prepare(); |
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", |
"Snapshots", |
"Data", |
rowId, |
false)) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
|
var rowId = |
(long)await sqliteCommand.ExecuteScalarAsync( |
cancellationToken); |
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
} |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", |
"Data", |
rowId, |
false)) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", |
"Snapshots", |
"Shot", |
rowId, |
false)) |
{ |
var bitmapMemoryStreamData = |
bitmapMemoryStream.ToArray(); |
|
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
sqliteBlob.Write(bitmapMemoryStreamData, |
bitmapMemoryStreamData.Length, |
0); |
} |
} |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", |
"Shot", |
rowId, |
false)) |
{ |
var bitmapMemoryStreamData = bitmapMemoryStream.ToArray(); |
dbTransaction.Commit(); |
|
sqliteBlob.Write(bitmapMemoryStreamData, |
bitmapMemoryStreamData.Length, |
0); |
} |
SnapshotCreate?.Invoke(this, |
new SnapshotCreateSuccessEventArgs(name, time, path, color, |
hashHex)); |
} |
|
dbTransaction.Commit(); |
|
SnapshotCreate?.Invoke(this, |
new SnapshotCreateSuccessEventArgs(name, time, path, color, |
hashHex)); |
} |
} |
} |
@@ -637,81 +961,81 @@ |
} |
} |
} |
} |
catch (SQLiteException exception) |
{ |
dbTransaction.Rollback(); |
catch (SQLiteException exception) |
{ |
dbTransaction.Rollback(); |
|
if (exception.ResultCode != SQLiteErrorCode.Constraint) |
if (exception.ResultCode != SQLiteErrorCode.Constraint) |
{ |
SnapshotCreate?.Invoke(this, |
new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
} |
|
throw; |
} |
catch (Exception exception) |
{ |
dbTransaction.Rollback(); |
|
SnapshotCreate?.Invoke(this, |
new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
|
throw; |
} |
|
throw; |
} |
catch (Exception exception) |
{ |
dbTransaction.Rollback(); |
|
SnapshotCreate?.Invoke(this, new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
|
throw; |
} |
finally |
{ |
_snapshotSemaphore.Release(); |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task SaveFile(string path, string hash, CancellationToken cancellationToken) |
public async Task SaveFileAsync(string path, string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection)) |
{ |
new SQLiteParameter("@hash", hash) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
// Create directories if they do not exist. |
var dir = Path.GetDirectoryName(path); |
|
if (dir != null && !Directory.Exists(dir)) |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
Directory.CreateDirectory(dir); |
} |
// Create directories if they do not exist. |
var dir = Path.GetDirectoryName(path); |
|
using (var readStream = sqlDataReader.GetStream(2)) |
{ |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Create, FileAccess.Write, |
FileShare.Write, |
cancellationToken)) |
if (dir != null && !Directory.Exists(dir)) |
{ |
readStream.Position = 0L; |
Directory.CreateDirectory(dir); |
} |
|
using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) |
using (var readStream = sqlDataReader.GetStream(2)) |
{ |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Create, FileAccess.Write, |
FileShare.Write, |
cancellationToken)) |
{ |
await zipStream.CopyToAsync(fileStream); |
readStream.Position = 0L; |
|
using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
await zipStream.CopyToAsync(fileStream); |
} |
} |
} |
} |
@@ -719,209 +1043,184 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RevertFile(string name, string hash, CancellationToken cancellationToken, bool atomic = true) |
public async Task RevertFileAsync(string name, string hash, CancellationToken cancellationToken, bool atomic = true) |
{ |
await _snapshotSemaphore.WaitAsync(cancellationToken); |
|
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection)) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
try |
{ |
new SQLiteParameter("@hash", hash) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
var path = (string)sqlDataReader["Path"]; |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
var path = (string)sqlDataReader["Path"]; |
|
// Create directories if they do not exist. |
var dir = Path.GetDirectoryName(path); |
// Create directories if they do not exist. |
var dir = Path.GetDirectoryName(path); |
|
if (dir != null && !Directory.Exists(dir)) |
{ |
Directory.CreateDirectory(dir); |
} |
if (dir != null && !Directory.Exists(dir)) |
{ |
Directory.CreateDirectory(dir); |
} |
|
switch (atomic) |
{ |
case true: |
// Atomic |
var temp = Path.Combine(Path.GetDirectoryName(path), |
$"{Path.GetFileName(path)}.temp"); |
switch (atomic) |
{ |
case true: |
// Atomic |
var temp = Path.Combine(dir, |
$"{Path.GetFileName(path)}.temp"); |
|
using (var readStream = sqlDataReader.GetStream(2)) |
{ |
using (var fileStream = new FileStream(temp, FileMode.Create, |
FileAccess.Write, |
FileShare.None)) |
using (var readStream = sqlDataReader.GetStream(2)) |
{ |
using (var zipStream = |
new GZipStream(readStream, CompressionMode.Decompress)) |
using (var fileStream = new FileStream(temp, FileMode.Create, |
FileAccess.Write, |
FileShare.None)) |
{ |
zipStream.CopyTo(fileStream); |
using (var zipStream = |
new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
await zipStream.CopyToAsync(fileStream); |
zipStream.Close(); |
} |
|
fileStream.Close(); |
} |
|
readStream.Close(); |
} |
} |
|
try |
{ |
File.Replace(temp, path, null, true); |
} |
catch |
{ |
try |
{ |
File.Delete(temp); |
if (!File.Exists(path)) |
{ |
File.Create(path).Close(); |
} |
|
File.Replace(temp, path, null, true); |
} |
catch (Exception exception) |
catch(Exception replaceException) |
{ |
// Suppress deletion errors of temporary file. |
Log.Warning(exception, "Could not delete temporary file.", temp); |
Log.Warning(replaceException, "Failed to copy temporary file."); |
try |
{ |
File.Delete(temp); |
} |
catch (Exception exception) |
{ |
// Suppress deletion errors of temporary file. |
Log.Warning(exception, "Could not delete temporary file.", temp); |
} |
|
throw; |
} |
|
throw; |
} |
|
break; |
default: |
// Asynchronous |
using (var readStream = sqlDataReader.GetStream(2)) |
{ |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Create, |
FileAccess.Write, |
FileShare.Write, |
cancellationToken)) |
break; |
default: |
// Asynchronous |
using (var readStream = sqlDataReader.GetStream(2)) |
{ |
readStream.Position = 0L; |
using (var fileStream = |
await Miscellaneous.GetFileStream(path, FileMode.Create, |
FileAccess.Write, |
FileShare.Write, |
cancellationToken)) |
{ |
readStream.Position = 0L; |
|
using (var zipStream = |
new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
await zipStream.CopyToAsync(fileStream); |
using (var zipStream = |
new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
await zipStream.CopyToAsync(fileStream); |
zipStream.Close(); |
} |
|
fileStream.Close(); |
} |
|
readStream.Close(); |
} |
} |
|
|
break; |
break; |
} |
|
SnapshotRevert?.Invoke(this, new SnapshotRevertSuccessEventArgs(name)); |
} |
|
SnapshotRevert?.Invoke(this, new SnapshotRevertSuccessEventArgs(name)); |
} |
} |
} |
catch |
{ |
SnapshotRevert?.Invoke(this, new SnapshotRevertFailureEventArgs(name)); |
catch |
{ |
SnapshotRevert?.Invoke(this, new SnapshotRevertFailureEventArgs(name)); |
|
throw; |
throw; |
} |
} |
finally |
{ |
_snapshotSemaphore.Release(); |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RemoveFileFast(IEnumerable<string> hashes, CancellationToken cancellationToken) |
public async Task RemoveFileFastAsync(IEnumerable<string> hashes, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
var transactionCommands = new List<Task>(); |
try |
{ |
var transactionCommands = new List<Task>(); |
|
foreach (var hash in hashes) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) |
foreach (var hash in hashes) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) |
{ |
new SQLiteParameter("@hash", hash) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
sqliteCommand.Prepare(); |
|
var command = sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
var command = sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
transactionCommands.Add(command); |
transactionCommands.Add(command); |
} |
} |
} |
|
await Task.WhenAll(transactionCommands); |
await Task.WhenAll(transactionCommands); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
} |
} |
} |
} |
|
public async Task RemoveFile(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
@@ -933,68 +1232,71 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task UpdateColor(string hash, Color color, CancellationToken cancellationToken) |
public async Task RemoveFileAsync(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateColorFromHashSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash), |
new SQLiteParameter("@color", color.ToArgb()) |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RemoveColor(string hash, CancellationToken cancellationToken) |
public async Task UpdateColorAsync(string hash, Color color, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
await _databaseLock.WaitAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
try |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveColorFromHashSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateColorFromHashSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
@@ -1001,217 +1303,229 @@ |
new SQLiteParameter("@hash", hash) |
}); |
|
var numeric = color.ToArgb(); |
switch (numeric) |
{ |
case 0: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", DBNull.Value)); |
break; |
default: |
sqliteCommand.Parameters.Add( |
new SQLiteParameter("@color", numeric)); |
break; |
} |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<SnapshotPreview> RetrievePreview(string hash, CancellationToken cancellationToken) |
public async Task RemoveColorAsync(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrievePreviewFromHashSql, sqliteConnection)) |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
await sqliteConnection.OpenAsync(cancellationToken); |
|
var note = string.Empty; |
|
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RemoveColorFromHashSql, sqliteConnection, dbTransaction)) |
{ |
if (!(sqlDataReader["Note"] is DBNull)) |
sqliteCommand.Parameters.AddRange(new[] |
{ |
note = (string)sqlDataReader["Note"]; |
} |
new SQLiteParameter("@hash", hash) |
}); |
|
Bitmap shot = null; |
sqliteCommand.Prepare(); |
|
if (!(sqlDataReader["Shot"] is DBNull)) |
try |
{ |
var readStream = sqlDataReader.GetStream(2); |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
readStream.Position = 0L; |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
using (var image = Image.FromStream(zipStream)) |
{ |
shot = new Bitmap(image); |
} |
} |
throw; |
} |
|
return new SnapshotPreview(hash, shot, note); |
} |
|
return null; |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
/* |
public MemoryStream RetrieveFileStream(string hash, CancellationToken cancellationToken) |
public async Task<SnapshotPreview> RetrievePreviewAsync(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
|
sqliteConnection.Open(); |
|
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrievePreviewFromHashSql, sqliteConnection)) |
{ |
new SQLiteParameter("@hash", hash) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
var note = string.Empty; |
|
using (var sqlDataReader = sqliteCommand.ExecuteReader()) |
{ |
sqliteCommand.Prepare(); |
|
while (sqlDataReader.Read()) |
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
using (var readStream = sqlDataReader.GetStream(1)) |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
if (!(sqlDataReader["Note"] is DBNull)) |
{ |
note = (string)sqlDataReader["Note"]; |
} |
|
using (var memoryStream = new MemoryStream()) |
Bitmap shot = null; |
|
if (!(sqlDataReader["Shot"] is DBNull)) |
{ |
var readStream = sqlDataReader.GetStream(2); |
|
readStream.Position = 0L; |
|
readStream.CopyTo(memoryStream); |
|
memoryStream.Position = 0L; |
|
using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) |
try |
{ |
|
var outputStream = new MemoryStream(); |
|
zipStream.CopyTo(outputStream); |
|
outputStream.Position = 0L; |
|
return outputStream; |
using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) |
{ |
using (var image = Image.FromStream(zipStream)) |
{ |
shot = new Bitmap(image); |
} |
} |
} |
catch (Exception exception) |
{ |
Log.Error(exception, $"Could not retrieve image preview for snapshot {hash}."); |
return null; |
} |
} |
|
return new SnapshotPreview(hash, shot, note); |
} |
|
return null; |
} |
|
return null; |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
*/ |
|
public async Task<MemoryStream> RetrieveFileStream(string hash, CancellationToken cancellationToken) |
public async Task<MemoryStream> RetrieveFileStreamAsync(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection)) |
{ |
new SQLiteParameter("@hash", hash) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
using (var readStream = sqlDataReader.GetStream(1)) |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
using (var memoryStream = new MemoryStream()) |
using (var readStream = sqlDataReader.GetStream(1)) |
{ |
readStream.Position = 0L; |
using (var memoryStream = new MemoryStream()) |
{ |
readStream.Position = 0L; |
|
await readStream.CopyToAsync(memoryStream); |
await readStream.CopyToAsync(memoryStream); |
|
memoryStream.Position = 0L; |
memoryStream.Position = 0L; |
|
using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) |
{ |
// Do not dispose the returned stream and leave it up to callers to dispose. |
var outputStream = new MemoryStream(); |
using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) |
{ |
// Do not dispose the returned stream and leave it up to callers to dispose. |
var outputStream = new MemoryStream(); |
|
await zipStream.CopyToAsync(outputStream); |
await zipStream.CopyToAsync(outputStream); |
|
outputStream.Position = 0L; |
outputStream.Position = 0L; |
|
return outputStream; |
return outputStream; |
} |
} |
} |
} |
|
return null; |
} |
|
return null; |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RelocateFile(string hash, string path, CancellationToken cancellationToken) |
public async Task RelocateFileAsync(string hash, string path, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RelocateFileFromHashSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(RelocateFileFromHashSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
@@ -1221,39 +1535,43 @@ |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
|
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task UpdateNote(string hash, string note, CancellationToken cancellationToken) |
public async Task UpdateNoteAsync(string hash, string note, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateNoteFromHashSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateNoteFromHashSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
@@ -1263,157 +1581,166 @@ |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
dbTransaction.Commit(); |
|
SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateSuccessEventArgs(note)); |
} |
catch |
{ |
dbTransaction.Rollback(); |
SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateSuccessEventArgs(note)); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateFailureEventArgs()); |
SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateFailureEventArgs()); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<string> UpdateFile(string hash, byte[] data, CancellationToken cancellationToken) |
public async Task<string> UpdateFileAsync(string hash, byte[] data, CancellationToken cancellationToken) |
{ |
using (var dataMemoryStream = new MemoryStream(data)) |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
using (var dataMemoryStream = new MemoryStream(data)) |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
using (var md5 = MD5.Create()) |
try |
{ |
using (var hashMemoryStream = new MemoryStream()) |
using (var md5 = MD5.Create()) |
{ |
dataMemoryStream.Position = 0L; |
await dataMemoryStream.CopyToAsync(hashMemoryStream); |
using (var hashMemoryStream = new MemoryStream()) |
{ |
dataMemoryStream.Position = 0L; |
await dataMemoryStream.CopyToAsync(hashMemoryStream); |
|
hashMemoryStream.Position = 0L; |
var recomputedHash = md5.ComputeHash(hashMemoryStream); |
var hashHex = BitConverter.ToString(recomputedHash).Replace("-", "") |
.ToLowerInvariant(); |
hashMemoryStream.Position = 0L; |
var recomputedHash = md5.ComputeHash(hashMemoryStream); |
var hashHex = BitConverter.ToString(recomputedHash).Replace("-", "") |
.ToLowerInvariant(); |
|
using (var fileMemoryStream = new MemoryStream()) |
{ |
using (var fileZipStream = |
new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) |
using (var fileMemoryStream = new MemoryStream()) |
{ |
dataMemoryStream.Position = 0L; |
await dataMemoryStream.CopyToAsync(fileZipStream); |
fileZipStream.Close(); |
using (var fileZipStream = |
new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) |
{ |
dataMemoryStream.Position = 0L; |
await dataMemoryStream.CopyToAsync(fileZipStream); |
fileZipStream.Close(); |
|
fileMemoryStream.Position = 0L; |
fileMemoryStream.Position = 0L; |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateFileSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateFileSql, sqliteConnection, |
dbTransaction)) |
{ |
new SQLiteParameter("@dataLength", fileMemoryStream.Length), |
new SQLiteParameter("@recomputedHash", hashHex), |
new SQLiteParameter("@hash", hash) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@dataLength", fileMemoryStream.Length), |
new SQLiteParameter("@recomputedHash", hashHex), |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
sqliteCommand.Prepare(); |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
|
using (var sqliteCommand = |
new SQLiteCommand(GetRowFromHashSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
using (var sqliteCommand = |
new SQLiteCommand(GetRowFromHashSql, sqliteConnection, |
dbTransaction)) |
{ |
new SQLiteParameter("@hash", hashHex) |
}); |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hashHex) |
}); |
|
sqliteCommand.Prepare(); |
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = |
await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
using (var sqlDataReader = |
await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
if (sqlDataReader["id"] is long rowId) |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
using (var sqliteBlob = SQLiteBlob.Create(sqliteConnection, |
"main", |
"Snapshots", |
"Data", |
rowId, false)) |
if (sqlDataReader["id"] is long rowId) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
using (var sqliteBlob = SQLiteBlob.Create( |
sqliteConnection, |
"main", |
"Snapshots", |
"Data", |
rowId, false)) |
{ |
var fileMemoryStreamData = |
fileMemoryStream.ToArray(); |
|
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
} |
} |
} |
} |
} |
} |
|
dbTransaction.Commit(); |
dbTransaction.Commit(); |
|
SnapshotDataUpdate?.Invoke(this, |
new SnapshotDataUpdateSuccessEventArgs(hash, hashHex)); |
SnapshotDataUpdate?.Invoke(this, |
new SnapshotDataUpdateSuccessEventArgs(hash, hashHex)); |
|
return hashHex; |
return hashHex; |
} |
} |
} |
} |
} |
} |
catch |
{ |
dbTransaction.Rollback(); |
catch |
{ |
dbTransaction.Rollback(); |
|
SnapshotDataUpdate?.Invoke(this, new SnapshotDataUpdateFailureEventArgs(hash)); |
SnapshotDataUpdate?.Invoke(this, new SnapshotDataUpdateFailureEventArgs(hash)); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task UpdateHash(string from, string to, CancellationToken cancellationToken) |
public async Task UpdateHashAsync(string from, string to, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateHashFromHashSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateHashFromHashSql, sqliteConnection, dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
@@ -1423,19 +1750,26 @@ |
|
sqliteCommand.Prepare(); |
|
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
#endregion |
@@ -1442,59 +1776,67 @@ |
|
#region Private Methods |
|
private static async Task SetAutoVacuum(CancellationToken cancellationToken) |
private async Task SetAutoVacuum(CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = |
new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
// Set auto vacuum. |
using (var sqliteCommand = new SQLiteCommand(SetAutoVacuumSql, sqliteConnection)) |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
// Set auto vacuum. |
using (var sqliteCommand = new SQLiteCommand(SetAutoVacuumSql, sqliteConnection)) |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
private static async Task CreateDatabase(CancellationToken cancellationToken) |
private async Task CreateDatabase(CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
ConnectionString = DatabaseConnectionString |
}; |
using (var sqliteConnection = new SQLiteConnection(_sqliteConnectionStringBuilder.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
|
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
// Create the table if it does not exist. |
using (var sqliteCommand = new SQLiteCommand(CreateTableSql, sqliteConnection, dbTransaction)) |
using (var dbTransaction = sqliteConnection.BeginTransaction()) |
{ |
try |
// Create the table if it does not exist. |
using (var sqliteCommand = new SQLiteCommand(CreateTableSql, sqliteConnection, dbTransaction)) |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
dbTransaction.Commit(); |
} |
catch |
{ |
dbTransaction.Rollback(); |
|
throw; |
throw; |
} |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
#endregion |
|
|
} |
} |