Skip to content

Commit 66abcd2

Browse files
committed
💾 Feat(SyncCodes): Better way to compare differences
1 parent fc0dd6e commit 66abcd2

File tree

3 files changed

+97
-53
lines changed

3 files changed

+97
-53
lines changed

‎Utils/SyncCodes/Context.cs

+35-20
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public class Context
1212

1313
private readonly ILogger _logger;
1414

15+
private readonly object _filesLock = new();
16+
1517
public Context(string workBase, ILogger logger)
1618
{
1719
WorkBase = workBase;
@@ -53,38 +55,51 @@ public Context InitializeFileSystemWatcher(Action<FileSystemEventArgs> onChanged
5355
return this;
5456
}
5557

56-
public List<FileItem> GetFiles() => Files;
58+
public List<FileItem> GetFiles()
59+
{
60+
lock (_filesLock)
61+
{
62+
return Files;
63+
}
64+
}
5765

5866
public void RefreshFiles()
5967
{
6068
var folder = new DirectoryInfo(WorkBase);
6169

62-
Files.Clear();
63-
Files.AddRange(
64-
folder.GetFiles()
65-
.Where(f => Filter.ShouldIgnore(f.FullName) == false)
66-
.Select(
67-
f => new FileItem(
68-
Path.GetRelativePath(WorkBase, f.FullName)
69-
)
70-
)
71-
.Where(f => f.FileLoaded)
72-
);
73-
74-
var foldersToSearch = new Queue<DirectoryInfo>(folder.GetDirectories());
75-
while (foldersToSearch.Count > 0)
70+
lock (_filesLock)
7671
{
77-
var subFolder = foldersToSearch.Dequeue();
78-
foreach (var dir in subFolder.GetDirectories())
79-
foldersToSearch.Enqueue(dir);
72+
Files.Clear();
8073
Files.AddRange(
81-
subFolder.GetFiles()
74+
folder.GetFiles()
8275
.Where(f => Filter.ShouldIgnore(f.FullName) == false)
8376
.Select(
84-
f => new FileItem(Path.GetRelativePath(WorkBase, f.FullName))
77+
f => new FileItem(
78+
Path.GetRelativePath(WorkBase, f.FullName),
79+
_logger
80+
)
8581
)
8682
.Where(f => f.FileLoaded)
8783
);
84+
85+
var foldersToSearch = new Queue<DirectoryInfo>(folder.GetDirectories());
86+
while (foldersToSearch.Count > 0)
87+
{
88+
var subFolder = foldersToSearch.Dequeue();
89+
foreach (var dir in subFolder.GetDirectories())
90+
foldersToSearch.Enqueue(dir);
91+
Files.AddRange(
92+
subFolder.GetFiles()
93+
.Where(f => Filter.ShouldIgnore(f.FullName) == false)
94+
.Select(
95+
f => new FileItem(
96+
Path.GetRelativePath(WorkBase, f.FullName),
97+
_logger
98+
)
99+
)
100+
.Where(f => f.FileLoaded)
101+
);
102+
}
88103
}
89104
}
90105

‎Utils/SyncCodes/FileItem.cs

+17-10
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,43 @@
11
using System.Security.Cryptography;
22
using System.Text;
33
using System.Text.Json.Serialization;
4+
using Polly;
45

56
namespace SyncCodes;
67

78
public class FileItem
89
{
910
public string Path { get; }
1011

11-
public string Hash { get; }
12+
public string Hash { get; set; }
1213

1314
[JsonIgnore] public bool FileLoaded { get; set; }
1415

15-
public FileItem(string path)
16+
private readonly ILogger _logger;
17+
18+
public FileItem(string path, ILogger logger)
1619
{
1720
Path = path;
1821

22+
_logger = logger;
23+
1924
// Avoid file not exists exception, sometimes IDE creates temporary files
20-
try
25+
Policy.Handle<Exception>().Retry(3, (exception, retryCount) =>
26+
{
27+
_logger.LogError(
28+
"Error loading sync ignore file: {message}, try times: {retryCount}",
29+
exception.Message,
30+
retryCount
31+
);
32+
33+
}).Execute(() =>
2134
{
2235
var content = File.ReadAllText(Path);
2336
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(content));
2437
Hash = Convert.ToBase64String(hash);
2538

2639
FileLoaded = true;
27-
}
28-
catch (Exception e)
29-
{
30-
Hash = string.Empty;
31-
32-
FileLoaded = false;
33-
}
40+
});
3441
}
3542
}
3643

‎Utils/SyncCodes/Program.cs

+45-23
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
using System.Text.Json;
33
using System.Text.RegularExpressions;
44
using CommandLine;
5+
using Polly;
56
using Spectre.Console;
67
using SyncCodes;
8+
using Context = SyncCodes.Context;
79
using Timer = System.Timers.Timer;
810

