Horizon – Diff between revs 3 and 5

Subversion Repositories:
Rev:
Show entire fileIgnore whitespace
Rev 3 Rev 5
Line 4... Line 4...
4 using System.Drawing; 4 using System.Drawing;
5 using System.Drawing.Imaging; 5 using System.Drawing.Imaging;
6 using System.Globalization; 6 using System.Globalization;
7 using System.IO; 7 using System.IO;
8 using System.IO.Compression; 8 using System.IO.Compression;
-   9 using System.Runtime.CompilerServices;
9 using System.Security.Cryptography; 10 using System.Security.Cryptography;
10 using System.Threading; 11 using System.Threading;
11 using System.Threading.Tasks; 12 using System.Threading.Tasks;
12 using Horizon.Snapshots; 13 using Horizon.Snapshots;
13 using Horizon.Utilities; 14 using Horizon.Utilities;
Line 94... Line 95...
94 #endregion 95 #endregion
Line 95... Line 96...
95   96  
Line 96... Line 97...
96 #region Private Delegates, Events, Enums, Properties, Indexers and Fields 97 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
97   -  
98 private readonly CancellationTokenSource _cancellationTokenSource; 98  
Line 99... Line 99...
99   99 private readonly CancellationTokenSource _cancellationTokenSource;
Line 100... Line 100...
100 private SemaphoreSlim _snapshotSemaphore; 100 private readonly SemaphoreSlim _databaseLock;
Line 101... Line 101...
101   101  
102 #endregion 102 #endregion
103   -  
104 #region Constructors, Destructors and Finalizers 103  
Line 105... Line 104...
105   104 #region Constructors, Destructors and Finalizers
-   105  
Line -... Line 106...
-   106 private SnapshotDatabase()
-   107 {
-   108 Directory.CreateDirectory(Constants.DatabaseDirectory);
106 public SnapshotDatabase() 109  
-   110 _databaseLock = new SemaphoreSlim(1, 1);
-   111 }
-   112  
-   113 public SnapshotDatabase(CancellationToken cancellationToken) : this()
-   114 {
Line 107... Line 115...
107 { 115 _cancellationTokenSource = new CancellationTokenSource();
108 _cancellationTokenSource = new CancellationTokenSource(); 116 var localCancellationToken = _cancellationTokenSource.Token;
109 _cancellationToken = _cancellationTokenSource.Token; 117 var combinedCancellationTokenSource =
110   118 CancellationTokenSource.CreateLinkedTokenSource(localCancellationToken, cancellationToken);
Line 135... Line 143...
135 } 143 }
Line 136... Line 144...
136   144  
137 public void Dispose() 145 public void Dispose()
138 { 146 {
139 _cancellationTokenSource.Cancel(); -  
140   -  
141 _snapshotSemaphore?.Dispose(); -  
142 _snapshotSemaphore = null; 147 _cancellationTokenSource.Cancel();
Line 143... Line 148...
143 } 148 }
Line 144... Line 149...
144   149  
Line 151... Line 156...
151 var connectionString = new SQLiteConnectionStringBuilder 156 var connectionString = new SQLiteConnectionStringBuilder
152 { 157 {
153 ConnectionString = DatabaseConnectionString 158 ConnectionString = DatabaseConnectionString
154 }; 159 };
Line 155... Line 160...
155   160  
-   161 await _databaseLock.WaitAsync(cancellationToken);
156 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 162 try
157 { -  
158 await sqliteConnection.OpenAsync(cancellationToken); -  
159   163 {
160 using (var dbTransaction = sqliteConnection.BeginTransaction()) 164 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
161 { 165 {
162 // Insert the file change. -  
-   166 await sqliteConnection.OpenAsync(cancellationToken);
163 using (var sqliteCommand = 167  
164 new SQLiteCommand(RemoveScreenshotFromHashSql, sqliteConnection, dbTransaction)) 168 using (var dbTransaction = sqliteConnection.BeginTransaction())
-   169 {
165 { 170 // Insert the file change.
-   171 using (var sqliteCommand =
166 try 172 new SQLiteCommand(RemoveScreenshotFromHashSql, sqliteConnection, dbTransaction))
167 { 173 {
168 sqliteCommand.Parameters.AddRange(new[] 174 sqliteCommand.Parameters.AddRange(new[]
169 { 175 {
170 new SQLiteParameter("@hash", hash) 176 new SQLiteParameter("@hash", hash)
Line 171... Line 177...
171 }); 177 });
Line -... Line 178...
-   178  
-   179 sqliteCommand.Prepare();
172   180  
Line 173... Line 181...
173 sqliteCommand.Prepare(); 181 try
174   182 {
175 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); 183 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
176   184  
177 dbTransaction.Commit(); 185 dbTransaction.Commit();
Line 178... Line 186...
178 } 186 }
-   187 catch
179 catch 188 {
180 { 189 dbTransaction.Rollback();
181 dbTransaction.Rollback(); 190  
182   191 throw;
-   192 }
-   193 }
-   194 }
-   195 }
183 throw; 196 }
Line 184... Line 197...
184 } 197 finally
185 } 198 {
186 } 199 _databaseLock.Release();
187 } 200 }
188 } 201 }
189   202  
Line 190... Line 203...
190 public async Task NormalizeTime(string hash, CancellationToken cancellationToken) 203 public async Task NormalizeTime(string hash, CancellationToken cancellationToken)
191 { 204 {
192 var connectionString = new SQLiteConnectionStringBuilder 205 var connectionString = new SQLiteConnectionStringBuilder
193 { 206 {
194 ConnectionString = DatabaseConnectionString -  
195 }; 207 ConnectionString = DatabaseConnectionString
196   208 };
197 using (var sqliteConnection = 209  
-   210 await _databaseLock.WaitAsync(cancellationToken);
-   211 try
198 new SQLiteConnection(connectionString.ConnectionString)) 212 {
-   213 using (var sqliteConnection =
-   214 new SQLiteConnection(connectionString.ConnectionString))
199 { 215 {
200 await sqliteConnection.OpenAsync(cancellationToken); 216 await sqliteConnection.OpenAsync(cancellationToken);
Line 201... Line 217...
201   217  
Line 202... Line 218...
202 using (var readSQLiteCommand = new SQLiteCommand(RetrieveTimeFromHash, sqliteConnection)) 218 using (var readSQLiteCommand = new SQLiteCommand(RetrieveTimeFromHash, sqliteConnection))
203 { -  
204 readSQLiteCommand.Parameters.AddRange(new[] -  
205 { 219 {
206 new SQLiteParameter("@hash", hash) 220 readSQLiteCommand.Parameters.AddRange(new[]
207 }); 221 {
208   222 new SQLiteParameter("@hash", hash)
209 readSQLiteCommand.Prepare(); 223 });
210   224  
211 using (var sqlDataReader = await readSQLiteCommand.ExecuteReaderAsync(cancellationToken)) -  
212 { -  
213 using (var dbTransaction = sqliteConnection.BeginTransaction()) -  
214 { -  
215 try -  
216 { -  
217 while (await sqlDataReader.ReadAsync(cancellationToken)) 225 readSQLiteCommand.Prepare();
218 { 226  
219 var time = (string)sqlDataReader["Time"]; -  
Line -... Line 227...
-   227 using (var sqlDataReader = await readSQLiteCommand.ExecuteReaderAsync(cancellationToken))
220   228 {
-   229 using (var dbTransaction = sqliteConnection.BeginTransaction())
-   230 {
-   231 try
221 // Skip if already ISO 8601 232 {
222 if (DateTime.TryParseExact(time, 233 while (await sqlDataReader.ReadAsync(cancellationToken))
223 "yyyy-MM-ddTHH:mm:ss.fff", 234 {
Line 224... Line -...
224 CultureInfo.InvariantCulture, -  
225 DateTimeStyles.None, out _)) -  
226 { -  
227 continue; 235 var time = (string)sqlDataReader["Time"];
228 } 236  
229   -  
230 if (!DateTime.TryParse(time, out var dateTime)) 237 // Skip if already ISO 8601
231 { 238 if (DateTime.TryParseExact(time,
Line -... Line 239...
-   239 "yyyy-MM-ddTHH:mm:ss.fff",
-   240 CultureInfo.InvariantCulture,
-   241 DateTimeStyles.None, out _))
232 dateTime = DateTime.Now; 242 {
-   243 continue;
-   244 }
-   245  
-   246 if (!DateTime.TryParse(time, out var dateTime))
-   247 {
Line -... Line 248...
-   248 dateTime = DateTime.Now;
-   249 }
233 } 250  
-   251 using (var writeSQLiteCommand =
234   252 new SQLiteCommand(UpdateTimeFromHash, sqliteConnection, dbTransaction))
235 using (var writeSQLiteCommand = -  
Line 236... Line 253...
236 new SQLiteCommand(UpdateTimeFromHash, sqliteConnection, dbTransaction)) 253 {
237 { 254 writeSQLiteCommand.Parameters.AddRange(new[]
238 writeSQLiteCommand.Parameters.AddRange(new[] 255 {
239 { 256 new SQLiteParameter("@time",
240 new SQLiteParameter("@time", dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff")), 257 dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff")),
Line 241... Line 258...
241 new SQLiteParameter("@hash", hash) 258 new SQLiteParameter("@hash", hash)
-   259 });
242 }); 260  
243   261 writeSQLiteCommand.Prepare();
244 writeSQLiteCommand.Prepare(); 262  
245   263 await writeSQLiteCommand.ExecuteNonQueryAsync(cancellationToken);
246 await writeSQLiteCommand.ExecuteNonQueryAsync(cancellationToken); 264 }
-   265 }
-   266  
-   267 dbTransaction.Commit();
-   268 }
247 } 269 catch
Line 248... Line 270...
248 } 270 {
249   271 dbTransaction.Rollback();
250 dbTransaction.Commit(); 272  
251 } 273 throw;
252 catch 274 }
253 { 275 }
Line 254... Line 276...
254 dbTransaction.Rollback(); 276 }
-   277 }
255   278 }
256 throw; -  
257 } -  
258 } -  
259 } 279 }
260 } 280 finally
261 } -  
262 } -  
263   281 {
Line -... Line 282...
-   282 _databaseLock.Release();
264 public async Task<long> CountSnapshots(CancellationToken cancellationToken) 283 }
265 { 284 }
-   285  
-   286 public async Task<long> CountSnapshots(CancellationToken cancellationToken)
-   287 {
-   288 var connectionString = new SQLiteConnectionStringBuilder
266 var connectionString = new SQLiteConnectionStringBuilder 289 {
267 { 290 ConnectionString = DatabaseConnectionString
268 ConnectionString = DatabaseConnectionString 291 };
269 }; 292  
-   293 await _databaseLock.WaitAsync(cancellationToken);
-   294 try
270   295 {
271 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 296 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
-   297 {
-   298 await sqliteConnection.OpenAsync(cancellationToken);
-   299  
272 { 300 // Insert the file change.
Line 273... Line 301...
273 await sqliteConnection.OpenAsync(cancellationToken); 301 using (var sqliteCommand = new SQLiteCommand(CountSnapshotsSql, sqliteConnection))
274   302 {
275 // Insert the file change. -  
276 using (var sqliteCommand = new SQLiteCommand(CountSnapshotsSql, sqliteConnection)) -  
277 { 303 long count = 0;
278 long count = 0; 304  
279   305 sqliteCommand.Prepare();
-   306  
-   307 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken))
-   308 {
-   309 while (await sqlDataReader.ReadAsync(cancellationToken))
280 sqliteCommand.Prepare(); 310 {
Line 281... Line 311...
281   311 if (!(sqlDataReader[0] is long dbCount))
282 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) 312 {
283 { 313 count = -1;
284 while (await sqlDataReader.ReadAsync(cancellationToken)) 314 break;
285 { 315 }
286 if (!(sqlDataReader[0] is long dbCount)) 316  
Line 287... Line 317...
287 { 317 count = dbCount;
288 count = -1; 318 }
289 break; 319  
290 } -  
291   -  
292 count = dbCount; 320 return count;
293 } 321 }
294   322 }
295 return count; 323 }
Line -... Line 324...
-   324 }
296 } 325 finally
297 } 326 {
298 } -  
299 } -  
300   -  
301 public async Task<IEnumerable<Snapshot>> LoadSnapshots(CancellationToken cancellationToken) -  
302 { -  
303 var connectionString = new SQLiteConnectionStringBuilder -  
304 { -  
305 ConnectionString = DatabaseConnectionString -  
306 }; 327 _databaseLock.Release();
Line -... Line 328...
-   328 }
-   329 }
-   330  
307   331 public async IAsyncEnumerable<Snapshot> LoadSnapshots([EnumeratorCancellation] CancellationToken cancellationToken)
308 using (var sqliteConnection = 332 {
-   333 var connectionString = new SQLiteConnectionStringBuilder
-   334 {
-   335 ConnectionString = DatabaseConnectionString
309 new SQLiteConnection(connectionString.ConnectionString)) 336 };
Line 310... Line 337...
310 { 337  
-   338 await _databaseLock.WaitAsync(cancellationToken);
-   339 try
311 await sqliteConnection.OpenAsync(cancellationToken); 340 {
-   341 using (var sqliteConnection =
-   342 new SQLiteConnection(connectionString.ConnectionString))
-   343 {
-   344 await sqliteConnection.OpenAsync(cancellationToken);
312   345  
313 // Insert the file change. 346 // Insert the file change.
314 using (var sqliteCommand = new SQLiteCommand(RetrieveSnapshotsSql, sqliteConnection)) 347 using (var sqliteCommand = new SQLiteCommand(RetrieveSnapshotsSql, sqliteConnection))
315 { 348 {
316 sqliteCommand.Prepare(); 349 sqliteCommand.Prepare();
317   350  
-   351 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken))
318 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) 352 {
319 { -  
Line 320... Line 353...
320 var snapshots = new List<Snapshot>(); 353 //var snapshots = new List<Snapshot>();
-   354 while (await sqlDataReader.ReadAsync(cancellationToken))
321 while (await sqlDataReader.ReadAsync(cancellationToken)) 355 {
322 { -  
323 var name = (string)sqlDataReader["Name"]; -  
324 var path = (string)sqlDataReader["Path"]; 356 var name = (string)sqlDataReader["Name"];
325 var time = (string)sqlDataReader["Time"]; 357 var path = (string)sqlDataReader["Path"];
326 var hash = (string)sqlDataReader["Hash"]; 358 var time = (string)sqlDataReader["Time"];
-   359 var hash = (string)sqlDataReader["Hash"];
-   360  
-   361 var color = Color.Empty;
-   362  
327   363 if (!(sqlDataReader["Color"] is DBNull))
Line 328... Line 364...
328 var color = Color.Empty; 364 {
329   365 var dbColor = Convert.ToInt32(sqlDataReader["Color"]);
330 if (!(sqlDataReader["Color"] is DBNull)) -  
331 { -  
332 var dbColor = Convert.ToInt32(sqlDataReader["Color"]); 366  
333   367 switch (dbColor)
334 switch (dbColor) 368 {
335 { 369 case 0:
Line 336... Line 370...
336 case 0: 370 color = Color.Empty;
337 color = Color.Empty; 371 break;
338 break; 372 default:
339 default: 373 color = Color.FromArgb(dbColor);
340 color = Color.FromArgb(dbColor); -  
341 break; 374 break;
342 } 375 }
343 } 376 }
-   377  
-   378 yield return new Snapshot(name, path, time, hash, color);
344   379 }
345 snapshots.Add(new Snapshot(name, path, time, hash, color)); 380 }
346 } 381 }
347   382 }
348 return snapshots; 383 }
349 } 384 finally
350 } -  
351 } -  
352 } -  
353   385 {
-   386 _databaseLock.Release();
-   387 }
-   388 }
-   389  
-   390 public async Task CreateSnapshot(string name, string path, Color color, CancellationToken cancellationToken)
354 public async Task CreateSnapshot(string name, string path, Color color, CancellationToken cancellationToken) 391 {
355 { 392 var connectionString = new SQLiteConnectionStringBuilder
Line 356... Line 393...
356 await _snapshotSemaphore.WaitAsync(cancellationToken); 393 {
357   394 ConnectionString = DatabaseConnectionString
358 var connectionString = new SQLiteConnectionStringBuilder 395 };
359 { 396  
Line 360... Line 397...
360 ConnectionString = DatabaseConnectionString 397 await _databaseLock.WaitAsync(cancellationToken);
361 }; -  
362   -  
363 using (var sqliteConnection = -  
364 new SQLiteConnection(connectionString.ConnectionString)) 398 try
365 { -  
366 await sqliteConnection.OpenAsync(cancellationToken); -  
367   -  
368 using (var dbTransaction = sqliteConnection.BeginTransaction()) -  
369 { -  
370 try -  
371 { -  
372 using (var md5 = MD5.Create()) -  
373 { -  
374 using (var hashMemoryStream = new MemoryStream()) 399 {
375 { 400 using (var sqliteConnection =
376 using (var fileStream = -  
377 await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read, 401 new SQLiteConnection(connectionString.ConnectionString))
-   402 {
-   403 await sqliteConnection.OpenAsync(cancellationToken);
-   404  
-   405 using (var dbTransaction = sqliteConnection.BeginTransaction())
-   406 {
-   407 try
378 FileShare.Read, 408 {
-   409 using (var md5 = MD5.Create())
-   410 {
-   411 using (var hashMemoryStream = new MemoryStream())
-   412 {
-   413 using (var fileStream =
379 cancellationToken)) 414 await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read,
-   415 FileShare.Read,
-   416 cancellationToken))
380 { 417 {
381 fileStream.Position = 0L; 418 fileStream.Position = 0L;
382 await fileStream.CopyToAsync(hashMemoryStream); 419 await fileStream.CopyToAsync(hashMemoryStream);
383   420  
384 hashMemoryStream.Position = 0L; 421 hashMemoryStream.Position = 0L;
385 var hash = md5.ComputeHash(hashMemoryStream); 422 var hash = md5.ComputeHash(hashMemoryStream);
386 var hashHex = BitConverter.ToString(hash).Replace("-", "") 423 var hashHex = BitConverter.ToString(hash).Replace("-", "")
Line 387... Line 424...
387 .ToLowerInvariant(); 424 .ToLowerInvariant();
388   425  
389 using (var fileMemoryStream = new MemoryStream()) 426 using (var fileMemoryStream = new MemoryStream())
390 { 427 {
391 using (var fileZipStream = 428 using (var fileZipStream =
392 new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) 429 new GZipStream(fileMemoryStream, CompressionMode.Compress, true))
393 { 430 {
394 fileStream.Position = 0L; 431 fileStream.Position = 0L;
395 await fileStream.CopyToAsync(fileZipStream); 432 await fileStream.CopyToAsync(fileZipStream);
396 fileZipStream.Close(); 433 fileZipStream.Close();
397   434  
398 var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff"); 435 var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff");
Line 399... Line 436...
399   436  
Line 400... Line 437...
400 fileMemoryStream.Position = 0L; 437 fileMemoryStream.Position = 0L;
401   438  
Line 402... Line 439...
402 // Insert the file change. 439 // Insert the file change.
403 using (var sqliteCommand = 440 using (var sqliteCommand =
404 new SQLiteCommand(SnapshotFileNoScreenshotSql, sqliteConnection, 441 new SQLiteCommand(SnapshotFileNoScreenshotSql, sqliteConnection,
405 dbTransaction)) 442 dbTransaction))
406 { 443 {
407 sqliteCommand.Parameters.AddRange(new[] 444 sqliteCommand.Parameters.AddRange(new[]
Line 408... Line 445...
408 { 445 {
409 new SQLiteParameter("@name", name), 446 new SQLiteParameter("@name", name),
Line 410... Line 447...
410 new SQLiteParameter("@time", time), 447 new SQLiteParameter("@time", time),
411 new SQLiteParameter("@path", path), 448 new SQLiteParameter("@path", path),
-   449 new SQLiteParameter("@dataLength",
412 new SQLiteParameter("@dataLength", 450 fileMemoryStream.Length),
413 fileMemoryStream.Length), 451 new SQLiteParameter("@hash", hashHex)
414 new SQLiteParameter("@hash", hashHex) 452 });
415 }); 453  
Line 416... Line 454...
416   454 var numeric = color.ToArgb();
-   455 switch (numeric)
417 var numeric = color.ToArgb(); 456 {
-   457 case 0:
418 switch (numeric) 458 sqliteCommand.Parameters.Add(
419 { -  
Line 420... Line 459...
420 case 0: 459 new SQLiteParameter("@color", null));
Line 421... Line 460...
421 sqliteCommand.Parameters.Add( 460 break;
422 new SQLiteParameter("@color", null)); 461 default:
423 break; 462 sqliteCommand.Parameters.Add(
-   463 new SQLiteParameter("@color", numeric));
424 default: 464 break;
425 sqliteCommand.Parameters.Add( 465 }
426 new SQLiteParameter("@color", numeric)); 466  
427 break; 467 sqliteCommand.Prepare();
428 } 468  
429   -  
430 sqliteCommand.Prepare(); 469 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
431   470 }
432 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); 471  
Line 433... Line 472...
433 } 472 // Insert the data blobs.
-   473 using (var sqliteCommand =
-   474 new SQLiteCommand(GetLastRowInsertSql, sqliteConnection,
-   475 dbTransaction))
-   476 {
-   477 sqliteCommand.Prepare();
-   478  
-   479 var rowId =
-   480 (long)await sqliteCommand.ExecuteScalarAsync(cancellationToken);
434   481  
-   482 using (var sqliteBlob =
-   483 SQLiteBlob.Create(sqliteConnection, "main", "Snapshots",
435 // Insert the data blobs. 484 "Data",
436 using (var sqliteCommand = 485 rowId,
437 new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, -  
438 dbTransaction)) -  
439 { -  
440 sqliteCommand.Prepare(); -  
441   -  
442 var rowId = -  
443 (long)await sqliteCommand.ExecuteScalarAsync(cancellationToken); -  
444   -  
445 using (var sqliteBlob = -  
Line 446... Line 486...
446 SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", "Data", 486 false))
447 rowId, 487 {
448 false)) -  
449 { -  
450 var fileMemoryStreamData = fileMemoryStream.ToArray(); -  
451   488 var fileMemoryStreamData = fileMemoryStream.ToArray();
452 sqliteBlob.Write(fileMemoryStreamData, fileMemoryStreamData.Length, 489  
453 0); 490 sqliteBlob.Write(fileMemoryStreamData,
-   491 fileMemoryStreamData.Length,
-   492 0);
-   493 }
-   494 }
454 } 495  
Line 455... Line 496...
455 } 496 dbTransaction.Commit();
456   497  
457 dbTransaction.Commit(); 498 SnapshotCreate?.Invoke(this,
458   -  
459 SnapshotCreate?.Invoke(this, -  
460 new SnapshotCreateSuccessEventArgs(name, time, path, color, 499 new SnapshotCreateSuccessEventArgs(name, time, path, color,
461 hashHex)); 500 hashHex));
462 } 501 }
463 } 502 }
Line 464... Line 503...
464 } 503 }
465 } 504 }
466 } 505 }
467 } 506 }
468 catch (SQLiteException exception) -  
469 { 507 catch (SQLiteException exception)
470 dbTransaction.Rollback(); 508 {
471   509 dbTransaction.Rollback();
-   510  
-   511 if (exception.ResultCode != SQLiteErrorCode.Constraint)
472 if (exception.ResultCode != SQLiteErrorCode.Constraint) 512 {
473 { 513 SnapshotCreate?.Invoke(this,
474 SnapshotCreate?.Invoke(this, 514 new SnapshotCreateFailureEventArgs(name, path, color, exception));
475 new SnapshotCreateFailureEventArgs(name, path, color, exception)); 515 }
476 } 516  
477   517 throw;
478 throw; -  
479 } -  
480 catch (Exception exception) -  
481 { 518 }
-   519 catch (Exception exception)
-   520 {
-   521 dbTransaction.Rollback();
-   522  
-   523 SnapshotCreate?.Invoke(this,
482 dbTransaction.Rollback(); 524 new SnapshotCreateFailureEventArgs(name, path, color, exception));
483   525  
Line 484... Line 526...
484 SnapshotCreate?.Invoke(this, new SnapshotCreateFailureEventArgs(name, path, color, exception)); 526 throw;
485   527 }
486 throw; 528 }
487 } 529 }
Line 488... Line 530...
488 finally 530 }
489 { -  
490 _snapshotSemaphore.Release(); -  
491 } -  
492 } 531 finally
493 } -  
494 } -  
495   532 {
496 public async Task CreateSnapshot(string name, string path, -  
497 Bitmap shot, Color color, CancellationToken cancellationToken) 533 _databaseLock.Release();
498 { 534 }
499 await _snapshotSemaphore.WaitAsync(cancellationToken); -  
500   -  
501 var connectionString = new SQLiteConnectionStringBuilder 535 }
502 { -  
503 ConnectionString = DatabaseConnectionString 536  
504 }; 537 public async Task CreateSnapshot(string name, string path,
Line -... Line 538...
-   538 Bitmap shot, Color color, CancellationToken cancellationToken)
-   539 {
-   540 var connectionString = new SQLiteConnectionStringBuilder
-   541 {
-   542 ConnectionString = DatabaseConnectionString
-   543 };
505   544  
-   545 await _databaseLock.WaitAsync(cancellationToken);
Line 506... Line -...
506 using (var sqliteConnection = -  
507 new SQLiteConnection(connectionString.ConnectionString)) 546 try
Line 508... Line -...
508 { -  
509 await sqliteConnection.OpenAsync(cancellationToken); -  
510   -  
511 using (var dbTransaction = sqliteConnection.BeginTransaction()) 547 {
512 { -  
513 try -  
514 { -  
515 using (var md5 = MD5.Create()) -  
516 { -  
517 using (var hashMemoryStream = new MemoryStream()) -  
518 { -  
519 using (var fileStream = 548 using (var sqliteConnection =
520 await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read, -  
521 FileShare.Read, -  
522 cancellationToken)) -  
523 { -  
Line 524... Line 549...
524 fileStream.Position = 0L; 549 new SQLiteConnection(connectionString.ConnectionString))
-   550 {
-   551 await sqliteConnection.OpenAsync(cancellationToken);
525 await fileStream.CopyToAsync(hashMemoryStream); 552  
526   553 using (var dbTransaction = sqliteConnection.BeginTransaction())
-   554 {
527 hashMemoryStream.Position = 0L; 555 try
528 var hash = md5.ComputeHash(hashMemoryStream); 556 {
529 var hashHex = BitConverter.ToString(hash).Replace("-", "") 557 using (var md5 = MD5.Create())
530 .ToLowerInvariant(); 558 {
531   559 using (var hashMemoryStream = new MemoryStream())
532 using (var fileMemoryStream = new MemoryStream()) 560 {
533 { 561 using (var fileStream =
534 using (var fileZipStream = 562 await Miscellaneous.GetFileStream(path, FileMode.Open, FileAccess.Read,
-   563 FileShare.Read,
535 new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) 564 cancellationToken))
Line -... Line 565...
-   565 {
-   566 fileStream.Position = 0L;
-   567 await fileStream.CopyToAsync(hashMemoryStream);
-   568  
-   569 hashMemoryStream.Position = 0L;
-   570 var hash = md5.ComputeHash(hashMemoryStream);
536 { 571 var hashHex = BitConverter.ToString(hash).Replace("-", "")
-   572 .ToLowerInvariant();
-   573  
-   574 using (var fileMemoryStream = new MemoryStream())
-   575 {
-   576 using (var fileZipStream =
Line 537... Line 577...
537 fileStream.Position = 0L; 577 new GZipStream(fileMemoryStream, CompressionMode.Compress, true))
538 await fileStream.CopyToAsync(fileZipStream); -  
Line 539... Line -...
539 fileZipStream.Close(); -  
540   -  
541 using (var bitmapMemoryStream = new MemoryStream()) 578 {
542 { -  
543 using (var bitmapZipStream = 579 fileStream.Position = 0L;
544 new GZipStream(bitmapMemoryStream, CompressionMode.Compress, -  
Line 545... Line -...
545 true)) -  
546 { -  
547 shot.Save(bitmapZipStream, ImageFormat.Bmp); 580 await fileStream.CopyToAsync(fileZipStream);
548 bitmapZipStream.Close(); -  
549   581 fileZipStream.Close();
550 var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff"); 582  
551   -  
552 fileMemoryStream.Position = 0L; -  
553 bitmapMemoryStream.Position = 0L; 583 using (var bitmapMemoryStream = new MemoryStream())
554   584 {
555 // Insert the file change. 585 using (var bitmapZipStream =
Line 556... Line 586...
556 using (var sqliteCommand = 586 new GZipStream(bitmapMemoryStream, CompressionMode.Compress,
557 new SQLiteCommand(SnapshotFileSql, sqliteConnection, 587 true))
558 dbTransaction)) 588 {
559 { -  
Line 560... Line 589...
560 sqliteCommand.Parameters.AddRange(new[] 589 shot.Save(bitmapZipStream, ImageFormat.Bmp);
561 { 590 bitmapZipStream.Close();
-   591  
562 new SQLiteParameter("@name", name), 592 var time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff");
563 new SQLiteParameter("@time", time), 593  
564 new SQLiteParameter("@path", path), 594 fileMemoryStream.Position = 0L;
565 new SQLiteParameter("@shotLength", 595 bitmapMemoryStream.Position = 0L;
566 bitmapMemoryStream.Length), 596  
Line -... Line 597...
-   597 // Insert the file change.
-   598 using (var sqliteCommand =
-   599 new SQLiteCommand(SnapshotFileSql, sqliteConnection,
-   600 dbTransaction))
-   601 {
-   602 sqliteCommand.Parameters.AddRange(new[]
-   603 {
-   604 new SQLiteParameter("@name", name),
-   605 new SQLiteParameter("@time", time),
-   606 new SQLiteParameter("@path", path),
-   607 new SQLiteParameter("@shotLength",
-   608 bitmapMemoryStream.Length),
-   609 new SQLiteParameter("@dataLength",
-   610 fileMemoryStream.Length),
-   611 new SQLiteParameter("@hash", hashHex)
567 new SQLiteParameter("@dataLength", 612 });
568 fileMemoryStream.Length), 613  
569 new SQLiteParameter("@hash", hashHex) 614 var numeric = color.ToArgb();
-   615 switch (numeric)
570 }); 616 {
571   -  
Line 572... Line 617...
572 var numeric = color.ToArgb(); 617 case 0:
Line 573... Line 618...
573 switch (numeric) 618 sqliteCommand.Parameters.Add(
574 { 619 new SQLiteParameter("@color", null));
575 case 0: 620 break;
-   621 default:
576 sqliteCommand.Parameters.Add( 622 sqliteCommand.Parameters.Add(
577 new SQLiteParameter("@color", null)); 623 new SQLiteParameter("@color", numeric));
578 break; 624 break;
579 default: 625 }
580 sqliteCommand.Parameters.Add( 626  
581 new SQLiteParameter("@color", numeric)); 627 sqliteCommand.Prepare();
582 break; 628  
-   629 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
583 } 630 }
584   631  
-   632 // Insert the data blobs.
-   633 using (var sqliteCommand =
585 sqliteCommand.Prepare(); 634 new SQLiteCommand(GetLastRowInsertSql, sqliteConnection,
586   635 dbTransaction))
-   636 {
-   637 sqliteCommand.Prepare();
Line -... Line 638...
-   638  
-   639 var rowId =
587 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); 640 (long)await sqliteCommand.ExecuteScalarAsync(
588 } 641 cancellationToken);
-   642  
-   643 using (var sqliteBlob =
589   644 SQLiteBlob.Create(sqliteConnection, "main",
590 // Insert the data blobs. 645 "Snapshots",
591 using (var sqliteCommand = -  
592 new SQLiteCommand(GetLastRowInsertSql, sqliteConnection, -  
593 dbTransaction)) -  
594 { -  
595 sqliteCommand.Prepare(); -  
596   -  
597 var rowId = -  
Line 598... Line -...
598 (long)await sqliteCommand.ExecuteScalarAsync( -  
599 cancellationToken); -  
600   646 "Data",
601 using (var sqliteBlob = 647 rowId,
602 SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", -  
603 "Data", -  
604 rowId, -  
605 false)) 648 false))
606 { 649 {
607 var fileMemoryStreamData = fileMemoryStream.ToArray(); 650 var fileMemoryStreamData = fileMemoryStream.ToArray();
-   651  
-   652 sqliteBlob.Write(fileMemoryStreamData,
-   653 fileMemoryStreamData.Length,
-   654 0);
608   655 }
Line 609... Line 656...
609 sqliteBlob.Write(fileMemoryStreamData, 656  
610 fileMemoryStreamData.Length, 657 using (var sqliteBlob =
611 0); 658 SQLiteBlob.Create(sqliteConnection, "main",
612 } 659 "Snapshots",
613   660 "Shot",
614 using (var sqliteBlob = 661 rowId,
Line 615... Line 662...
615 SQLiteBlob.Create(sqliteConnection, "main", "Snapshots", 662 false))
-   663 {
616 "Shot", 664 var bitmapMemoryStreamData =
617 rowId, 665 bitmapMemoryStream.ToArray();
618 false)) -  
619 { -  
620 var bitmapMemoryStreamData = bitmapMemoryStream.ToArray(); -  
621   -  
622 sqliteBlob.Write(bitmapMemoryStreamData, 666  
623 bitmapMemoryStreamData.Length, 667 sqliteBlob.Write(bitmapMemoryStreamData,
624 0); -  
625 } -  
626 } -  
627   -  
628 dbTransaction.Commit(); -  
Line -... Line 668...
-   668 bitmapMemoryStreamData.Length,
-   669 0);
629   670 }
630 SnapshotCreate?.Invoke(this, 671 }
631 new SnapshotCreateSuccessEventArgs(name, time, path, color, 672  
632 hashHex)); 673 dbTransaction.Commit();
633 } 674  
634 } 675 SnapshotCreate?.Invoke(this,
Line 635... Line -...
635 } -  
636 } -  
637 } 676 new SnapshotCreateSuccessEventArgs(name, time, path, color,
638 } -  
Line -... Line 677...
-   677 hashHex));
-   678 }
639 } 679 }
640 } 680 }
641 catch (SQLiteException exception) 681 }
642 { -  
643 dbTransaction.Rollback(); 682 }
-   683 }
644   684 }
645 if (exception.ResultCode != SQLiteErrorCode.Constraint) 685 }
646 { 686 catch (SQLiteException exception)
-   687 {
Line 647... Line 688...
647 SnapshotCreate?.Invoke(this, 688 dbTransaction.Rollback();
-   689  
-   690 if (exception.ResultCode != SQLiteErrorCode.Constraint)
-   691 {
-   692 SnapshotCreate?.Invoke(this,
-   693 new SnapshotCreateFailureEventArgs(name, path, color, exception));
648 new SnapshotCreateFailureEventArgs(name, path, color, exception)); 694 }
-   695  
-   696 throw;
-   697 }
-   698 catch (Exception exception)
649 } 699 {
-   700 dbTransaction.Rollback();
650   701  
651 throw; 702 SnapshotCreate?.Invoke(this,
652 } 703 new SnapshotCreateFailureEventArgs(name, path, color, exception));
653 catch (Exception exception) 704  
654 { 705 throw;
655 dbTransaction.Rollback(); 706 }
656   707 }
-   708 }
-   709 }
-   710 finally
-   711 {
657 SnapshotCreate?.Invoke(this, new SnapshotCreateFailureEventArgs(name, path, color, exception)); 712 _databaseLock.Release();
Line 658... Line 713...
658   713 }
659 throw; 714 }
660 } -  
661 finally -  
662 { 715  
663 _snapshotSemaphore.Release(); 716 public async Task SaveFile(string path, string hash, CancellationToken cancellationToken)
664 } 717 {
665 } 718 var connectionString = new SQLiteConnectionStringBuilder
Line 666... Line 719...
666 } 719 {
-   720 ConnectionString = DatabaseConnectionString
667 } 721 };
668   722  
669 public async Task SaveFile(string path, string hash, CancellationToken cancellationToken) -  
670 { -  
671 var connectionString = new SQLiteConnectionStringBuilder -  
672 { -  
673 ConnectionString = DatabaseConnectionString 723 await _databaseLock.WaitAsync(cancellationToken);
-   724 try
-   725 {
-   726 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
674 }; 727 {
-   728 await sqliteConnection.OpenAsync(cancellationToken);
675   729  
676 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 730 // Insert the file change.
677 { 731 using (var sqliteCommand =
-   732 new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection))
-   733 {
678 await sqliteConnection.OpenAsync(cancellationToken); 734 sqliteCommand.Parameters.AddRange(new[]
679   735 {
Line 680... Line 736...
680 // Insert the file change. 736 new SQLiteParameter("@hash", hash)
Line 681... Line 737...
681 using (var sqliteCommand = 737 });
682 new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection)) -  
683 { -  
684 sqliteCommand.Parameters.AddRange(new[] 738  
-   739 sqliteCommand.Prepare();
-   740  
685 { 741 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken))
Line 686... Line 742...
686 new SQLiteParameter("@hash", hash) 742 {
687 }); 743 while (await sqlDataReader.ReadAsync(cancellationToken))
Line 688... Line 744...
688   744 {
689 sqliteCommand.Prepare(); 745 // Create directories if they do not exist.
690   746 var dir = Path.GetDirectoryName(path);
691 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) 747  
Line 692... Line 748...
692 { 748 if (dir != null && !Directory.Exists(dir))
693 while (await sqlDataReader.ReadAsync(cancellationToken)) 749 {
694 { 750 Directory.CreateDirectory(dir);
695 // Create directories if they do not exist. 751 }
696 var dir = Path.GetDirectoryName(path); 752  
697   753 using (var readStream = sqlDataReader.GetStream(2))
Line 698... Line 754...
698 if (dir != null && !Directory.Exists(dir)) 754 {
699 { -  
700 Directory.CreateDirectory(dir); -  
701 } -  
702   -  
703 using (var readStream = sqlDataReader.GetStream(2)) 755 using (var fileStream =
-   756 await Miscellaneous.GetFileStream(path, FileMode.Create, FileAccess.Write,
704 { 757 FileShare.Write,
705 using (var fileStream = 758 cancellationToken))
706 await Miscellaneous.GetFileStream(path, FileMode.Create, FileAccess.Write, 759 {
-   760 readStream.Position = 0L;
-   761  
-   762 using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress))
707 FileShare.Write, 763 {
-   764 await zipStream.CopyToAsync(fileStream);
708 cancellationToken)) 765 }
709 { 766 }
710 readStream.Position = 0L; -  
Line 711... Line -...
711   -  
712 using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) -  
713 { -  
714 await zipStream.CopyToAsync(fileStream); -  
715 } -  
716 } -  
717 } 767 }
718 } 768 }
719 } 769 }
720 } 770 }
721 } 771 }
722 } 772 }
-   773 finally
-   774 {
-   775 _databaseLock.Release();
-   776 }
-   777 }
-   778  
723   779 public async Task RevertFile(string name, string hash, CancellationToken cancellationToken, bool atomic = true)
724 public async Task RevertFile(string name, string hash, CancellationToken cancellationToken, bool atomic = true) 780 {
725 { 781 var connectionString = new SQLiteConnectionStringBuilder
Line 726... Line 782...
726 await _snapshotSemaphore.WaitAsync(cancellationToken); 782 {
727   783 ConnectionString = DatabaseConnectionString
Line 728... Line 784...
728 var connectionString = new SQLiteConnectionStringBuilder 784 };
729 { 785  
730 ConnectionString = DatabaseConnectionString 786 await _databaseLock.WaitAsync(cancellationToken);
731 }; 787 try
732   -  
733 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) -  
734 { -  
735 await sqliteConnection.OpenAsync(cancellationToken); -  
736   -  
737 // Insert the file change. -  
738 using (var sqliteCommand = 788 {
739 new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection)) 789 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
740 { -  
-   790 {
-   791 await sqliteConnection.OpenAsync(cancellationToken);
741 try 792  
742 { 793 // Insert the file change.
743 sqliteCommand.Parameters.AddRange(new[] 794 using (var sqliteCommand =
-   795 new SQLiteCommand(RetrieveDataPathFromHashSql, sqliteConnection))
-   796 {
-   797 try
-   798 {
-   799 sqliteCommand.Parameters.AddRange(new[]
744 { 800 {
-   801 new SQLiteParameter("@hash", hash)
745 new SQLiteParameter("@hash", hash) 802 });
746 }); 803  
747   -  
Line 748... Line 804...
748 sqliteCommand.Prepare(); 804 sqliteCommand.Prepare();
749   805  
Line 750... Line 806...
750 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) 806 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken))
-   807 {
751 { 808 while (await sqlDataReader.ReadAsync(cancellationToken))
752 while (await sqlDataReader.ReadAsync(cancellationToken)) 809 {
753 { -  
754 var path = (string)sqlDataReader["Path"]; 810 var path = (string)sqlDataReader["Path"];
755   811  
756 // Create directories if they do not exist. 812 // Create directories if they do not exist.
Line 757... Line 813...
757 var dir = Path.GetDirectoryName(path); 813 var dir = Path.GetDirectoryName(path);
758   814  
759 if (dir != null && !Directory.Exists(dir)) -  
760 { -  
761 Directory.CreateDirectory(dir); -  
762 } 815 if (dir != null && !Directory.Exists(dir))
763   816 {
764 switch (atomic) 817 Directory.CreateDirectory(dir);
-   818 }
-   819  
-   820 switch (atomic)
-   821 {
765 { 822 case true:
Line 766... Line 823...
766 case true: 823 // Atomic
767 // Atomic 824 var temp = Path.Combine(Path.GetDirectoryName(path),
768 var temp = Path.Combine(Path.GetDirectoryName(path), 825 $"{Path.GetFileName(path)}.temp");
769 $"{Path.GetFileName(path)}.temp"); 826  
770   827 using (var readStream = sqlDataReader.GetStream(2))
771 using (var readStream = sqlDataReader.GetStream(2)) 828 {
Line 772... Line 829...
772 { 829 using (var fileStream = new FileStream(temp, FileMode.Create,
-   830 FileAccess.Write,
773 using (var fileStream = new FileStream(temp, FileMode.Create, 831 FileShare.None))
774 FileAccess.Write, -  
775 FileShare.None)) -  
776 { 832 {
777 using (var zipStream = 833 using (var zipStream =
778 new GZipStream(readStream, CompressionMode.Decompress)) -  
779 { -  
780 zipStream.CopyTo(fileStream); 834 new GZipStream(readStream, CompressionMode.Decompress))
Line -... Line 835...
-   835 {
-   836 zipStream.CopyTo(fileStream);
781 } 837 }
782 } 838 }
783 } 839 }
-   840  
784   841 try
785 try -  
786 { 842 {
-   843 File.Replace(temp, path, null, true);
787 File.Replace(temp, path, null, true); 844 }
-   845 catch
788 } 846 {
-   847 try
-   848 {
789 catch 849 File.Delete(temp);
790 { 850 }
Line 791... Line 851...
791 try 851 catch (Exception exception)
Line 792... Line 852...
792 { 852 {
Line 793... Line 853...
793 File.Delete(temp); 853 // Suppress deletion errors of temporary file.
-   854 Log.Warning(exception, "Could not delete temporary file.", temp);
794 } 855 }
795 catch (Exception exception) -  
Line 796... Line 856...
796 { 856  
Line 797... Line 857...
797 // Suppress deletion errors of temporary file. 857 throw;
798 Log.Warning(exception, "Could not delete temporary file.", temp); 858 }
799 } 859  
800   860 break;
801 throw; 861 default:
Line 802... Line 862...
802 } 862 // Asynchronous
-   863 using (var readStream = sqlDataReader.GetStream(2))
803   864 {
804 break; 865 using (var fileStream =
805 default: 866 await Miscellaneous.GetFileStream(path, FileMode.Create,
-   867 FileAccess.Write,
-   868 FileShare.Write,
-   869 cancellationToken))
-   870 {
806 // Asynchronous 871 readStream.Position = 0L;
Line 807... Line 872...
807 using (var readStream = sqlDataReader.GetStream(2)) 872  
808 { 873 using (var zipStream =
809 using (var fileStream = 874 new GZipStream(readStream, CompressionMode.Decompress))
810 await Miscellaneous.GetFileStream(path, FileMode.Create, 875 {
811 FileAccess.Write, 876 await zipStream.CopyToAsync(fileStream);
812 FileShare.Write, 877 }
813 cancellationToken)) -  
814 { 878 }
-   879 }
815 readStream.Position = 0L; 880  
816   -  
817 using (var zipStream = -  
818 new GZipStream(readStream, CompressionMode.Decompress)) 881  
819 { 882 break;
820 await zipStream.CopyToAsync(fileStream); 883 }
821 } -  
-   884  
822 } 885 SnapshotRevert?.Invoke(this, new SnapshotRevertSuccessEventArgs(name));
823 } 886 }
-   887 }
824   888 }
-   889 catch
825   890 {
826 break; 891 SnapshotRevert?.Invoke(this, new SnapshotRevertFailureEventArgs(name));
827 } 892  
828   893 throw;
829 SnapshotRevert?.Invoke(this, new SnapshotRevertSuccessEventArgs(name)); 894 }
Line 830... Line 895...
830 } 895 }
Line -... Line 896...
-   896 }
-   897 }
831 } 898 finally
Line 832... Line 899...
832 } 899 {
833 catch 900 _databaseLock.Release();
834 { 901 }
835 SnapshotRevert?.Invoke(this, new SnapshotRevertFailureEventArgs(name)); 902 }
836   903  
Line 837... Line 904...
837 throw; 904 public async Task RemoveFileFast(IEnumerable<string> hashes, CancellationToken cancellationToken)
-   905 {
838 } 906 var connectionString = new SQLiteConnectionStringBuilder
839 finally 907 {
840 { 908 ConnectionString = DatabaseConnectionString
841 _snapshotSemaphore.Release(); 909 };
-   910  
-   911 await _databaseLock.WaitAsync(cancellationToken);
-   912 try
-   913 {
842 } 914 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
Line 843... Line 915...
843 } 915 {
844 } 916 await sqliteConnection.OpenAsync(cancellationToken);
845 } 917  
846   918 using (var dbTransaction = sqliteConnection.BeginTransaction())
847 public async Task RemoveFileFast(IEnumerable<string> hashes, CancellationToken cancellationToken) 919 {
848 { 920 try
Line 849... Line -...
849 var connectionString = new SQLiteConnectionStringBuilder -  
850 { -  
851 ConnectionString = DatabaseConnectionString 921 {
Line -... Line 922...
-   922 var transactionCommands = new List<Task>();
-   923  
852 }; 924 foreach (var hash in hashes)
853   925 {
854 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 926 // Insert the file change.
855 { -  
-   927 using (var sqliteCommand =
856 await sqliteConnection.OpenAsync(cancellationToken); 928 new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction))
857   929 {
-   930 sqliteCommand.Parameters.AddRange(new[]
858 using (var dbTransaction = sqliteConnection.BeginTransaction()) 931 {
-   932 new SQLiteParameter("@hash", hash)
859 { 933 });
860 try 934  
861 { 935 sqliteCommand.Prepare();
862 var transactionCommands = new List<Task>(); 936  
863   937 var command = sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
864 foreach (var hash in hashes) 938  
Line 865... Line 939...
865 { 939 transactionCommands.Add(command);
Line -... Line 940...
-   940 }
-   941 }
866 // Insert the file change. 942  
Line 867... Line 943...
867 using (var sqliteCommand = 943 await Task.WhenAll(transactionCommands);
868 new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) 944  
869 { 945 dbTransaction.Commit();
870 sqliteCommand.Parameters.AddRange(new[] 946 }
871 { 947 catch
Line 872... Line 948...
872 new SQLiteParameter("@hash", hash) 948 {
-   949 dbTransaction.Rollback();
873 }); 950  
874   951 throw;
875 sqliteCommand.Prepare(); 952 }
876   953 }
-   954 }
-   955 }
-   956 finally
-   957 {
877 var command = sqliteCommand.ExecuteNonQueryAsync(cancellationToken); 958 _databaseLock.Release();
Line 878... Line 959...
878   959 }
879 transactionCommands.Add(command); 960 }
880 } 961  
881 } 962 public async Task RemoveFile(string hash, CancellationToken cancellationToken)
882   963 {
883 await Task.WhenAll(transactionCommands); 964 var connectionString = new SQLiteConnectionStringBuilder
Line 884... Line 965...
884   965 {
-   966 ConnectionString = DatabaseConnectionString
885 dbTransaction.Commit(); 967 };
886 } -  
887 catch -  
888 { 968 await _databaseLock.WaitAsync(cancellationToken);
889 dbTransaction.Rollback(); 969 try
890   970 {
891 throw; -  
-   971 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
892 } 972 {
893 } 973 await sqliteConnection.OpenAsync(cancellationToken);
-   974  
894 } 975 using (var dbTransaction = sqliteConnection.BeginTransaction())
-   976 {
895 } 977 // Insert the file change.
896   978 using (var sqliteCommand =
897 public async Task RemoveFile(string hash, CancellationToken cancellationToken) 979 new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction))
898 { 980 {
899 var connectionString = new SQLiteConnectionStringBuilder 981 sqliteCommand.Parameters.AddRange(new[]
Line 900... Line 982...
900 { 982 {
Line -... Line 983...
-   983 new SQLiteParameter("@hash", hash)
-   984 });
901 ConnectionString = DatabaseConnectionString 985  
Line 902... Line 986...
902 }; 986 sqliteCommand.Prepare();
903   987  
904 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 988 try
905 { 989 {
906 await sqliteConnection.OpenAsync(cancellationToken); 990 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
Line 907... Line 991...
907   991  
-   992 dbTransaction.Commit();
908 using (var dbTransaction = sqliteConnection.BeginTransaction()) 993 }
909 { 994 catch
910 // Insert the file change. 995 {
911 using (var sqliteCommand = 996 dbTransaction.Rollback();
-   997  
-   998 throw;
-   999 }
-   1000 }
912 new SQLiteCommand(RemoveSnapshotFromHashSql, sqliteConnection, dbTransaction)) 1001 }
Line 913... Line 1002...
913 { 1002 }
914 try 1003 }
915 { 1004 finally
916 sqliteCommand.Parameters.AddRange(new[] 1005 {
917 { 1006 _databaseLock.Release();
918 new SQLiteParameter("@hash", hash) 1007 }
Line 919... Line 1008...
919 }); 1008 }
-   1009  
920   1010 public async Task UpdateColor(string hash, Color color, CancellationToken cancellationToken)
921 sqliteCommand.Prepare(); -  
922   -  
923 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); -  
924   1011 {
925 dbTransaction.Commit(); 1012 var connectionString = new SQLiteConnectionStringBuilder
926 } 1013 {
927 catch -  
928 { -  
929 dbTransaction.Rollback(); -  
930   -  
931 throw; -  
932 } -  
933 } -  
Line -... Line 1014...
-   1014 ConnectionString = DatabaseConnectionString
934 } 1015 };
935 } 1016  
936 } 1017 await _databaseLock.WaitAsync(cancellationToken);
937   1018  
938 public async Task UpdateColor(string hash, Color color, CancellationToken cancellationToken) 1019 try
939 { 1020 {
940 var connectionString = new SQLiteConnectionStringBuilder -  
941 { -  
942 ConnectionString = DatabaseConnectionString -  
943 }; -  
Line 944... Line -...
944   -  
945 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1021 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
946 { -  
Line 947... Line 1022...
947 await sqliteConnection.OpenAsync(cancellationToken); 1022 {
Line 948... Line 1023...
948   1023 await sqliteConnection.OpenAsync(cancellationToken);
-   1024  
-   1025 using (var dbTransaction = sqliteConnection.BeginTransaction())
-   1026 {
-   1027 // Insert the file change.
949 using (var dbTransaction = sqliteConnection.BeginTransaction()) 1028 using (var sqliteCommand =
950 { -  
951 // Insert the file change. -  
952 using (var sqliteCommand = 1029 new SQLiteCommand(UpdateColorFromHashSql, sqliteConnection, dbTransaction))
953 new SQLiteCommand(UpdateColorFromHashSql, sqliteConnection, dbTransaction)) -  
954 { 1030 {
955 try -  
956 { -  
957 sqliteCommand.Parameters.AddRange(new[] -  
958 { -  
959 new SQLiteParameter("@hash", hash), -  
960 new SQLiteParameter("@color", color.ToArgb()) -  
961 }); -  
962   -  
963 sqliteCommand.Prepare(); -  
964   -  
965 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); -  
966   -  
967 dbTransaction.Commit(); -  
968 } -  
969 catch -  
970 { -  
971 dbTransaction.Rollback(); -  
972   -  
973 throw; -  
974 } -  
975 } -  
976 } -  
977 } -  
978 } -  
979   -  
980 public async Task RemoveColor(string hash, CancellationToken cancellationToken) -  
981 { -  
982 var connectionString = new SQLiteConnectionStringBuilder -  
983 { -  
984 ConnectionString = DatabaseConnectionString -  
985 }; -  
986   -  
987 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) -  
Line 988... Line 1031...
988 { 1031 sqliteCommand.Parameters.AddRange(new[]
989 await sqliteConnection.OpenAsync(cancellationToken); -  
Line 990... Line 1032...
990   1032 {
991 using (var dbTransaction = sqliteConnection.BeginTransaction()) -  
992 { -  
993 // Insert the file change. -  
994 using (var sqliteCommand = -  
995 new SQLiteCommand(RemoveColorFromHashSql, sqliteConnection, dbTransaction)) -  
996 { 1033 new SQLiteParameter("@hash", hash),
-   1034 new SQLiteParameter("@color", color.ToArgb())
Line 997... Line 1035...
997 try 1035 });
Line 998... Line -...
998 { -  
999 sqliteCommand.Parameters.AddRange(new[] -  
1000 { -  
1001 new SQLiteParameter("@hash", hash) -  
1002 }); 1036  
1003   1037 sqliteCommand.Prepare();
1004 sqliteCommand.Prepare(); -  
1005   1038  
1006 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); -  
1007   1039 try
1008 dbTransaction.Commit(); -  
1009 } 1040 {
1010 catch -  
1011 { 1041 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
1012 dbTransaction.Rollback(); 1042  
1013   1043 dbTransaction.Commit();
-   1044 }
-   1045 catch
1014 throw; 1046 {
1015 } -  
Line 1016... Line 1047...
1016 } 1047 dbTransaction.Rollback();
-   1048  
1017 } 1049 throw;
1018 } 1050 }
1019 } 1051 }
-   1052 }
-   1053 }
-   1054 }
-   1055 finally
1020   1056 {
1021 public async Task<SnapshotPreview> RetrievePreview(string hash, CancellationToken cancellationToken) -  
Line 1022... Line 1057...
1022 { 1057 _databaseLock.Release();
1023 var connectionString = new SQLiteConnectionStringBuilder 1058 }
1024 { 1059 }
1025 ConnectionString = DatabaseConnectionString 1060  
1026 }; 1061 public async Task RemoveColor(string hash, CancellationToken cancellationToken)
1027   1062 {
Line 1028... Line 1063...
1028 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1063 var connectionString = new SQLiteConnectionStringBuilder
-   1064 {
1029 { 1065 ConnectionString = DatabaseConnectionString
1030 await sqliteConnection.OpenAsync(cancellationToken); -  
1031   -  
1032 // Insert the file change. -  
1033 using (var sqliteCommand = new SQLiteCommand(RetrievePreviewFromHashSql, sqliteConnection)) 1066 };
1034 { 1067  
1035 sqliteCommand.Parameters.AddRange(new[] 1068 await _databaseLock.WaitAsync(cancellationToken);
-   1069 try
-   1070 {
-   1071 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
1036 { 1072 {
-   1073 await sqliteConnection.OpenAsync(cancellationToken);
-   1074  
1037 new SQLiteParameter("@hash", hash) 1075 using (var dbTransaction = sqliteConnection.BeginTransaction())
1038 }); 1076 {
Line 1039... Line 1077...
1039   1077 // Insert the file change.
Line 1040... Line 1078...
1040 var note = string.Empty; 1078 using (var sqliteCommand =
1041   -  
1042 sqliteCommand.Prepare(); -  
1043   1079 new SQLiteCommand(RemoveColorFromHashSql, sqliteConnection, dbTransaction))
1044 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) 1080 {
1045 { 1081 sqliteCommand.Parameters.AddRange(new[]
1046 while (await sqlDataReader.ReadAsync(cancellationToken)) 1082 {
1047 { 1083 new SQLiteParameter("@hash", hash)
-   1084 });
-   1085  
1048 if (!(sqlDataReader["Note"] is DBNull)) 1086 sqliteCommand.Prepare();
Line 1049... Line 1087...
1049 { 1087  
Line 1050... Line 1088...
1050 note = (string)sqlDataReader["Note"]; 1088 try
Line 1051... Line 1089...
1051 } 1089 {
1052   1090 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
1053 Bitmap shot = null; 1091  
1054   1092 dbTransaction.Commit();
Line 1055... Line 1093...
1055 if (!(sqlDataReader["Shot"] is DBNull)) 1093 }
Line 1056... Line 1094...
1056 { 1094 catch
Line 1057... Line 1095...
1057 var readStream = sqlDataReader.GetStream(2); 1095 {
-   1096 dbTransaction.Rollback();
1058   1097  
1059 readStream.Position = 0L; 1098 throw;
1060   1099 }
1061 using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress)) -  
Line 1062... Line 1100...
1062 { 1100 }
-   1101 }
1063 using (var image = Image.FromStream(zipStream)) 1102 }
1064 { 1103 }
1065 shot = new Bitmap(image); 1104 finally
-   1105 {
-   1106 _databaseLock.Release();
-   1107 }
-   1108 }
1066 } 1109  
Line 1067... Line 1110...
1067 } 1110 public async Task<SnapshotPreview> RetrievePreview(string hash, CancellationToken cancellationToken)
1068 } 1111 {
1069   1112 var connectionString = new SQLiteConnectionStringBuilder
1070 return new SnapshotPreview(hash, shot, note); 1113 {
1071 } 1114 ConnectionString = DatabaseConnectionString
1072   1115 };
Line 1073... Line 1116...
1073 return null; 1116  
-   1117 await _databaseLock.WaitAsync(cancellationToken);
1074 } 1118 try
1075 } -  
1076 } -  
1077 } 1119 {
1078   1120 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
1079 /* 1121 {
1080 public MemoryStream RetrieveFileStream(string hash, CancellationToken cancellationToken) -  
-   1122 await sqliteConnection.OpenAsync(cancellationToken);
1081 { 1123  
1082 var connectionString = new SQLiteConnectionStringBuilder 1124 // Insert the file change.
-   1125 using (var sqliteCommand = new SQLiteCommand(RetrievePreviewFromHashSql, sqliteConnection))
1083 { 1126 {
-   1127 sqliteCommand.Parameters.AddRange(new[]
1084 ConnectionString = DatabaseConnectionString 1128 {
1085 }; 1129 new SQLiteParameter("@hash", hash)
1086   1130 });
1087 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1131  
1088 { 1132 var note = string.Empty;
1089   1133  
Line 1090... Line 1134...
1090 sqliteConnection.Open(); 1134 sqliteCommand.Prepare();
Line -... Line 1135...
-   1135  
-   1136 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken))
1091   1137 {
Line 1092... Line 1138...
1092 // Insert the file change. 1138 while (await sqlDataReader.ReadAsync(cancellationToken))
1093 using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection)) 1139 {
1094 { 1140 if (!(sqlDataReader["Note"] is DBNull))
1095 sqliteCommand.Parameters.AddRange(new[] 1141 {
1096 { 1142 note = (string)sqlDataReader["Note"];
Line 1097... Line 1143...
1097 new SQLiteParameter("@hash", hash) 1143 }
-   1144  
1098 }); 1145 Bitmap shot = null;
1099   1146  
1100 sqliteCommand.Prepare(); 1147 if (!(sqlDataReader["Shot"] is DBNull))
1101   1148 {
-   1149 var readStream = sqlDataReader.GetStream(2);
-   1150  
-   1151 readStream.Position = 0L;
-   1152  
-   1153 using (var zipStream = new GZipStream(readStream, CompressionMode.Decompress))
1102 using (var sqlDataReader = sqliteCommand.ExecuteReader()) 1154 {
Line 1103... Line 1155...
1103 { 1155 using (var image = Image.FromStream(zipStream))
1104   1156 {
1105 while (sqlDataReader.Read()) 1157 shot = new Bitmap(image);
1106 { 1158 }
1107 using (var readStream = sqlDataReader.GetStream(1)) 1159 }
1108 { 1160 }
Line 1109... Line 1161...
1109   1161  
-   1162 return new SnapshotPreview(hash, shot, note);
1110 using (var memoryStream = new MemoryStream()) 1163 }
1111 { -  
1112   -  
1113 readStream.Position = 0L; 1164  
1114   1165 return null;
1115 readStream.CopyTo(memoryStream); 1166 }
1116   -  
-   1167 }
1117 memoryStream.Position = 0L; 1168 }
1118   1169 }
-   1170 finally
1119 using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) 1171 {
-   1172 _databaseLock.Release();
1120 { 1173 }
1121   1174 }
1122 var outputStream = new MemoryStream(); 1175  
1123   1176 public async Task<MemoryStream> RetrieveFileStream(string hash, CancellationToken cancellationToken)
1124 zipStream.CopyTo(outputStream); 1177 {
1125   1178 var connectionString = new SQLiteConnectionStringBuilder
Line 1126... Line 1179...
1126 outputStream.Position = 0L; 1179 {
Line -... Line 1180...
-   1180 ConnectionString = DatabaseConnectionString
-   1181 };
1127   1182  
Line 1128... Line 1183...
1128 return outputStream; 1183 await _databaseLock.WaitAsync(cancellationToken);
Line 1129... Line 1184...
1129 } 1184 try
1130 } 1185 {
1131 } 1186 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
1132 } 1187 {
1133   1188 await sqliteConnection.OpenAsync(cancellationToken);
Line 1134... Line 1189...
1134 return null; 1189  
Line 1135... Line 1190...
1135 } 1190 // Insert the file change.
-   1191 using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection))
1136 } 1192 {
1137 } 1193 sqliteCommand.Parameters.AddRange(new[]
1138 } 1194 {
1139 */ 1195 new SQLiteParameter("@hash", hash)
-   1196 });
-   1197  
-   1198 sqliteCommand.Prepare();
-   1199  
1140   1200 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken))
Line 1141... Line 1201...
1141 public async Task<MemoryStream> RetrieveFileStream(string hash, CancellationToken cancellationToken) 1201 {
1142 { 1202 while (await sqlDataReader.ReadAsync(cancellationToken))
1143 var connectionString = new SQLiteConnectionStringBuilder 1203 {
1144 { 1204 using (var readStream = sqlDataReader.GetStream(1))
1145 ConnectionString = DatabaseConnectionString -  
1146 }; -  
1147   1205 {
1148 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1206 using (var memoryStream = new MemoryStream())
Line -... Line 1207...
-   1207 {
-   1208 readStream.Position = 0L;
-   1209  
1149 { 1210 await readStream.CopyToAsync(memoryStream);
1150 await sqliteConnection.OpenAsync(cancellationToken); 1211  
1151   -  
1152 // Insert the file change. -  
1153 using (var sqliteCommand = new SQLiteCommand(RetrieveDataFromHashSql, sqliteConnection)) 1212 memoryStream.Position = 0L;
1154 { 1213  
1155 sqliteCommand.Parameters.AddRange(new[] 1214 using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
-   1215 {
-   1216 // Do not dispose the returned stream and leave it up to callers to dispose.
1156 { 1217 var outputStream = new MemoryStream();
1157 new SQLiteParameter("@hash", hash) 1218  
1158 }); 1219 await zipStream.CopyToAsync(outputStream);
1159   1220  
1160 sqliteCommand.Prepare(); 1221 outputStream.Position = 0L;
-   1222  
-   1223 return outputStream;
1161   1224 }
1162 using (var sqlDataReader = await sqliteCommand.ExecuteReaderAsync(cancellationToken)) 1225 }
Line 1163... Line 1226...
1163 { 1226 }
1164 while (await sqlDataReader.ReadAsync(cancellationToken)) 1227 }
1165 { 1228  
1166 using (var readStream = sqlDataReader.GetStream(1)) 1229 return null;
Line 1167... Line 1230...
1167 { 1230 }
1168 using (var memoryStream = new MemoryStream()) -  
1169 { -  
1170 readStream.Position = 0L; -  
1171   1231 }
1172 await readStream.CopyToAsync(memoryStream); -  
1173   -  
1174 memoryStream.Position = 0L; -  
1175   -  
1176 using (var zipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) -  
1177 { -  
1178 // Do not dispose the returned stream and leave it up to callers to dispose. -  
1179 var outputStream = new MemoryStream(); 1232 }
1180   1233 }
1181 await zipStream.CopyToAsync(outputStream); 1234 finally
-   1235 {
-   1236 _databaseLock.Release();
-   1237 }
-   1238 }
1182   1239  
-   1240 public async Task RelocateFile(string hash, string path, CancellationToken cancellationToken)
-   1241 {
-   1242 var connectionString = new SQLiteConnectionStringBuilder
-   1243 {
-   1244 ConnectionString = DatabaseConnectionString
1183 outputStream.Position = 0L; 1245 };
-   1246  
-   1247 await _databaseLock.WaitAsync(cancellationToken);
1184   1248 try
1185 return outputStream; 1249 {
1186 } 1250 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
1187 } 1251 {
Line 1188... Line 1252...
1188 } 1252 await sqliteConnection.OpenAsync(cancellationToken);
1189 } 1253  
1190   1254 using (var dbTransaction = sqliteConnection.BeginTransaction())
Line 1191... Line 1255...
1191 return null; 1255 {
1192 } 1256 // Insert the file change.
1193 } 1257 using (var sqliteCommand =
1194 } -  
1195 } -  
1196   1258 new SQLiteCommand(RelocateFileFromHashSql, sqliteConnection, dbTransaction))
-   1259 {
-   1260 sqliteCommand.Parameters.AddRange(new[]
1197 public async Task RelocateFile(string hash, string path, CancellationToken cancellationToken) 1261 {
1198 { 1262 new SQLiteParameter("@hash", hash),
Line 1199... Line 1263...
1199 var connectionString = new SQLiteConnectionStringBuilder 1263 new SQLiteParameter("@path", path)
Line 1200... Line 1264...
1200 { 1264 });
1201 ConnectionString = DatabaseConnectionString 1265  
1202 }; -  
1203   -  
1204 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1266 sqliteCommand.Prepare();
1205 { 1267  
1206 await sqliteConnection.OpenAsync(cancellationToken); 1268 try
1207   -  
1208 using (var dbTransaction = sqliteConnection.BeginTransaction()) -  
1209 { -  
1210 // Insert the file change. -  
1211 using (var sqliteCommand = 1269 {
1212 new SQLiteCommand(RelocateFileFromHashSql, sqliteConnection, dbTransaction)) 1270 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
-   1271  
-   1272 dbTransaction.Commit();
-   1273 }
-   1274 catch
-   1275 {
-   1276 dbTransaction.Rollback();
-   1277  
-   1278 throw;
1213 { 1279 }
1214 try 1280 }
1215 { 1281 }
1216 sqliteCommand.Parameters.AddRange(new[] 1282 }
1217 { 1283 }
-   1284  
1218 new SQLiteParameter("@hash", hash), 1285 finally
1219 new SQLiteParameter("@path", path) 1286 {
1220 }); 1287 _databaseLock.Release();
1221   1288 }
1222 sqliteCommand.Prepare(); -  
Line 1223... Line 1289...
1223   1289 }
Line 1224... Line 1290...
1224 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); 1290  
1225   1291 public async Task UpdateNote(string hash, string note, CancellationToken cancellationToken)
Line 1226... Line 1292...
1226 dbTransaction.Commit(); 1292 {
-   1293 var connectionString = new SQLiteConnectionStringBuilder
1227 } 1294 {
1228 catch 1295 ConnectionString = DatabaseConnectionString
1229 { 1296 };
1230 dbTransaction.Rollback(); 1297  
1231   -  
1232 throw; 1298 await _databaseLock.WaitAsync(cancellationToken);
1233 } 1299 try
1234 } 1300 {
Line 1235... Line 1301...
1235 } 1301 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
Line 1236... Line 1302...
1236 } 1302 {
-   1303 await sqliteConnection.OpenAsync(cancellationToken);
1237 } 1304  
1238   1305 using (var dbTransaction = sqliteConnection.BeginTransaction())
1239 public async Task UpdateNote(string hash, string note, CancellationToken cancellationToken) 1306 {
1240 { 1307 // Insert the file change.
-   1308 using (var sqliteCommand =
-   1309 new SQLiteCommand(UpdateNoteFromHashSql, sqliteConnection, dbTransaction))
-   1310 {
-   1311 sqliteCommand.Parameters.AddRange(new[]
1241 var connectionString = new SQLiteConnectionStringBuilder 1312 {
Line 1242... Line 1313...
1242 { 1313 new SQLiteParameter("@hash", hash),
1243 ConnectionString = DatabaseConnectionString 1314 new SQLiteParameter("@note", note)
1244 }; 1315 });
1245   1316  
1246 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1317 sqliteCommand.Prepare();
1247 { 1318  
Line 1248... Line 1319...
1248 await sqliteConnection.OpenAsync(cancellationToken); 1319 try
-   1320 {
1249   1321 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
1250 using (var dbTransaction = sqliteConnection.BeginTransaction()) -  
1251 { -  
1252 // Insert the file change. 1322  
1253 using (var sqliteCommand = 1323 dbTransaction.Commit();
1254 new SQLiteCommand(UpdateNoteFromHashSql, sqliteConnection, dbTransaction)) 1324  
1255 { -  
-   1325 SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateSuccessEventArgs(note));
1256 try 1326 }
1257 { 1327 catch
-   1328 {
1258 sqliteCommand.Parameters.AddRange(new[] 1329 dbTransaction.Rollback();
-   1330  
1259 { 1331 SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateFailureEventArgs());
1260 new SQLiteParameter("@hash", hash), 1332  
1261 new SQLiteParameter("@note", note) 1333 throw;
1262 }); 1334 }
1263   1335 }
1264 sqliteCommand.Prepare(); 1336 }
Line 1265... Line 1337...
1265   1337 }
Line -... Line 1338...
-   1338 }
-   1339 finally
1266 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken); 1340 {
Line 1267... Line 1341...
1267   1341 _databaseLock.Release();
1268 dbTransaction.Commit(); 1342 }
1269   1343 }
1270 SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateSuccessEventArgs(note)); 1344  
1271 } 1345 public async Task<string> UpdateFile(string hash, byte[] data, CancellationToken cancellationToken)
Line 1272... Line 1346...
1272 catch 1346 {
-   1347 var connectionString = new SQLiteConnectionStringBuilder
1273 { 1348 {
1274 dbTransaction.Rollback(); 1349 ConnectionString = DatabaseConnectionString
1275   1350 };
1276 SnapshotNoteUpdate?.Invoke(this, new SnapshotNoteUpdateFailureEventArgs()); 1351  
-   1352 await _databaseLock.WaitAsync(cancellationToken);
-   1353 try
-   1354 {
-   1355 using (var dataMemoryStream = new MemoryStream(data))
1277   1356 {
Line 1278... Line 1357...
1278 throw; 1357 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString))
Line 1279... Line 1358...
1279 } 1358 {
Line 1280... Line 1359...
1280 } 1359 await sqliteConnection.OpenAsync(cancellationToken);
1281 } 1360  
1282 } 1361 using (var dbTransaction = sqliteConnection.BeginTransaction())
1283 } 1362 {
1284   1363 try
1285 public async Task<string> UpdateFile(string hash, byte[] data, CancellationToken cancellationToken) 1364 {
Line 1286... Line 1365...
1286 { 1365 using (var md5 = MD5.Create())
1287 using (var dataMemoryStream = new MemoryStream(data)) 1366 {
1288 { 1367 using (var hashMemoryStream = new MemoryStream())
1289 var connectionString = new SQLiteConnectionStringBuilder -  
1290 { -  
1291 ConnectionString = DatabaseConnectionString 1368 {
1292 }; 1369 dataMemoryStream.Position = 0L;
1293   1370 await dataMemoryStream.CopyToAsync(hashMemoryStream);
-   1371  
-   1372 hashMemoryStream.Position = 0L;
-   1373 var recomputedHash = md5.ComputeHash(hashMemoryStream);
-   1374 var hashHex = BitConverter.ToString(recomputedHash).Replace("-", "")
-   1375 .ToLowerInvariant();
1294 using (var sqliteConnection = new SQLiteConnection(connectionString.ConnectionString)) 1376  
-   1377 using (var fileMemoryStream = new MemoryStream())
1295 { 1378 {
1296 await sqliteConnection.OpenAsync(cancellationToken); 1379 using (var fileZipStream =
-   1380 new GZipStream(fileMemoryStream, CompressionMode.Compress, true))
-   1381 {
-   1382 dataMemoryStream.Position = 0L;
-   1383 await dataMemoryStream.CopyToAsync(fileZipStream);
1297   1384 fileZipStream.Close();
Line 1298... Line 1385...
1298 using (var dbTransaction = sqliteConnection.BeginTransaction()) 1385  
1299 { 1386 fileMemoryStream.Position = 0L;
1300 try 1387  
1301 { 1388 // Insert the file change.
1302 using (var md5 = MD5.Create()) 1389 using (var sqliteCommand =
1303 { 1390 new SQLiteCommand(UpdateFileSql, sqliteConnection,
Line 1304... Line 1391...
1304 using (var hashMemoryStream = new MemoryStream()) 1391 dbTransaction))
-   1392 {
1305 { 1393 sqliteCommand.Parameters.AddRange(new[]
1306 dataMemoryStream.Position = 0L; -  
1307 await dataMemoryStream.CopyToAsync(hashMemoryStream); -  
1308   1394 {
1309 hashMemoryStream.Position = 0L; 1395 new SQLiteParameter("@dataLength", fileMemoryStream.Length),
1310 var recomputedHash = md5.ComputeHash(hashMemoryStream); 1396 new SQLiteParameter("@recomputedHash", hashHex),
-   1397 new SQLiteParameter("@hash", hash)
1311 var hashHex = BitConverter.ToString(recomputedHash).Replace("-", "") 1398 });
1312 .ToLowerInvariant(); 1399  
1313   1400 sqliteCommand.Prepare();
-   1401 await sqliteCommand.ExecuteNonQueryAsync(cancellationToken);
1314 using (var fileMemoryStream = new MemoryStream()) 1402 }
-   1403  
-   1404 using (var sqliteCommand =
1315 { 1405 new SQLiteCommand(GetRowFromHashSql, sqliteConnection,
Line 1316... Line 1406...
1316 using (var fileZipStream = 1406 dbTransaction))
1317 new GZipStream(fileMemoryStream, CompressionMode.Compress, true)) 1407 {
1318 { 1408 sqliteCommand.Parameters.AddRange(new[]
1319 dataMemoryStream.Position = 0L; 1409 {
1320 await dataMemoryStream.CopyToAsync(fileZipStream); 1410 new SQLiteParameter("@hash", hashHex)
Line 1321... Line 1411...
1321 fileZipStream.Close(); 1411 });
-   1412  
1322   1413 sqliteCommand.Prepare();
1323 fileMemoryStream.Position = 0L; 1414  
1324   1415 using (var sqlDataReader =
1325 // Insert the file change. 1416 await sqliteCommand.ExecuteReaderAsync(cancellationToken))
-   1417 {
-   1418 while (await sqlDataReader.ReadAsync(cancellationToken))
-   1419 {
-   1420 if (sqlDataReader["id"] is long rowId)
1326 using (var sqliteCommand = 1421 {
Line 1327... Line 1422...
1327 new SQLiteCommand(UpdateFileSql, sqliteConnection, dbTransaction)) 1422 using (var sqliteBlob = SQLiteBlob.Create(
1328 { 1423 sqliteConnection,
1329 sqliteCommand.Parameters.AddRange(new[] 1424 "main",
1330 { 1425 "Snapshots",