Skip to content

Commit 7a512cc

Browse files
[feature] Display skipped entries counters in inventory status (#280)
1 parent 57d90c0 commit 7a512cc

File tree

21 files changed

+355
-117
lines changed

21 files changed

+355
-117
lines changed

src/ByteSync.Client/Assets/Resources/Resources.fr.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ Voulez-vous continuer ?</value>
397397
<data name="InventoryProcess_IdentificationErrors" xml:space="preserve">
398398
<value>Erreurs d'identification :</value>
399399
</data>
400+
<data name="InventoryProcess_SkippedEntries" xml:space="preserve">
401+
<value>Entrées ignorées :</value>
402+
</data>
400403
<data name="InventoryProcess_Start" xml:space="preserve">
401404
<value>Démarrage :</value>
402405
</data>
@@ -670,6 +673,9 @@ Voulez-vous continuer ?</value>
670673
<data name="InventoryProcess_GlobalAnalyzeErrors" xml:space="preserve">
671674
<value>Total des erreurs de calcul :</value>
672675
</data>
676+
<data name="InventoryProcess_GlobalSkippedEntries" xml:space="preserve">
677+
<value>Total des entrées ignorées :</value>
678+
</data>
673679
<data name="InventoryProcess_GlobalIdentificationErrors" xml:space="preserve">
674680
<value>Total erreurs d'identification :</value>
675681
</data>

src/ByteSync.Client/Assets/Resources/Resources.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ Would you like to continue ?</value>
397397
<data name="InventoryProcess_IdentificationErrors" xml:space="preserve">
398398
<value>Identification Errors:</value>
399399
</data>
400+
<data name="InventoryProcess_SkippedEntries" xml:space="preserve">
401+
<value>Skipped Entries:</value>
402+
</data>
400403
<data name="InventoryProcess_Start" xml:space="preserve">
401404
<value>Start:</value>
402405
</data>
@@ -679,6 +682,9 @@ Would you like to continue ?</value>
679682
<data name="InventoryProcess_GlobalAnalyzeErrors" xml:space="preserve">
680683
<value>Total Calculation Errors:</value>
681684
</data>
685+
<data name="InventoryProcess_GlobalSkippedEntries" xml:space="preserve">
686+
<value>Total Skipped Entries:</value>
687+
</data>
682688
<data name="InventoryProcess_GlobalIdentificationErrors" xml:space="preserve">
683689
<value>Total Identification Errors:</value>
684690
</data>

src/ByteSync.Client/Business/Inventories/InventoryMonitorData.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public record InventoryMonitorData
2323
public long UploadTotalVolume { get; set; }
2424

2525
public long UploadedVolume { get; set; }
26+
27+
public int SkippedEntriesCount { get; set; }
2628

2729
public bool HasNonZeroProperty()
2830
{
@@ -36,6 +38,7 @@ public bool HasNonZeroProperty()
3638
|| AnalyzableVolume != 0
3739
|| IdentifiedVolume != 0
3840
|| UploadTotalVolume != 0
39-
|| UploadedVolume != 0;
41+
|| UploadedVolume != 0
42+
|| SkippedEntriesCount != 0;
4043
}
4144
}

src/ByteSync.Client/Business/Inventories/InventoryProcessData.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class InventoryProcessData : ReactiveObject
1414
private readonly object _monitorDataLock = new object();
1515
private readonly ConcurrentQueue<SkippedEntry> _skippedEntries = new();
1616
private readonly ConcurrentDictionary<SkipReason, int> _skippedCountsByReason = new();
17-
private int _skippedCount;
1817

1918
public InventoryProcessData()
2019
{
@@ -72,11 +71,11 @@ public InventoryProcessData()
7271
Reset();
7372
}
7473

75-
public List<IInventoryBuilder>? InventoryBuilders { get; set; }
74+
public List<IInventoryBuilder> InventoryBuilders { get; set; } = [];
7675