911
var workBase = Directory.GetCurrentDirectory();
@@ -30,6 +32,21 @@
3032

3133
var context = new Context(workBase, app.Logger);
3234

35+
context.InitializeFileSystemWatcher(
36+
(e) =>
37+
{
38+
if (context.Filter.ShouldIgnore(e.FullPath) == false)
39+
app.Logger.LogInformation(
40+
"[{time}] FileSystem Modified: {name}, {changeType} | {path}",
41+
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
42+
e.Name,
43+
e.ChangeType,
44+
Path.GetRelativePath(workBase, e.FullPath)
45+
);
46+
context.RefreshFiles();
47+
}
48+
);
49+
3350
switch (options.Job)
3451
{
3552
case Jobs.FetchCodes:
@@ -49,21 +66,6 @@
4966

5067
void RunServer(Context context)
5168
{
52-
context.InitializeFileSystemWatcher(
53-
(e) =>
54-
{
55-
if (context.Filter.ShouldIgnore(e.FullPath) == false)
56-
app.Logger.LogInformation(
57-
"FileSystem Modified: {name}, {changeType} | {path}, [{time}]",
58-
e.Name,
59-
e.ChangeType,
60-
Path.GetRelativePath(workBase, e.FullPath),
61-
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
62-
);
63-
context.RefreshFiles();
64-
}
65-
);
66-
6769
app.MapGet(
6870
"/",
6971
() => Results.Content(
@@ -98,8 +100,6 @@ void RunServer(Context context)
98100

99101
void RunClient(Context context)
100102
{
101-
context.InitializeFileSystemWatcher((_) => context.RefreshFiles());
102-
103103
var address = AnsiConsole.Prompt(new TextPrompt<string>("Please input the server address: ")
104104
{
105105
Validator = (s) => ServerAddressRegex().IsMatch(s)
@@ -138,20 +138,32 @@ await catalogResponse.Content.ReadAsStringAsync(),
138138
var localCatalog = context.GetFiles();
139139

140140
var differences = catalog.Concat(localCatalog).GroupBy(
141-
f => f.Path,
141+
f => f.Path.RelatedTo(workBase),
142142
f => f.Hash,
143143
(path, hashes) => new
144144
{
145145
Path = path,
146146
Count = hashes.Count(),
147-
LocalHash = localCatalog.FirstOrDefault(f => f.Path.Equals(path))?.Hash,
148-
RemoteHash = catalog.FirstOrDefault(f => f.Path.Equals(path))?.Hash,
147+
LocalHash = localCatalog.FirstOrDefault(f => f.Path.RelatedTo(workBase).Equals(path))?.Hash,
148+
RemoteHash = catalog.FirstOrDefault(f => f.Path.RelatedTo(workBase).Equals(path))?.Hash,
149149
}
150150
);
151151

152-
// app.Logger.LogInformation("Need to fetch: {json}", JsonSerializer.Serialize(needToFetch, jsonSerializerOptions));
153-
// app.Logger.LogInformation("Need to delete:: {json}", JsonSerializer.Serialize(needToDelete, jsonSerializerOptions));
154-
app.Logger.LogDebug("Differences: {json}", JsonSerializer.Serialize(differences));
152+
app.Logger.LogInformation(
153+
"Remote: {json1}\n Local: {json2}\n Differences: {json3}",
154+
JsonSerializer.Serialize(
155+
differences.Where(c => c.LocalHash is null && c.RemoteHash is not null),
156+
jsonSerializerOptions
157+
),
158+
JsonSerializer.Serialize(
159+
differences.Where(c => c.RemoteHash is null && c.LocalHash is not null),
160+
jsonSerializerOptions
161+
),
162+
JsonSerializer.Serialize(
163+
differences.Where(c => c.LocalHash is not null && c.RemoteHash is not null && !c.LocalHash.Equals(c.RemoteHash)),
164+
jsonSerializerOptions
165+
)
166+
);
155167
};
156168
timer.Start();
157169

@@ -165,6 +177,11 @@ await catalogResponse.Content.ReadAsStringAsync(),
165177
)
166178
);
167179

180+
app.MapGet(
181+
"/catalog",
182+
() => context.GetFiles().Where(f => f.FileLoaded)
183+
);
184+
168185
app.Run();
169186
}
170187

@@ -198,3 +215,8 @@ partial class Program
198215
[GeneratedRegex(@"([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|(\[[0-9A-Fa-f:.]+\])|([a-zA-Z0-9.-]+)(:\d+)?")]
199216
private static partial Regex ServerAddressRegex();
200217
}
218+
219+
public static class Extensions
220+
{
221+
public static string RelatedTo(this string path, string workBase) => Path.GetRelativePath(workBase, Path.Combine(workBase, path));
222+
}

0 commit comments

Comments
 (0)