Implement telemetry system with data collection and reporting
Signed-off-by: Dmitrii <computer@yawaflua.tech> Took 20 minutes
This commit is contained in:
@@ -20,6 +20,7 @@ namespace SpMega.Backend.Controllers.v1;
|
||||
|
||||
public record GetSessionIdBody(string userName, Guid userUUID);
|
||||
public record ValidateSessionBody(string sessionId, Guid userUUID);
|
||||
|
||||
[Route("api/v1/auth")]
|
||||
[ApiController]
|
||||
public class AuthController(AppDbContext dbContext, TokenService tokenService, ILogger<AuthController> logger) : ControllerBase
|
||||
@@ -67,7 +68,7 @@ public class AuthController(AppDbContext dbContext, TokenService tokenService, I
|
||||
|
||||
var resp = await httpClient.SendAsync(request);
|
||||
if (resp.StatusCode != HttpStatusCode.OK) throw new Exception("Mojang response is not OK");
|
||||
Console.WriteLine(await resp.Content.ReadAsStringAsync());
|
||||
|
||||
var dto = await resp.Content.ReadFromJsonAsync<MojangDto>();
|
||||
if (dto == null || dto.Name != session.UserName || Guid.Parse(dto.Id) != session.UserId) throw new Exception("Session expired, or dto is not acceptable.");
|
||||
var token = tokenService.GenerateAccessToken(session.UserName, body.userUUID);
|
||||
@@ -75,6 +76,9 @@ public class AuthController(AppDbContext dbContext, TokenService tokenService, I
|
||||
if (user != null)
|
||||
{
|
||||
user.Token = token;
|
||||
user.Username = session.UserName;
|
||||
user.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
dbContext.Update(user);
|
||||
}
|
||||
else
|
||||
@@ -84,6 +88,7 @@ public class AuthController(AppDbContext dbContext, TokenService tokenService, I
|
||||
Id = body.userUUID,
|
||||
Username = session.UserName,
|
||||
Token = token,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
};
|
||||
await dbContext.AddAsync(user);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SpMega.Backend.Persistent.Models.DTO;
|
||||
using SpMega.Backend.Persistent.Models.Users;
|
||||
|
||||
namespace SpMega.Backend.Controllers.v1;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/v1/telemetry")]
|
||||
public class TelemetryController : ControllerBase
|
||||
{
|
||||
private static readonly ActivitySource Source = new("SpMega.ModTelemetry");
|
||||
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public IActionResult Post([FromBody] ModTelemetryBatchDto batch)
|
||||
{
|
||||
if (batch?.Events == null || batch.Events.Count == 0)
|
||||
{
|
||||
return Ok(new { received = 0 });
|
||||
}
|
||||
|
||||
var user = HttpContext.Items["@me"] as User;
|
||||
var userId = user?.Id.ToString() ?? User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "anonymous";
|
||||
var sessionId = !string.IsNullOrEmpty(batch.SessionId) ? batch.SessionId : Guid.NewGuid().ToString("N");
|
||||
|
||||
foreach (var e in batch.Events)
|
||||
{
|
||||
using var activity = Source.StartActivity("mod.telemetry.event", ActivityKind.Internal);
|
||||
if (activity is null) continue;
|
||||
|
||||
activity.SetTag("user.id", userId);
|
||||
activity.SetTag("session.id", sessionId);
|
||||
activity.SetTag("client.version", batch.ClientVersion ?? string.Empty);
|
||||
activity.SetTag("event.type", e.EventType);
|
||||
activity.SetTag("event.timestamp", e.Timestamp.ToString("O"));
|
||||
activity.SetTag("event.payload", JsonSerializer.Serialize(e.Payload));
|
||||
activity.SetTag("batch.sent_at", batch.SentAt.ToString("O"));
|
||||
}
|
||||
|
||||
return Ok(new { received = batch.Events.Count });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SpMega.Backend.Middleware;
|
||||
|
||||
public class RequestTelemetryMiddleware(RequestDelegate next, ILogger<RequestTelemetryMiddleware> logger)
|
||||
{
|
||||
private static readonly ActivitySource Source = new("SpMega.RequestTelemetry");
|
||||
private const string RequestIdHeader = "X-Request-Id";
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
var path = context.Request.Path.Value ?? string.Empty;
|
||||
if (path.Equals("/api/v1/telemetry", StringComparison.OrdinalIgnoreCase)
|
||||
&& context.Request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var requestId = context.Request.Headers[RequestIdHeader].FirstOrDefault() ?? Guid.NewGuid().ToString("N");
|
||||
context.Response.Headers[RequestIdHeader] = requestId;
|
||||
|
||||
using var activity = Source.StartActivity("http.request", ActivityKind.Server);
|
||||
activity?.SetTag("request.id", requestId);
|
||||
activity?.SetTag("http.method", context.Request.Method);
|
||||
activity?.SetTag("http.path", path);
|
||||
activity?.SetTag("http.scheme", context.Request.Scheme);
|
||||
activity?.SetTag("http.host", context.Request.Host.Value ?? string.Empty);
|
||||
activity?.SetTag("client.ip", context.Connection.RemoteIpAddress?.ToString());
|
||||
activity?.SetTag("http.user_agent", context.Request.Headers.UserAgent.ToString());
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
stopwatch.Stop();
|
||||
activity?.SetTag("http.status_code", context.Response.StatusCode);
|
||||
activity?.SetTag("http.duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
|
||||
var userId = context.User?.Identity?.IsAuthenticated == true
|
||||
? context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
|
||||
: null;
|
||||
if (userId is not null)
|
||||
activity?.SetTag("user.id", userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MongoDB.EntityFrameworkCore.Extensions;
|
||||
using SpMega.Backend.Persistent.Models.Telemetry;
|
||||
using SpMega.Backend.Persistent.Models.Transactions;
|
||||
using SpMega.Backend.Persistent.Models.Users;
|
||||
using SpMega.Backend.Services;
|
||||
@@ -11,6 +12,8 @@ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(op
|
||||
internal DbSet<Transaction> Transactions { get; set; }
|
||||
internal DbSet<User> Users { get; set; }
|
||||
internal DbSet<UserSession> UserSessions { get; set; }
|
||||
internal DbSet<ModTelemetryDocument> ModTelemetry { get; set; }
|
||||
internal DbSet<BackendRequestTelemetryDocument> BackendRequestTelemetry { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SpMega.Backend.Persistent.Models.DTO;
|
||||
|
||||
public record ModTelemetryEventDto(
|
||||
string EventType,
|
||||
DateTimeOffset Timestamp,
|
||||
JsonElement Payload
|
||||
);
|
||||
|
||||
public record ModTelemetryBatchDto(
|
||||
string ClientVersion,
|
||||
string SessionId,
|
||||
DateTimeOffset SentAt,
|
||||
List<ModTelemetryEventDto> Events
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace SpMega.Backend.Persistent.Models.Telemetry;
|
||||
|
||||
public class BackendRequestTelemetryDocument
|
||||
{
|
||||
public ObjectId Id { get; set; }
|
||||
public string RequestId { get; set; } = string.Empty;
|
||||
public string Method { get; set; } = string.Empty;
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public string Scheme { get; set; } = string.Empty;
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public string? ClientIp { get; set; }
|
||||
public string? UserAgent { get; set; }
|
||||
public int StatusCode { get; set; }
|
||||
public long DurationMs { get; set; }
|
||||
public string? UserId { get; set; }
|
||||
public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace SpMega.Backend.Persistent.Models.Telemetry;
|
||||
|
||||
public class ModTelemetryDocument
|
||||
{
|
||||
public ObjectId Id { get; set; }
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
public string SessionId { get; set; } = string.Empty;
|
||||
public string ClientVersion { get; set; } = string.Empty;
|
||||
public DateTimeOffset SentAt { get; set; }
|
||||
public DateTimeOffset ReceivedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public List<ModTelemetryEventDocument> Events { get; set; } = [];
|
||||
}
|
||||
|
||||
public class ModTelemetryEventDocument
|
||||
{
|
||||
public string EventType { get; set; } = string.Empty;
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
public string PayloadJson { get; set; } = "{}";
|
||||
}
|
||||
@@ -3,7 +3,10 @@ using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MongoDB.Driver;
|
||||
using OpenTelemetry.Resources;
|
||||
using OpenTelemetry.Trace;
|
||||
using SpMega.Backend.Authetication;
|
||||
using SpMega.Backend.Middleware;
|
||||
using SpMega.Backend.Persistent.Database;
|
||||
using SpMega.Backend.Services;
|
||||
|
||||
@@ -56,18 +59,33 @@ public class Program
|
||||
.RequireAuthenticatedUser()
|
||||
.Build());
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var mongoClient =
|
||||
new MongoClient(builder.Configuration.GetValue<string>("Mongo") ?? "mongodb://curiosity:27018");
|
||||
serviceCollection.AddSingleton<IMongoClient>(mongoClient);
|
||||
|
||||
builder.Services.AddSingleton<IMongoClient>(mongoClient);
|
||||
|
||||
builder.Services.AddDbContext<AppDbContext>((_, options) =>
|
||||
{
|
||||
options.UseMongoDB(mongoClient, "spmega");
|
||||
});
|
||||
|
||||
var otlpEndpoint = conf["Otlp:Endpoint"] ?? "http://localhost:4317";
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.ConfigureResource(res => res.AddService("SpMega.Backend"))
|
||||
.WithTracing(tracing =>
|
||||
{
|
||||
tracing
|
||||
.AddSource("SpMega.ModTelemetry")
|
||||
.AddSource("SpMega.RequestTelemetry")
|
||||
.AddAspNetCoreInstrumentation()
|
||||
.AddOtlpExporter(opts =>
|
||||
{
|
||||
opts.Endpoint = new Uri(otlpEndpoint);
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseMiddleware<RequestTelemetryMiddleware>();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/api"), appBuilder =>
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.19.1" />
|
||||
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="10.0.2" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||
<PackageReference Include="spworlds-api" Version="1.0.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.19.1" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v10.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v10.0": {
|
||||
"SpMega.Backend/1.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": "10.0.9",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "10.0.9",
|
||||
"Microsoft.IdentityModel.Tokens": "8.19.1",
|
||||
"MongoDB.EntityFrameworkCore": "10.0.2",
|
||||
"System.IdentityModel.Tokens.Jwt": "8.19.1",
|
||||
"spworlds-api": "1.0.3"
|
||||
},
|
||||
"runtime": {
|
||||
"SpMega.Backend.dll": {}
|
||||
}
|
||||
},
|
||||
"DnsClient/1.6.1": {
|
||||
"runtime": {
|
||||
"lib/net5.0/DnsClient.dll": {
|
||||
"assemblyVersion": "1.6.1.0",
|
||||
"fileVersion": "1.6.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Bcl.Cryptography/10.0.2": {
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.Bcl.Cryptography.dll": {
|
||||
"assemblyVersion": "10.0.0.2",
|
||||
"fileVersion": "10.0.225.61305"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore/10.0.9": {
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": "10.0.9"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.EntityFrameworkCore.dll": {
|
||||
"assemblyVersion": "10.0.9.0",
|
||||
"fileVersion": "10.0.926.27113"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Abstractions/10.0.9": {
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll": {
|
||||
"assemblyVersion": "10.0.9.0",
|
||||
"fileVersion": "10.0.926.27113"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Relational/10.0.9": {
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "10.0.9"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.EntityFrameworkCore.Relational.dll": {
|
||||
"assemblyVersion": "10.0.9.0",
|
||||
"fileVersion": "10.0.926.27113"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Abstractions/8.19.1": {
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.IdentityModel.Abstractions.dll": {
|
||||
"assemblyVersion": "8.19.1.0",
|
||||
"fileVersion": "8.19.1.26153"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.JsonWebTokens/8.19.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Tokens": "8.19.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
|
||||
"assemblyVersion": "8.19.1.0",
|
||||
"fileVersion": "8.19.1.26153"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Logging/8.19.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Abstractions": "8.19.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.IdentityModel.Logging.dll": {
|
||||
"assemblyVersion": "8.19.1.0",
|
||||
"fileVersion": "8.19.1.26153"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Tokens/8.19.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.Cryptography": "10.0.2",
|
||||
"Microsoft.IdentityModel.Logging": "8.19.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/Microsoft.IdentityModel.Tokens.dll": {
|
||||
"assemblyVersion": "8.19.1.0",
|
||||
"fileVersion": "8.19.1.26153"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MongoDB.Bson/3.9.0": {
|
||||
"runtime": {
|
||||
"lib/net6.0/MongoDB.Bson.dll": {
|
||||
"assemblyVersion": "3.9.0.0",
|
||||
"fileVersion": "3.9.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MongoDB.Driver/3.9.0": {
|
||||
"dependencies": {
|
||||
"DnsClient": "1.6.1",
|
||||
"MongoDB.Bson": "3.9.0",
|
||||
"SharpCompress": "0.48.1",
|
||||
"Snappier": "1.3.1",
|
||||
"ZstdSharp.Port": "0.7.3"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net6.0/MongoDB.Driver.dll": {
|
||||
"assemblyVersion": "3.9.0.0",
|
||||
"fileVersion": "3.9.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MongoDB.EntityFrameworkCore/10.0.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "10.0.9",
|
||||
"MongoDB.Driver": "3.9.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/MongoDB.EntityFrameworkCore.dll": {
|
||||
"assemblyVersion": "10.0.2.0",
|
||||
"fileVersion": "10.0.2.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SharpCompress/0.48.1": {
|
||||
"runtime": {
|
||||
"lib/net10.0/SharpCompress.dll": {
|
||||
"assemblyVersion": "0.48.1.0",
|
||||
"fileVersion": "0.48.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Snappier/1.3.1": {
|
||||
"runtime": {
|
||||
"lib/net8.0/Snappier.dll": {
|
||||
"assemblyVersion": "1.3.1.0",
|
||||
"fileVersion": "1.3.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"spworlds-api/1.0.3": {
|
||||
"runtime": {
|
||||
"lib/net8.0/spworlds-api.dll": {
|
||||
"assemblyVersion": "1.0.3.0",
|
||||
"fileVersion": "1.0.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.IdentityModel.Tokens.Jwt/8.19.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.JsonWebTokens": "8.19.1",
|
||||
"Microsoft.IdentityModel.Tokens": "8.19.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/System.IdentityModel.Tokens.Jwt.dll": {
|
||||
"assemblyVersion": "8.19.1.0",
|
||||
"fileVersion": "8.19.1.26153"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ZstdSharp.Port/0.7.3": {
|
||||
"runtime": {
|
||||
"lib/net7.0/ZstdSharp.dll": {
|
||||
"assemblyVersion": "0.7.3.0",
|
||||
"fileVersion": "0.7.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"SpMega.Backend/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"DnsClient/1.6.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==",
|
||||
"path": "dnsclient/1.6.1",
|
||||
"hashPath": "dnsclient.1.6.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Bcl.Cryptography/10.0.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-LG9Yll3B5aNpxv0+D47g6LiOiKBIlodhcHdQwcYzo8VeexFLGqx5ymetmA2aBRyo9cCcWsQWrFsdbsr8LvmWDw==",
|
||||
"path": "microsoft.bcl.cryptography/10.0.2",
|
||||
"hashPath": "microsoft.bcl.cryptography.10.0.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore/10.0.9": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-tu85SRzOT021V7EQlViCiAE7TqldVn469Y6lt5TEn/+XC4/MeNCHgMRSxqYuWqvF4zAQZUhCmtNEZuM3ss4LeA==",
|
||||
"path": "microsoft.entityframeworkcore/10.0.9",
|
||||
"hashPath": "microsoft.entityframeworkcore.10.0.9.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Abstractions/10.0.9": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-GRMaiPkqYna/gCsyDffYDWmefGPC3hDrdMw+2rrGcQwhs6uZOsaMQXMJnoXQ35tx9SkBV2ieRRU9N/jLOO6BZw==",
|
||||
"path": "microsoft.entityframeworkcore.abstractions/10.0.9",
|
||||
"hashPath": "microsoft.entityframeworkcore.abstractions.10.0.9.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Relational/10.0.9": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-dEoyYKgiaZHHgOFm1WMWm1sFEsEuhPWufX4L9PekKtqd/RaIcPjkCjvbrVvJtApErb5wPSJhYvnTlxhH+p9h2g==",
|
||||
"path": "microsoft.entityframeworkcore.relational/10.0.9",
|
||||
"hashPath": "microsoft.entityframeworkcore.relational.10.0.9.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Abstractions/8.19.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-gFA8THIk23uNF/vMdOHnjIdXD1LyA2g12cHzMJ+Xag6WpgWLw6E/6uCXxvA0gp9d2yAvkRt3xzFzMUiO/hofnQ==",
|
||||
"path": "microsoft.identitymodel.abstractions/8.19.1",
|
||||
"hashPath": "microsoft.identitymodel.abstractions.8.19.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.JsonWebTokens/8.19.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6eeY+y2QFyjj3XnCz/8gJdoP5smYHTS9ow1bw2nsZzDIPjPhBZlackYTIduSMipVpxnoT/B62LkrXX2jPggOXg==",
|
||||
"path": "microsoft.identitymodel.jsonwebtokens/8.19.1",
|
||||
"hashPath": "microsoft.identitymodel.jsonwebtokens.8.19.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Logging/8.19.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-H+sMrMpdbWnwkQnpb/ESkQovtOgdefmj0ecGCcP40mDKzE5i4dUYkH6599M9mWYFNGNJnTp92l/9wLubYXWimw==",
|
||||
"path": "microsoft.identitymodel.logging/8.19.1",
|
||||
"hashPath": "microsoft.identitymodel.logging.8.19.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Tokens/8.19.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-KDiuSLXud2AFVNAOottd8ztVysfPeHyr4r8gofU3/VKUXlI7oytzGTnPsNJ/B3nui17rgz8wAdWNJOtzPjkUxw==",
|
||||
"path": "microsoft.identitymodel.tokens/8.19.1",
|
||||
"hashPath": "microsoft.identitymodel.tokens.8.19.1.nupkg.sha512"
|
||||
},
|
||||
"MongoDB.Bson/3.9.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-J6vB61zKwMSfxbkN+/amGvj1qVMDKrKjV3kmoOWttMcv8JJScLDCFh89FyL3f2lDUyJrnfgZCR6/KX+07e99eg==",
|
||||
"path": "mongodb.bson/3.9.0",
|
||||
"hashPath": "mongodb.bson.3.9.0.nupkg.sha512"
|
||||
},
|
||||
"MongoDB.Driver/3.9.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-XKUa+y5RtNH1iInfxj3Y7c1FN1BQ16/7hFxoqU6fzc3+BKM1D3mGa+pB/yBbAk8jNxf7+JWEnCfuQOyCo7dQLg==",
|
||||
"path": "mongodb.driver/3.9.0",
|
||||
"hashPath": "mongodb.driver.3.9.0.nupkg.sha512"
|
||||
},
|
||||
"MongoDB.EntityFrameworkCore/10.0.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-GBN9+OAoIyBEgVPlYTXW3tyIsnpGPCA5AWZPy+X7ca3zJu+2Lli9FODZWl//w0yZHqwGwsLUL6XhcPPEaBYvBQ==",
|
||||
"path": "mongodb.entityframeworkcore/10.0.2",
|
||||
"hashPath": "mongodb.entityframeworkcore.10.0.2.nupkg.sha512"
|
||||
},
|
||||
"SharpCompress/0.48.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-SqGaVniGG943Gph/gHhUQUiZPyC7y0tXZyMf0/B2oGsMav9dqs7JJOuUA+xOkwKYaWM2TM7aZQjNK91f4bX71A==",
|
||||
"path": "sharpcompress/0.48.1",
|
||||
"hashPath": "sharpcompress.0.48.1.nupkg.sha512"
|
||||
},
|
||||
"Snappier/1.3.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-DOdDQiO8YZ5rBtVLY+6CmR1yp9WYoJRgEEktPBrR0tEj9QO2djA/zv0O3DX0OZpEAfosbY8pytQ9tQUogwQsEA==",
|
||||
"path": "snappier/1.3.1",
|
||||
"hashPath": "snappier.1.3.1.nupkg.sha512"
|
||||
},
|
||||
"spworlds-api/1.0.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-rLQsC3MiXBfPKf3v45Qcrj0yypfZktTPuT/eGUJpcAlSZix1FBSRUbQVtfXbA8BHGIqn7nhZMVetaP3dmk+n1g==",
|
||||
"path": "spworlds-api/1.0.3",
|
||||
"hashPath": "spworlds-api.1.0.3.nupkg.sha512"
|
||||
},
|
||||
"System.IdentityModel.Tokens.Jwt/8.19.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-2VHcRtT95GAcW1E3aVBLvL2rAAMxKHXKMXKXFyWzwgkdFXZPMMvP8tVOfnRydL4vTr1RirNuGC6T8VSEF2YsPQ==",
|
||||
"path": "system.identitymodel.tokens.jwt/8.19.1",
|
||||
"hashPath": "system.identitymodel.tokens.jwt.8.19.1.nupkg.sha512"
|
||||
},
|
||||
"ZstdSharp.Port/0.7.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==",
|
||||
"path": "zstdsharp.port/0.7.3",
|
||||
"hashPath": "zstdsharp.port.0.7.3.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net10.0",
|
||||
"frameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App",
|
||||
"version": "10.0.0"
|
||||
}
|
||||
],
|
||||
"configProperties": {
|
||||
"System.GC.Server": true,
|
||||
"System.Reflection.NullabilityInfoContext.IsSupported": true,
|
||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"ManifestType": "Build",
|
||||
"Endpoints": []
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APaymentWrapper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F28d7b99649ed43d899c3d8518f41c1976400_003F94_003Fbc0e580e_003FPaymentWrapper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASPWorlds_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F28d7b99649ed43d899c3d8518f41c1976400_003F64_003Fd3041423_003FSPWorlds_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
Reference in New Issue
Block a user