77-
public List<Inventory>? Inventories
76+
public List<Inventory> GetInventories()
7877
{
79-
get { return InventoryBuilders?.Select(ib => ib.Inventory).ToList(); }
78+
return InventoryBuilders.Select(ib => ib.Inventory).ToList();
8079
}
8180

8281
public CancellationTokenSource CancellationTokenSource { get; private set; }
@@ -107,7 +106,7 @@ public List<Inventory>? Inventories
107106

108107
public IReadOnlyCollection<SkippedEntry> SkippedEntries => _skippedEntries.ToArray();
109108

110-
public int SkippedCount => _skippedCount;
109+
public int SkippedCount => _skippedCountsByReason.Values.Sum();
111110

112111
[Reactive]
113112
public DateTimeOffset InventoryStart { get; set; }
@@ -146,7 +145,7 @@ public void RecordSkippedEntry(SkippedEntry entry)
146145
{
147146
_skippedEntries.Enqueue(entry);
148147
_skippedCountsByReason.AddOrUpdate(entry.Reason, 1, (_, currentCount) => currentCount + 1);
149-
Interlocked.Increment(ref _skippedCount);
148+
UpdateMonitorData(m => { m.SkippedEntriesCount += 1; });
150149
}
151150

152151
// should be used during issue 268 implementation
@@ -175,11 +174,8 @@ public void UpdateMonitorData(Action<InventoryMonitorData> action)
175174

176175
private void ClearSkippedEntries()
177176
{
178-
while (_skippedEntries.TryDequeue(out _))
179-
{
180-
}
177+
_skippedEntries.Clear();
181178

182179
_skippedCountsByReason.Clear();
183-
Interlocked.Exchange(ref _skippedCount, 0);
184180
}
185-
}
181+
}

src/ByteSync.Client/Business/Inventories/InventoryStatistics.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ public record InventoryStatistics
1111
public int AnalyzeErrors { get; init; }
1212

1313
public int IdentificationErrors { get; init; }
14+
15+
public int TotalSkippedEntries { get; init; }
1416
}

