dbMango/Rms.Risk.Mango/Components/DatabaseInfo.razor
Alexander Shabarshov 2a7a24c9e7 Initial contribution
2025-11-03 14:43:26 +00:00

208 lines
5.4 KiB
Plaintext

@using System.Text.RegularExpressions
@attribute [Authorize]
@inject IMongoDbServiceFactory MongoDbServiceFactory
@inject IUserSession UserSession
@inject IAuthorizationService Auth
@if (Error != null)
@*
* dbMango
*
* Copyright 2025 Deutsche Bank AG
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*@
{
<ExceptionControl Exception="@Error"/>
}
else if (_loading)
{
<ProgressSpinner/>
}
else
{
<table>
@foreach (var item in _stats.Where(x => !_exclude.Contains(x.Key)))
{
<tr> <td><div class="mr-4">@(FormatName(item)):</div></td> <td><div class="text-right">@FormatValue(item)</div></td> </tr>
}
</table>
}
@code {
/// <summary>
/// This parameter value is unused, but any change initiating stats reloading
/// </summary>
[Parameter]
public string? Database
{
get;
set
{
if (field == value)
return;
field = value;
InvokeAsync(StateHasChanged);
}
}
/// <summary>
/// This parameter value is unused, but any change initiating stats reloading
/// </summary>
[Parameter]
public string? DatabaseInstance
{
get;
set
{
if (field == value)
return;
field = value;
InvokeAsync(StateHasChanged);
}
}
private Dictionary<string, object> _stats = new();
private string _loadedFor = "";
private Exception? Error { get; set; }
private bool _loading;
private HashSet<string> _exclude =
[
"raw",
"ok",
"$clusterTime",
"operationTime",
];
protected override Task OnAfterRenderAsync(bool firstRender)
{
var loadingFor = $"{UserSession.Database},{UserSession.DatabaseInstance}";
if (_loading || _loadedFor == loadingFor)
return Task.CompletedTask;
_ = Task.Run(Refresh);
return Task.CompletedTask;
}
private async Task Refresh()
{
var loadingFor = $"{UserSession.Database},{UserSession.DatabaseInstance}";
if (_loading || _loadedFor == loadingFor)
return;
_loading = true;
_loadedFor = loadingFor;
try
{
Error = null;
_stats.Clear();
await InvokeAsync(StateHasChanged);
await RefreshInternal();
}
catch (Exception e)
{
Error = e;
}
finally
{
_loading = false;
}
await InvokeAsync(StateHasChanged);
}
private async Task RefreshInternal()
{
var admin = UserSession.DatabaseInstance == null
? UserSession.MongoDbAdminForAdminDatabase
: UserSession.MongoDbAdmin
;
var stats = await admin.RunCommand(
BsonDocument.Parse( @"{
dbStats: 1,
scale: 1,
freeStorage: 0
}"));
_stats = stats.ToDictionary();
var readAccess = await Auth.AuthorizeAsync(
UserSession.User.GetUser(),
Database,
[new ReadAccessRequirement()]);
var writeAccess = await Auth.AuthorizeAsync(
UserSession.User.GetUser(),
Database,
[new WriteAccessRequirement()]);
var adminAccess = await Auth.AuthorizeAsync(
UserSession.User.GetUser(),
Database,
[new AdminAccessRequirement()]);
_stats["Read access"] = readAccess.Succeeded;
_stats["Write access"] = writeAccess.Succeeded;
_stats["Admin access"] = adminAccess.Succeeded;
}
private static HashSet<string> _byteMeasures =
[
"avgObjSize",
"dataSize",
"storageSize",
"totalSize",
"indexSize",
"fileSize",
"fsUsedSize",
"fsTotalSize",
];
private static HashSet<string> _numberMeasures =
[
"objects",
"indexes",
"scaleFactor",
];
private static string SplitCamelCase(string input)
{
return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
}
private string FormatName(KeyValuePair<string, object> item)
{
var s = SplitCamelCase(item.Key)
.Split(" ", StringSplitOptions.RemoveEmptyEntries)
.Select((x, i) => i == 0 ? char.ToUpper(x[0]) + x[1..] : char.ToLower(x[0]) + x[1..])
;
return string.Join(" ", s);
}
private string FormatValue(KeyValuePair<string, object> item)
{
if (_byteMeasures.Contains(item.Key))
return NumbersUtils.ToHumanReadable(Convert.ToDouble(item.Value));
if (_numberMeasures.Contains(item.Key))
return Convert.ToDouble(item.Value).ToString("N0");
return item.Value?.ToString() ?? "";
}
}