| Name | Message | Date |
|---|---|---|
| 📄 AppSettings.cs | 4 days ago | |
| 📄 NoteCacheJsonContext.cs | 4 days ago | |
| 📄 NoteCacheStore.cs | 4 days ago | |
| 📄 NoteContentCache.cs | 3 days ago | |
| 📄 NotePreviewBuilder.cs | 3 days ago |
📄
src/Storage/NoteContentCache.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace NotesApp.Storage; // Full note bodies fetched during this app process, keyed by note id. Storing the in-flight // Task<string> itself (not just the eventual result) lets a prefetch and an on-demand open of // the same note share one Graph request instead of racing two - whichever asks first starts // the fetch, and both awaiters land on the same task. In-memory only, unlike NoteCacheStore's // list metadata: full bodies for 1000+ notes aren't worth persisting to disk, and staleness // only matters for the current process's lifetime. public static class NoteContentCache { private static readonly Dictionary<string, Task<string>> Cache = new(); // Raised whenever a fetch started via GetOrStart completes successfully - whether that // fetch was a background prefetch or an on-demand open. Listeners (the note list) use this // to refresh a row's preview with the real content instead of the byte-range-truncated one // from GetPreviewsAsync. Not raised by Set(), since a save's caller already knows the fresh // preview and updates the list itself through the normal result-passback path. public static event Action<string, string>? ContentFetched; public static bool TryGet(string noteId, out Task<string> contentTask) => Cache.TryGetValue(noteId, out contentTask!); // Returns the existing fetch for this note if one's already running or done; otherwise // starts one via startFetch and caches it. Never starts a second fetch for the same note. public static Task<string> GetOrStart(string noteId, Func<Task<string>> startFetch) { if (Cache.TryGetValue(noteId, out var existing)) return existing; var task = Track(noteId, startFetch()); Cache[noteId] = task; return task; } public static void Set(string noteId, string content) => Cache[noteId] = Task.FromResult(content); public static void Remove(string noteId) => Cache.Remove(noteId); private static async Task<string> Track(string noteId, Task<string> fetch) { try { var content = await fetch; ContentFetched?.Invoke(noteId, content); return content; } catch { // A cached failed task would otherwise wedge that note - every future open/prefetch // would rethrow the same stale error instead of retrying. Cache.Remove(noteId); throw; } } }