src/ByteSync.Client/Services/Inventories/BaseInventoryRunner.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task<bool> RunBaseInventory()
3232
bool isOK;
3333
try
3434
{
35-
await Parallel.ForEachAsync(InventoryProcessData.InventoryBuilders!,
35+
await Parallel.ForEachAsync(InventoryProcessData.InventoryBuilders,
3636
new ParallelOptions { MaxDegreeOfParallelism = 2, CancellationToken = InventoryProcessData.CancellationTokenSource.Token },
3737
async (builder, token) =>
3838
{
@@ -46,7 +46,7 @@ await Parallel.ForEachAsync(InventoryProcessData.InventoryBuilders!,
4646
{
4747
InventoryProcessData.IdentificationStatus.OnNext(InventoryTaskStatus.Success);
4848

49-
await _inventoryFinishedService.SetLocalInventoryFinished(InventoryProcessData.Inventories!, LocalInventoryModes.Base);
49+
await _inventoryFinishedService.SetLocalInventoryFinished(InventoryProcessData.GetInventories(), LocalInventoryModes.Base);
5050
}
5151

5252
isOK = true;
@@ -66,4 +66,4 @@ await Parallel.ForEachAsync(InventoryProcessData.InventoryBuilders!,
6666

6767
return isOK;
6868
}
69-
}
69+
}

src/ByteSync.Client/Services/Inventories/FullInventoryRunner.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public async Task<bool> RunFullInventory()
4444
await _sessionMemberService.UpdateCurrentMemberGeneralStatus(SessionMemberGeneralStatus.InventoryRunningAnalysis);
4545

4646
var inventoriesBuildersAndItems = new List<Tuple<IInventoryBuilder, HashSet<IndexedItem>>>();
47-
foreach (var inventoryBuilder in InventoryProcessData.InventoryBuilders!)
47+
foreach (var inventoryBuilder in InventoryProcessData.InventoryBuilders)
4848
{
4949
using var inventoryComparer =
5050
_inventoryComparerFactory.CreateInventoryComparer(LocalInventoryModes.Base, inventoryBuilder.InventoryIndexer);
@@ -87,7 +87,7 @@ await Parallel.ForEachAsync(inventoriesBuildersAndItems,
8787
else
8888
{
8989
InventoryProcessData.AnalysisStatus.OnNext(InventoryTaskStatus.Success);
90-
await _inventoryFinishedService.SetLocalInventoryFinished(InventoryProcessData.Inventories!, LocalInventoryModes.Full);
90+
await _inventoryFinishedService.SetLocalInventoryFinished(InventoryProcessData.GetInventories(), LocalInventoryModes.Full);
9191
InventoryProcessData.MainStatus.OnNext(InventoryTaskStatus.Success);
9292
}
9393

src/ByteSync.Client/Services/Inventories/InventoryStatisticsService.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ namespace ByteSync.Services.Inventories;
1111

1212
public class InventoryStatisticsService : IInventoryStatisticsService
1313
{
14-
private readonly IInventoryService _inventoryService;
1514
private readonly IInventoryFileRepository _inventoryFileRepository;
1615
private readonly ILogger<InventoryStatisticsService> _logger;
1716

@@ -20,13 +19,12 @@ public class InventoryStatisticsService : IInventoryStatisticsService
2019
public InventoryStatisticsService(IInventoryService inventoryService, IInventoryFileRepository inventoryFileRepository,
2120
ILogger<InventoryStatisticsService> logger)
2221
{
23-
_inventoryService = inventoryService;
2422
_inventoryFileRepository = inventoryFileRepository;
2523
_logger = logger;
2624

2725
_statisticsSubject = new BehaviorSubject<InventoryStatistics?>(null);
2826

29-
_inventoryService.InventoryProcessData.AreFullInventoriesComplete
27+
inventoryService.InventoryProcessData.AreFullInventoriesComplete
3028
.DistinctUntilChanged()
3129
.SelectMany(isComplete =>
3230
isComplete
@@ -66,7 +64,8 @@ private void DoCompute()
6664
ProcessedVolume = statsCollector.ProcessedSize,
6765
AnalyzeSuccess = statsCollector.Success,
6866
AnalyzeErrors = statsCollector.Errors,
69-
IdentificationErrors = statsCollector.IdentificationErrors
67+
IdentificationErrors = statsCollector.IdentificationErrors,
68+
TotalSkippedEntries = statsCollector.TotalSkippedEntries
7069
};
7170

7271
_statisticsSubject.OnNext(stats);
@@ -81,6 +80,8 @@ private void ProcessInventoryFile(InventoryFile inventoryFile, StatisticsCollect
8180

8281
foreach (var part in inventory.InventoryParts)
8382
{
83+
collector.TotalSkippedEntries += part.SkippedCount;
84+
8485
foreach (var dir in part.DirectoryDescriptions)
8586
{
8687
if (!dir.IsAccessible)
@@ -133,7 +134,7 @@ private static bool HasValidFingerprint(FileDescription fd)
133134
return !string.IsNullOrEmpty(fd.Sha256) || !string.IsNullOrEmpty(fd.SignatureGuid);
134135
}
135136

136-
private class StatisticsCollector
137+
private sealed class StatisticsCollector
137138
{
138139
public int TotalAnalyzed { get; set; }
139140

@@ -142,6 +143,8 @@ private class StatisticsCollector
142143
public int Errors { get; set; }
143144

144145
public int IdentificationErrors { get; set; }
146+
147+
public int TotalSkippedEntries { get; set; }
145148

146149
public long ProcessedSize { get; set; }
147150
}

src/ByteSync.Client/ViewModels/Sessions/Inventories/InventoryGlobalStatusViewModel.cs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ namespace ByteSync.ViewModels.Sessions.Inventories;
1717

1818
public class InventoryGlobalStatusViewModel : ActivatableViewModelBase
1919
{
20+
private const string MainSecondaryColorBrushKey = "MainSecondaryColor";
21+
private const string HomeCloudSynchronizationBackGroundBrushKey = "HomeCloudSynchronizationBackGround";
22+
2023
private readonly IInventoryService _inventoryService = null!;
2124
private readonly ISessionService _sessionService = null!;
2225
private readonly IDialogService _dialogService = null!;
@@ -79,10 +82,15 @@ public InventoryGlobalStatusViewModel(IInventoryService inventoryService, ISessi
7982

8083
[Reactive]
8184
public int? GlobalIdentificationErrors { get; set; }
85+
86+
[Reactive]
87+
public int? GlobalSkippedEntries { get; set; }
8288

8389
public extern bool HasErrors { [ObservableAsProperty] get; }
8490

8591
public extern bool HasIdentificationErrors { [ObservableAsProperty] get; }
92+
93+
public extern bool HasGlobalSkippedEntries { [ObservableAsProperty] get; }
8694

8795
[Reactive]
8896
public string GlobalMainIcon { get; set; } = "None";
@@ -112,6 +120,11 @@ private void SetupBasicProperties(CompositeDisposable disposables)
112120
.Select(e => (e ?? 0) > 0)
113121
.ToPropertyEx(this, x => x.HasIdentificationErrors)
114122
.DisposeWith(disposables);
123+
124+
this.WhenAnyValue(x => x.GlobalSkippedEntries)
125+
.Select(e => (e ?? 0) > 0)
126+
.ToPropertyEx(this, x => x.HasGlobalSkippedEntries)
127+
.DisposeWith(disposables);
115128
}
116129

117130
private ReactiveStreams CreateStreams(IInventoryStatisticsService inventoryStatisticsService, CompositeDisposable disposables)
@@ -200,7 +213,7 @@ private void SetupVisualElements(ReactiveStreams streams, CompositeDisposable di
200213
.DisposeWith(disposables);
201214
}
202215

203-
private IObservable<(string Icon, string Text, string BrushKey)> CreateNonSuccessVisual(
216+
private static IObservable<(string Icon, string Text, string BrushKey)> CreateNonSuccessVisual(
204217
IObservable<InventoryTaskStatus> statusStream)
205218
{
206219
return statusStream
@@ -210,7 +223,7 @@ private void SetupVisualElements(ReactiveStreams streams, CompositeDisposable di
210223
InventoryTaskStatus.Cancelled => Resources.InventoryProcess_InventoryCancelled,
211224
InventoryTaskStatus.Error => Resources.InventoryProcess_InventoryError,
212225
_ => Resources.InventoryProcess_InventoryError
213-
}, BrushKey: "MainSecondaryColor"));
226+
}, BrushKey: MainSecondaryColorBrushKey));
214227
}
215228

216229
private IObservable<(string Icon, string Text, string BrushKey)> CreateSuccessVisual(ReactiveStreams streams)
@@ -231,18 +244,18 @@ private void SetupVisualElements(ReactiveStreams streams, CompositeDisposable di
231244
.Select(t => GetSuccessVisualState(t.s.AnalyzeErrors));
232245
}
233246

234-
private (string Icon, string Text, string BrushKey) GetSuccessVisualState(int? errors)
247+
private static (string Icon, string Text, string BrushKey) GetSuccessVisualState(int? errors)
235248
{
236249
if (errors is > 0)
237250
{
238251
var text = Resources.ResourceManager.GetString("InventoryProcess_InventorySuccessWithErrors", Resources.Culture)
239252
?? Resources.InventoryProcess_InventorySuccess;
240253

241-
return (Icon: "RegularError", Text: text, BrushKey: "MainSecondaryColor");
254+
return (Icon: "RegularError", Text: text, BrushKey: MainSecondaryColorBrushKey);
242255
}
243256

244257
return (Icon: "SolidCheckCircle", Text: Resources.InventoryProcess_InventorySuccess,
245-
BrushKey: "HomeCloudSynchronizationBackGround");
258+
BrushKey: HomeCloudSynchronizationBackGroundBrushKey);
246259
}
247260

248261
private void SetupStatisticsSubscription(IInventoryStatisticsService inventoryStatisticsService,
@@ -270,6 +283,7 @@ private void UpdateStatisticsValues(InventoryStatistics? stats)
270283
GlobalAnalyzeSuccess = stats?.AnalyzeSuccess;
271284
GlobalAnalyzeErrors = stats?.AnalyzeErrors;
272285
GlobalIdentificationErrors = stats?.IdentificationErrors;
286+
GlobalSkippedEntries = stats?.TotalSkippedEntries;
273287
}
274288

275289
private void ApplySuccessState(int? errors, int? identificationErrors = null)
@@ -282,13 +296,13 @@ private void ApplySuccessState(int? errors, int? identificationErrors = null)
282296
?? Resources.InventoryProcess_InventorySuccess;
283297
GlobalMainIcon = "RegularError";
284298
GlobalMainStatusText = text;
285-
GlobalMainIconBrush = _themeService.GetBrush("MainSecondaryColor");
299+
GlobalMainIconBrush = _themeService.GetBrush(MainSecondaryColorBrushKey);
286300
}
287301
else
288302
{
289303
GlobalMainIcon = "SolidCheckCircle";
290304
GlobalMainStatusText = Resources.InventoryProcess_InventorySuccess;
291-
GlobalMainIconBrush = _themeService.GetBrush("HomeCloudSynchronizationBackGround");
305+
GlobalMainIconBrush = _themeService.GetBrush(HomeCloudSynchronizationBackGroundBrushKey);
292306
}
293307
}
294308

@@ -332,6 +346,7 @@ private void ResetStatistics()
332346
GlobalAnalyzeSuccess = null;
333347
GlobalAnalyzeErrors = null;
334348
GlobalIdentificationErrors = null;
349+
GlobalSkippedEntries = null;
335350
GlobalMainIcon = "None";
336351
GlobalMainStatusText = string.Empty;
337352
GlobalMainIconBrush = null;
@@ -363,21 +378,19 @@ private void UpdateGlobalMainIconBrush()
363378
case InventoryTaskStatus.Error:
364379
case InventoryTaskStatus.Cancelled:
365380
case InventoryTaskStatus.NotLaunched:
366-
GlobalMainIconBrush = _themeService.GetBrush("MainSecondaryColor");
381+
GlobalMainIconBrush = _themeService.GetBrush(MainSecondaryColorBrushKey);
367382

368383
break;
369384
case InventoryTaskStatus.Success:
370385
var errors = GlobalAnalyzeErrors ?? 0;
371386
var identificationErrors = GlobalIdentificationErrors ?? 0;
372387
GlobalMainIconBrush = (errors + identificationErrors) > 0
373-
? _themeService.GetBrush("MainSecondaryColor")
374-
: _themeService.GetBrush("HomeCloudSynchronizationBackGround");
388+
? _themeService.GetBrush(MainSecondaryColorBrushKey)
389+
: _themeService.GetBrush(HomeCloudSynchronizationBackGroundBrushKey);
375390

376391
break;
377-
case InventoryTaskStatus.Pending:
378-
case InventoryTaskStatus.Running:
379392
default:
380-
GlobalMainIconBrush = _themeService.GetBrush("HomeCloudSynchronizationBackGround");
393+
GlobalMainIconBrush = _themeService.GetBrush(HomeCloudSynchronizationBackGroundBrushKey);
381394

382395
break;
383396
}
@@ -398,7 +411,7 @@ private async Task AbortInventory()
398411
}
399412
}
400413

401-
private record ReactiveStreams(
414+
private sealed record ReactiveStreams(
402415
IObservable<InventoryTaskStatus> StatusStream,
403416
IObservable<SessionStatus> SessionPreparation,
404417
IObservable<InventoryStatistics?> StatsStream,

0 commit comments

Comments
 (0)