/Horizon/Database/SnapshotDatabase.cs |
@@ -6,6 +6,7 @@ |
using System.Globalization; |
using System.IO; |
using System.IO.Compression; |
using System.Runtime.CompilerServices; |
using System.Security.Cryptography; |
using System.Threading; |
using System.Threading.Tasks; |
@@ -96,21 +97,28 @@ |
#region Private Delegates, Events, Enums, Properties, Indexers and Fields |
|
private readonly CancellationTokenSource _cancellationTokenSource; |
private readonly SemaphoreSlim _databaseLock; |
|
private SemaphoreSlim _snapshotSemaphore; |
|
#endregion |
|
#region Constructors, Destructors and Finalizers |
|
public SnapshotDatabase() |
private SnapshotDatabase() |
{ |
Directory.CreateDirectory(Constants.DatabaseDirectory); |
|
_databaseLock = new SemaphoreSlim(1, 1); |
} |
|
public SnapshotDatabase(CancellationToken cancellationToken) : this() |
{ |
_cancellationTokenSource = new CancellationTokenSource(); |
_cancellationToken = _cancellationTokenSource.Token; |
var localCancellationToken = _cancellationTokenSource.Token; |
var combinedCancellationTokenSource = |
CancellationTokenSource.CreateLinkedTokenSource(localCancellationToken, cancellationToken); |
_cancellationToken = combinedCancellationTokenSource.Token; |
|
_snapshotSemaphore = new SemaphoreSlim(1, 1); |
|
Directory.CreateDirectory(Constants.DatabaseDirectory); |
|
CreateDatabase(_cancellationToken).ContinueWith(async createDatabaseTask => |
{ |
@@ -137,9 +145,6 @@ |
public void Dispose() |
{ |
_cancellationTokenSource.Cancel(); |
|
_snapshotSemaphore?.Dispose(); |
_snapshotSemaphore = null; |
} |
|
#endregion |
@@ -153,6 +158,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -163,8 +171,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(RemoveScreenshotFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
@@ -172,6 +178,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -186,6 +194,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task NormalizeTime(string hash, CancellationToken cancellationToken) |
{ |
@@ -194,6 +207,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
@@ -237,7 +253,8 @@ |
{ |
writeSQLiteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@time", dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff")), |
new SQLiteParameter("@time", |
dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff")), |
new SQLiteParameter("@hash", hash) |
}); |
|
@@ -260,6 +277,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<long> CountSnapshots(CancellationToken cancellationToken) |
{ |
@@ -268,6 +290,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -297,8 +322,13 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<IEnumerable<Snapshot>> LoadSnapshots(CancellationToken cancellationToken) |
public async IAsyncEnumerable<Snapshot> LoadSnapshots([EnumeratorCancellation] CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
@@ -305,6 +335,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
@@ -317,7 +350,7 @@ |
|
using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) |
{ |
var snapshots = new List<Snapshot>(); |
//var snapshots = new List<Snapshot>(); |
while (await sqlDataReader.ReadAsync(cancellationToken)) |
{ |
var name = (string)sqlDataReader["Name"]; |
@@ -342,24 +375,28 @@ |
} |
} |
|
snapshots.Add(new Snapshot(name, path, time, hash, color)); |
yield return new Snapshot(name, path, time, hash, color); |
} |
|
return snapshots; |
} |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task CreateSnapshot(string name, string path, Color color, CancellationToken cancellationToken) |
{ |
await _snapshotSemaphore.WaitAsync(cancellationToken); |
|
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
@@ -443,13 +480,15 @@ |
(long)await sqliteCommand.ExecuteScalarAsync(cancellationToken); |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", "Data", |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", |
"Data", |
rowId, |
false)) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
|
sqliteBlob.Write(fileMemoryStreamData, fileMemoryStreamData.Length, |
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
0); |
} |
} |
@@ -481,28 +520,31 @@ |
{ |
dbTransaction.Rollback(); |
|
SnapshotCreate?.Invoke(this, new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
SnapshotCreate?.Invoke(this, |
new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
|
throw; |
} |
} |
} |
} |
finally |
{ |
_snapshotSemaphore.Release(); |
_databaseLock.Release(); |
} |
} |
} |
} |
|
public async Task CreateSnapshot(string name, string path, |
Bitmap shot, Color color, CancellationToken cancellationToken) |
{ |
await _snapshotSemaphore.WaitAsync(cancellationToken); |
|
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
@@ -599,7 +641,8 @@ |
cancellationToken); |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", |
SQLiteBlob.Create(sqliteConnection, "main", |
"Snapshots", |
"Data", |
rowId, |
false)) |
@@ -612,12 +655,14 @@ |
} |
|
using (var sqliteBlob = |
SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", |
SQLiteBlob.Create(sqliteConnection, "main", |
"Snapshots", |
"Shot", |
rowId, |
false)) |
{ |
var bitmapMemoryStreamData = bitmapMemoryStream.ToArray(); |
var bitmapMemoryStreamData = |
bitmapMemoryStream.ToArray(); |
|
sqliteBlob.Write(bitmapMemoryStreamData, |
bitmapMemoryStreamData.Length, |
@@ -654,17 +699,19 @@ |
{ |
dbTransaction.Rollback(); |
|
SnapshotCreate?.Invoke(this, new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
SnapshotCreate?.Invoke(this, |
new SnapshotCreateFailureEventArgs(name, path, color, exception)); |
|
throw; |
} |
} |
} |
} |
finally |
{ |
_snapshotSemaphore.Release(); |
_databaseLock.Release(); |
} |
} |
} |
} |
|
public async Task SaveFile(string path, string hash, CancellationToken cancellationToken) |
{ |
@@ -673,6 +720,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -720,16 +770,22 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RevertFile(string name, string hash, CancellationToken cancellationToken, bool atomic = true) |
{ |
await _snapshotSemaphore.WaitAsync(cancellationToken); |
|
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -836,13 +892,14 @@ |
|
throw; |
} |
} |
} |
} |
finally |
{ |
_snapshotSemaphore.Release(); |
_databaseLock.Release(); |
} |
} |
} |
} |
|
public async Task RemoveFileFast(IEnumerable<string> hashes, CancellationToken cancellationToken) |
{ |
@@ -851,6 +908,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -893,6 +953,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RemoveFile(string hash, CancellationToken cancellationToken) |
{ |
@@ -900,7 +965,9 @@ |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -911,8 +978,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
@@ -920,6 +985,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -934,6 +1001,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task UpdateColor(string hash, Color color, CancellationToken cancellationToken) |
{ |
@@ -942,6 +1014,10 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
|
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -952,8 +1028,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(UpdateColorFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash), |
@@ -962,6 +1036,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -976,6 +1052,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RemoveColor(string hash, CancellationToken cancellationToken) |
{ |
@@ -984,6 +1065,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -994,8 +1078,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(RemoveColorFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
@@ -1003,6 +1085,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -1017,6 +1101,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<SnapshotPreview> RetrievePreview(string hash, CancellationToken cancellationToken) |
{ |
@@ -1025,6 +1114,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1075,69 +1167,12 @@ |
} |
} |
} |
|
/* |
public MemoryStream RetrieveFileStream(string hash, CancellationToken cancellationToken) |
finally |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
|
sqliteConnection.Open(); |
|
// Insert the file change. |
using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash) |
}); |
|
sqliteCommand.Prepare(); |
|
using (var sqlDataReader = sqliteCommand.ExecuteReader()) |
{ |
|
while (sqlDataReader.Read()) |
{ |
using (var readStream = sqlDataReader.GetStream(1)) |
{ |
|
using (var memoryStream = new MemoryStream()) |
{ |
|
readStream.Position = 0L; |
|
readStream.CopyTo(memoryStream); |
|
memoryStream.Position = 0L; |
|
using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) |
{ |
|
var outputStream = new MemoryStream(); |
|
zipStream.CopyTo(outputStream); |
|
outputStream.Position = 0L; |
|
return outputStream; |
_databaseLock.Release(); |
} |
} |
} |
} |
|
return null; |
} |
} |
} |
} |
*/ |
|
public async Task<MemoryStream> RetrieveFileStream(string hash, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
@@ -1145,6 +1180,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1193,6 +1231,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task RelocateFile(string hash, string path, CancellationToken cancellationToken) |
{ |
@@ -1201,6 +1244,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1211,8 +1257,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(RelocateFileFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash), |
@@ -1221,6 +1265,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -1236,6 +1282,12 @@ |
} |
} |
|
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task UpdateNote(string hash, string note, CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
@@ -1243,6 +1295,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1253,8 +1308,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(UpdateNoteFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@hash", hash), |
@@ -1263,6 +1316,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -1281,16 +1336,24 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task<string> UpdateFile(string hash, byte[] data, CancellationToken cancellationToken) |
{ |
using (var dataMemoryStream = new MemoryStream(data)) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var dataMemoryStream = new MemoryStream(data)) |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1324,7 +1387,8 @@ |
|
// Insert the file change. |
using (var sqliteCommand = |
new SQLiteCommand(UpdateFileSql, sqliteConnection, dbTransaction)) |
new SQLiteCommand(UpdateFileSql, sqliteConnection, |
dbTransaction)) |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
@@ -1355,13 +1419,15 @@ |
{ |
if (sqlDataReader["id"] is long rowId) |
{ |
using (var sqliteBlob = SQLiteBlob.Create(sqliteConnection, |
using (var sqliteBlob = SQLiteBlob.Create( |
sqliteConnection, |
"main", |
"Snapshots", |
"Data", |
rowId, false)) |
{ |
var fileMemoryStreamData = fileMemoryStream.ToArray(); |
var fileMemoryStreamData = |
fileMemoryStream.ToArray(); |
|
sqliteBlob.Write(fileMemoryStreamData, |
fileMemoryStreamData.Length, |
@@ -1395,6 +1461,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
public async Task UpdateHash(string from, string to, CancellationToken cancellationToken) |
{ |
@@ -1403,6 +1474,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1413,8 +1487,6 @@ |
using (var sqliteCommand = |
new SQLiteCommand(UpdateHashFromHashSql, sqliteConnection, dbTransaction)) |
{ |
try |
{ |
sqliteCommand.Parameters.AddRange(new[] |
{ |
new SQLiteParameter("@from", from), |
@@ -1423,6 +1495,8 @@ |
|
sqliteCommand.Prepare(); |
|
try |
{ |
await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); |
|
dbTransaction.Commit(); |
@@ -1437,12 +1511,17 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
#endregion |
|
#region Private Methods |
|
private static async Task SetAutoVacuum(CancellationToken cancellationToken) |
private async Task SetAutoVacuum(CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
@@ -1449,6 +1528,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = |
new SQLiteConnection(connectionString.ConnectionString)) |
{ |
@@ -1461,8 +1543,13 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
private static async Task CreateDatabase(CancellationToken cancellationToken) |
private async Task CreateDatabase(CancellationToken cancellationToken) |
{ |
var connectionString = new SQLiteConnectionStringBuilder |
{ |
@@ -1469,6 +1556,9 @@ |
ConnectionString = DatabaseConnectionString |
}; |
|
await _databaseLock.WaitAsync(cancellationToken); |
try |
{ |
using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) |
{ |
await sqliteConnection.OpenAsync(cancellationToken); |
@@ -1494,6 +1584,11 @@ |
} |
} |
} |
finally |
{ |
_databaseLock.Release(); |
} |
} |
|
#endregion |
} |
/Horizon/Snapshots/SnapshotManagerForm.cs |
@@ -14,6 +14,7 @@ |
using Horizon.Database; |
using Horizon.Utilities; |
using Microsoft.WindowsAPICodePack.Dialogs; |
using Org.BouncyCastle.Crypto; |
using Serilog; |
|
namespace Horizon.Snapshots |
@@ -58,7 +59,7 @@ |
|
#region Constructors, Destructors and Finalizers |
|
public SnapshotManagerForm() |
private SnapshotManagerForm() |
{ |
InitializeComponent(); |
Utilities.WindowState.FormTracker.Track(this); |
@@ -592,21 +593,21 @@ |
toolStripProgressBar1.Maximum = (int)await _snapshotDatabase.CountSnapshots(_cancellationToken); |
|
var snapshotQueue = new ConcurrentQueue<Snapshot>(); |
var snapshotsQueuedTaskCompletionSource = new TaskCompletionSource<object>(); |
|
async void IdleHandler(object idleHandlerSender, EventArgs idleHandlerArgs) |
void IdleHandler(object idleHandlerSender, EventArgs idleHandlerArgs) |
{ |
await snapshotsQueuedTaskCompletionSource.Task; |
|
try |
{ |
if (!snapshotQueue.TryDequeue(out var snapshot)) |
if (snapshotQueue.IsEmpty) |
{ |
Application.Idle -= IdleHandler; |
|
dataGridView1.Sort(dataGridView1.Columns["TimeColumn"], ListSortDirection.Descending); |
toolStripStatusLabel1.Text = "Done."; |
} |
|
if (!snapshotQueue.TryDequeue(out var snapshot)) |
{ |
return; |
} |
|
@@ -630,15 +631,14 @@ |
} |
} |
|
Application.Idle += IdleHandler; |
try |
{ |
foreach (var snapshot in await _snapshotDatabase.LoadSnapshots(_cancellationToken)) |
await foreach (var snapshot in _snapshotDatabase.LoadSnapshots(_cancellationToken).WithCancellation(_cancellationToken)) |
{ |
snapshotQueue.Enqueue(snapshot); |
} |
|
snapshotsQueuedTaskCompletionSource.TrySetResult(new { }); |
Application.Idle += IdleHandler; |
} |
catch (Exception exception) |
{ |
@@ -676,6 +676,56 @@ |
e.Effect = DragDropEffects.None; |
} |
|
private async Task CreateSnapshots(IReadOnlyList<string> files, Bitmap screenCapture, TrackedFolders.TrackedFolders trackedFolders, IProgress<CreateSnapshotProgress> progress, CancellationToken cancellationToken) |
{ |
Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 512 }, async file => |
{ |
var color = Color.Empty; |
if (_mainForm.TrackedFolders.TryGet(file, out var folder)) |
{ |
color = folder.Color; |
} |
|
var fileInfo = File.GetAttributes(file); |
if (fileInfo.HasFlag(FileAttributes.Directory)) |
{ |
foreach (var directoryFile in Directory.GetFiles(file, "*.*", SearchOption.AllDirectories)) |
{ |
var name = Path.GetFileName(directoryFile); |
var path = Path.Combine(Path.GetDirectoryName(directoryFile), name); |
|
try |
{ |
await _snapshotDatabase.CreateSnapshot(name, path, screenCapture, color, |
_cancellationToken); |
|
progress.Report(new CreateSnapshotProgressSuccess(file)); |
} |
catch (Exception exception) |
{ |
progress.Report(new CreateSnapshotProgressFailure(file, exception)); |
} |
} |
|
return; |
} |
|
var fileName = Path.GetFileName(file); |
var pathName = Path.Combine(Path.GetDirectoryName(file), fileName); |
|
try |
{ |
await _snapshotDatabase.CreateSnapshot(fileName, pathName, screenCapture, color, |
_cancellationToken); |
|
progress.Report(new CreateSnapshotProgressSuccess(file)); |
} |
catch (Exception exception) |
{ |
progress.Report(new CreateSnapshotProgressFailure(file, exception)); |
} |
}); |
} |
private async void DataGridView1_DragDrop(object sender, DragEventArgs e) |
{ |
if (!e.Data.GetDataPresent(DataFormats.FileDrop)) |
@@ -690,17 +740,49 @@ |
toolStripStatusLabel1.Text = "Snapshotting files..."; |
|
var screenCapture = ScreenCapture.Capture((CaptureMode)_mainForm.Configuration.CaptureMode); |
for (var i = 0; i < files.Length; ++i) |
|
var progress = new Progress<CreateSnapshotProgress>(createSnapshotProgress => |
{ |
switch (createSnapshotProgress) |
{ |
case CreateSnapshotProgressSuccess createSnapshotProgressSuccess: |
toolStripStatusLabel1.Text = $"Snapshot taken of {createSnapshotProgressSuccess.File}."; |
break; |
case CreateSnapshotProgressFailure createSnapshotProgressFailure: |
if (createSnapshotProgressFailure.Exception is SQLiteException { ResultCode: SQLiteErrorCode.Constraint }) |
{ |
toolStripStatusLabel1.Text = $"Snapshot of file {createSnapshotProgressFailure.File} already exists."; |
break; |
} |
|
toolStripStatusLabel1.Text = $"Could not snapshot file {createSnapshotProgressFailure.File}"; |
Log.Warning(createSnapshotProgressFailure.Exception, $"Could not snapshot file {createSnapshotProgressFailure.File}"); |
break; |
} |
|
toolStripProgressBar1.Increment(1); |
statusStrip1.Update(); |
}); |
|
await Task.Factory.StartNew(async () => |
{ |
await CreateSnapshots(files, screenCapture, _mainForm.TrackedFolders, progress, _cancellationToken); |
}, _cancellationToken); |
|
/* |
|
foreach (var file in files) |
{ |
var color = Color.Empty; |
if (_mainForm.TrackedFolders.TryGet(files[i], out var folder)) |
if (_mainForm.TrackedFolders.TryGet(file, out var folder)) |
{ |
color = folder.Color; |
} |
|
if (Directory.Exists(files[i])) |
var fileInfo = File.GetAttributes(file); |
if (fileInfo.HasFlag(FileAttributes.Directory)) |
{ |
foreach (var directoryFile in Directory.GetFiles(files[i], "*.*", SearchOption.AllDirectories)) |
foreach (var directoryFile in Directory.GetFiles(file, "*.*", SearchOption.AllDirectories)) |
{ |
var name = Path.GetFileName(directoryFile); |
var path = Path.Combine(Path.GetDirectoryName(directoryFile), name); |
@@ -710,8 +792,9 @@ |
await _snapshotDatabase.CreateSnapshot(name, path, screenCapture, color, |
_cancellationToken); |
|
toolStripProgressBar1.Value = i + 1; |
toolStripStatusLabel1.Text = $"Snapshot taken of {files[i]}."; |
|
toolStripStatusLabel1.Text = $"Snapshot taken of {file}."; |
toolStripProgressBar1.Increment(1); |
statusStrip1.Update(); |
} |
catch (SQLiteException exception) |
@@ -720,8 +803,8 @@ |
{ |
Log.Information(exception, "Snapshot already exists."); |
|
toolStripProgressBar1.Value = i + 1; |
toolStripStatusLabel1.Text = "Snapshot already exists."; |
toolStripProgressBar1.Increment(1); |
statusStrip1.Update(); |
} |
} |
@@ -734,8 +817,8 @@ |
continue; |
} |
|
var fileName = Path.GetFileName(files[i]); |
var pathName = Path.Combine(Path.GetDirectoryName(files[i]), fileName); |
var fileName = Path.GetFileName(file); |
var pathName = Path.Combine(Path.GetDirectoryName(file), fileName); |
|
try |
{ |
@@ -742,8 +825,8 @@ |
await _snapshotDatabase.CreateSnapshot(fileName, pathName, screenCapture, color, |
_cancellationToken); |
|
toolStripProgressBar1.Value = i + 1; |
toolStripStatusLabel1.Text = $"Snapshot taken of {files[i]}."; |
toolStripStatusLabel1.Text = $"Snapshot taken of {file}."; |
toolStripProgressBar1.Increment(1); |
statusStrip1.Update(); |
} |
catch (SQLiteException exception) |
@@ -752,8 +835,8 @@ |
{ |
Log.Information(exception, "Snapshot already exists."); |
|
toolStripProgressBar1.Value = i + 1; |
toolStripStatusLabel1.Text = "Snapshot already exists."; |
toolStripProgressBar1.Increment(1); |
statusStrip1.Update(); |
} |
} |
@@ -762,6 +845,7 @@ |
Log.Warning(exception, "Could not create snapshot"); |
} |
} |
*/ |
} |
|
private async void FileToolStripMenuItem_Click(object sender, EventArgs e) |