Code
·
151 lines
·
4940 bytes
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151using MailSharp.MailClient.Services;
using MailSharp.MailClient.Services.Logging;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace MailSharp.MailClient.Controllers.Api;
[ApiController]
[Route("api/maintenance")]
[Authorize(Policy = "AdminOnly")]
public class MaintenanceApiController(
ILogStore logStore,
IAccountStore accountStore,
IMessageIndexStore indexStore,
IFolderSettingsStore folderSettingsStore,
IMailCacheStore mailCacheStore,
IBackgroundIndexingStatus indexingStatus) : ControllerBase
{
[HttpGet("logs")]
public IActionResult Logs(
LogLevel? level = null,
string? category = null,
int? accountId = null,
DateTime? from = null,
DateTime? to = null,
string? search = null,
int page = 1,
int pageSize = 50)
{
var result = logStore.Query(new LogQuery
{
Level = level,
Category = category,
AccountId = accountId,
From = from,
To = to,
Search = search,
Page = page,
PageSize = pageSize
});
return Ok(new { items = result.Items, totalCount = result.TotalCount, page, pageSize });
}
[HttpPost("logs/clear")]
public IActionResult ClearLogs()
{
logStore.Clear();
return Ok();
}
[HttpGet("status")]
public IActionResult Status()
{
// Per-account/folder index summary (accounts, indexed folders, total messages) - the same
// underlying data as the Metrics tab, but rolled up to totals here rather than shown
// per-folder, since this panel is about "is the background work healthy", not the folder
// browser the Metrics tab already is.
var accounts = accountStore.GetAll();
var indexSummaries = accounts.Select(account =>
{
var folders = indexStore.GetIndexedFolders(account.Id);
return new
{
accountId = account.Id,
emailAddress = account.EmailAddress,
indexedFolderCount = folders.Count,
indexedMessageCount = folders.Sum(f => indexStore.GetMessageCount(account.Id, f)),
indexedSizeBytes = folders.Sum(f => indexStore.GetTotalSize(account.Id, f))
};
}).ToList();
var cache = mailCacheStore.GetStats();
return Ok(new
{
indexing = new
{
maxConcurrentIndexing = indexingStatus.MaxConcurrentIndexing,
currentlyAvailableSlots = indexingStatus.CurrentlyAvailableSlots,
inProgress = indexingStatus.InProgressKeys.Select(key =>
{
indexingStatus.TryGetProgress(key, out var processed, out var total);
return new { key, processed, total };
})
},
index = new
{
accounts = indexSummaries,
totalIndexedFolders = indexSummaries.Sum(a => a.indexedFolderCount),
totalIndexedMessages = indexSummaries.Sum(a => a.indexedMessageCount),
totalIndexedSizeBytes = indexSummaries.Sum(a => a.indexedSizeBytes)
},
cache = new
{
messageListCacheEntries = cache.MessageListCacheEntries,
contactMailSearchEntries = cache.ContactMailSearchEntries,
senderImagePreferences = cache.SenderImagePreferences,
imageUrlMappings = cache.ImageUrlMappings,
messageIdMappings = cache.MessageIdMappings,
cachedMessages = new { fileCount = cache.CachedMessages.FileCount, totalBytes = cache.CachedMessages.TotalBytes },
cachedAttachments = new { fileCount = cache.CachedAttachments.FileCount, totalBytes = cache.CachedAttachments.TotalBytes },
cachedImages = new { fileCount = cache.CachedImages.FileCount, totalBytes = cache.CachedImages.TotalBytes }
}
});
}
[HttpGet("metrics")]
public IActionResult Metrics(int? accountId = null)
{
var accounts = accountStore.GetAll()
.Where(a => accountId == null || a.Id == accountId.Value)
.Select(account =>
{
// Same display order the user set up in Settings > Mappen beheren (see
// IImapService.GetFoldersAsync/ApplyDisplayOrder) - folders the user dragged to the
// top there should show in that order here too, not in whatever order LiteDB happens
// to return them.
var savedOrder = folderSettingsStore.GetOrder(account.Id);
var position = savedOrder.Select((name, i) => (name, i)).ToDictionary(x => x.name, x => x.i, StringComparer.Ordinal);
var folders = indexStore.GetIndexedFolders(account.Id)
.Select((folder, naturalIndex) => (folder, naturalIndex))
.OrderBy(x => position.TryGetValue(x.folder, out var idx) ? idx : int.MaxValue)
.ThenBy(x => x.naturalIndex)
.Select(x => new
{
folder = x.folder,
messageCount = indexStore.GetMessageCount(account.Id, x.folder),
sizeBytes = indexStore.GetTotalSize(account.Id, x.folder)
}).ToList();
return new
{
accountId = account.Id,
emailAddress = account.EmailAddress,
folders,
totalMessages = folders.Sum(f => f.messageCount),
totalSizeBytes = folders.Sum(f => f.sizeBytes)
};
}).ToList();
return Ok(new
{
accounts,
totalMessages = accounts.Sum(a => a.totalMessages),
totalSizeBytes = accounts.Sum(a => a.totalSizeBytes)
});
}
}