diff --git a/src/App/Extensions/CosmosDbServiceActivityExtensions.cs b/src/App/Extensions/CosmosDbServiceActivityExtensions.cs index 73d6142b..73f09b87 100644 --- a/src/App/Extensions/CosmosDbServiceActivityExtensions.cs +++ b/src/App/Extensions/CosmosDbServiceActivityExtensions.cs @@ -86,7 +86,7 @@ public static class CosmosDbServiceActivityExtensions /// The . /// The ID of the user. /// The started . - public static Activity? StartDbGetLyricsAnalyzerUserRateLimitActivity(this ActivitySource activitySource, ulong userId) => StartDbGetLyricsAnalyzerUserRateLimitActivity(activitySource, userId, null); + public static Activity? StartDbGetLyricsAnalyzerUserRateLimitActivity(this ActivitySource activitySource, string userId) => StartDbGetLyricsAnalyzerUserRateLimitActivity(activitySource, userId, null); /// /// Starts an activity for getting a lyrics analyzer rate limit for a user from the database. @@ -95,14 +95,14 @@ public static class CosmosDbServiceActivityExtensions /// The ID of the user. /// The parent activity ID. /// The started . - public static Activity? StartDbGetLyricsAnalyzerUserRateLimitActivity(this ActivitySource activitySource, ulong userId, string? parentActivityId) + public static Activity? StartDbGetLyricsAnalyzerUserRateLimitActivity(this ActivitySource activitySource, string userId, string? parentActivityId) { return activitySource.StartActivity( name: "Database:GetLyricsAnalyzerUserRateLimitAsync", kind: ActivityKind.Internal, tags: new ActivityTagsCollection { - { "userId", userId.ToString() } + { "userId", userId } }, parentId: parentActivityId ); diff --git a/src/App/Logging/CosmosDb/CosmosDbServiceLogging.cs b/src/App/Logging/CosmosDb/CosmosDbServiceLogging.cs index eab9c283..332bd784 100644 --- a/src/App/Logging/CosmosDb/CosmosDbServiceLogging.cs +++ b/src/App/Logging/CosmosDb/CosmosDbServiceLogging.cs @@ -7,6 +7,31 @@ namespace MuzakBot.App.Logging.CosmosDb; /// internal static partial class CosmosDbServiceLogging { + /// + /// Logs the initialization of the database and ensures that it exists. + /// + /// The instance. + /// The name of the database. + [LoggerMessage( + EventName = "CosmosDbService.Initialize.EnsureDbExists", + Level = LogLevel.Information, + Message = "Ensuring that the database, '{databaseName}', exists." + )] + public static partial void LogInitializeEnsureDbExists(this ILogger logger, string databaseName); + + /// + /// Logs the initialization of a container and ensures that it exists. + /// + /// The instance. + /// The name of the container. + /// The name of the database. + [LoggerMessage( + EventName = "CosmosDbService.Initialize.EnsureContainerExists", + Level = LogLevel.Information, + Message = "Ensuring that the container, '{containerName}', exists in '{databaseName}'." + )] + public static partial void LogInitializeEnsureContainerExists(this ILogger logger, string containerName, string databaseName); + /// /// Logs the start of an add or update operation to the database. /// diff --git a/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerUserRateLimit.cs b/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerUserRateLimit.cs index cf824632..aab24f51 100644 --- a/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerUserRateLimit.cs +++ b/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerUserRateLimit.cs @@ -16,7 +16,7 @@ public LyricsAnalyzerUserRateLimit() /// Initializes a new instance of the class. /// /// The user's ID. - public LyricsAnalyzerUserRateLimit(ulong userId): this(userId, 0, DateTimeOffset.UtcNow) + public LyricsAnalyzerUserRateLimit(string userId): this(userId, 0, DateTimeOffset.UtcNow) {} /// @@ -24,7 +24,7 @@ public LyricsAnalyzerUserRateLimit(ulong userId): this(userId, 0, DateTimeOffset /// /// The user's ID. /// The current request count. - public LyricsAnalyzerUserRateLimit(ulong userId, int currentRequestCount): this(userId, currentRequestCount, DateTimeOffset.UtcNow) + public LyricsAnalyzerUserRateLimit(string userId, int currentRequestCount): this(userId, currentRequestCount, DateTimeOffset.UtcNow) {} /// @@ -33,7 +33,7 @@ public LyricsAnalyzerUserRateLimit(ulong userId, int currentRequestCount): this( /// The user's ID. /// The current request count. /// The last request time. - public LyricsAnalyzerUserRateLimit(ulong userId, int currentRequestCount, DateTimeOffset lastRequestTime) + public LyricsAnalyzerUserRateLimit(string userId, int currentRequestCount, DateTimeOffset lastRequestTime) { Id = Guid.NewGuid().ToString(); PartitionKey = "user-item"; @@ -47,7 +47,7 @@ public LyricsAnalyzerUserRateLimit(ulong userId, int currentRequestCount, DateTi /// The user's ID. /// [JsonPropertyName("userId")] - public ulong UserId { get; set; } + public string UserId { get; set; } = null!; /// /// The current request count. diff --git a/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerUserRateLimit.cs b/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerUserRateLimit.cs index 3a5d0b53..a4f97d85 100644 --- a/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerUserRateLimit.cs +++ b/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerUserRateLimit.cs @@ -4,7 +4,7 @@ public interface ILyricsAnalyzerUserRateLimit { string Id { get; set; } string PartitionKey { get; set; } - ulong UserId { get; set; } + string UserId { get; set; } int CurrentRequestCount { get; set; } DateTimeOffset LastRequestTime { get; set; } diff --git a/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs b/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs index 510de530..396e236e 100644 --- a/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs +++ b/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs @@ -99,7 +99,7 @@ await FollowupAsync( if (lyricsAnalyzerConfig.RateLimitEnabled) { _logger.LogInformation("Getting current rate limit for user '{UserId}' from database.", Context.User.Id); - lyricsAnalyzerUserRateLimit = await _cosmosDbService.GetLyricsAnalyzerUserRateLimitAsync(Context.User.Id, activity?.Id); + lyricsAnalyzerUserRateLimit = await _cosmosDbService.GetLyricsAnalyzerUserRateLimitAsync(Context.User.Id.ToString(), activity?.Id); _logger.LogInformation("Current rate limit for user '{UserId}' is {CurrentRequestCount}/{MaxRequests}.", Context.User.Id, lyricsAnalyzerUserRateLimit.CurrentRequestCount, lyricsAnalyzerConfig.RateLimitMaxRequests); diff --git a/src/App/Program.cs b/src/App/Program.cs index ffdd61a2..cad8e8f6 100644 --- a/src/App/Program.cs +++ b/src/App/Program.cs @@ -82,4 +82,8 @@ using var host = builder.Build(); +// Initialize the database and containers for the Cosmos DB service +// before running the host. +await host.Services.GetRequiredService().InitializeDatabaseAsync(); + await host.RunAsync(); diff --git a/src/App/Services/CosmosDbService/CosmosDbService.cs b/src/App/Services/CosmosDbService/CosmosDbService.cs index 04aebf96..a648e077 100644 --- a/src/App/Services/CosmosDbService/CosmosDbService.cs +++ b/src/App/Services/CosmosDbService/CosmosDbService.cs @@ -2,6 +2,7 @@ using Microsoft.Azure.Cosmos; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using MuzakBot.App.Logging.CosmosDb; namespace MuzakBot.App.Services; @@ -28,6 +29,44 @@ public CosmosDbService(ILogger logger, IOptions + /// Initializes the database and containers for MuzakBot. + /// + /// + public async Task InitializeDatabaseAsync() + { + // Initialize the database and containers for 'lyrics-analyzer', + // if they don't exist. + _logger.LogInitializeEnsureDbExists("lyrics-analyzer"); + Database lyricsAnalyzerDb = await _cosmosDbClient.CreateDatabaseIfNotExistsAsync( + id: "lyrics-analyzer" + ); + + _logger.LogInitializeEnsureContainerExists("song-lyrics", "lyrics-analyzer"); + await lyricsAnalyzerDb.CreateContainerIfNotExistsAsync( + id: "song-lyrics", + partitionKeyPath: "/partitionKey" + ); + + _logger.LogInitializeEnsureContainerExists("command-configs", "lyrics-analyzer"); + await lyricsAnalyzerDb.CreateContainerIfNotExistsAsync( + id: "command-configs", + partitionKeyPath: "/partitionKey" + ); + + _logger.LogInitializeEnsureContainerExists("prompt-styles", "lyrics-analyzer"); + await lyricsAnalyzerDb.CreateContainerIfNotExistsAsync( + id: "prompt-styles", + partitionKeyPath: "/partitionKey" + ); + + _logger.LogInitializeEnsureContainerExists("rate-limit", "lyrics-analyzer"); + await lyricsAnalyzerDb.CreateContainerIfNotExistsAsync( + id: "rate-limit", + partitionKeyPath: "/partitionKey" + ); + } + /// public void Dispose() { diff --git a/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerUserRateLimitAsync.cs b/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerUserRateLimitAsync.cs index 384fb040..dc91f87c 100644 --- a/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerUserRateLimitAsync.cs +++ b/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerUserRateLimitAsync.cs @@ -16,7 +16,7 @@ public partial class CosmosDbService /// /// The ID of the user. /// The retrieved lyrics analyzer rate limit for the user. - public async Task GetLyricsAnalyzerUserRateLimitAsync(ulong userId) => await GetLyricsAnalyzerUserRateLimitAsync(userId, null); + public async Task GetLyricsAnalyzerUserRateLimitAsync(string userId) => await GetLyricsAnalyzerUserRateLimitAsync(userId, null); /// /// Gets the lyrics analyzer rate limit for a user from the database. @@ -24,7 +24,7 @@ public partial class CosmosDbService /// The ID of the user. /// The parent activity ID. /// The retrieved lyrics analyzer rate limit for the user. - public async Task GetLyricsAnalyzerUserRateLimitAsync(ulong userId, string? parentActivityId) + public async Task GetLyricsAnalyzerUserRateLimitAsync(string userId, string? parentActivityId) { using var activity = _activitySource.StartDbGetLyricsAnalyzerUserRateLimitActivity( userId: userId, diff --git a/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs b/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs index e435b5df..925662c7 100644 --- a/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs +++ b/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs @@ -4,14 +4,16 @@ namespace MuzakBot.App.Services; public interface ICosmosDbService : IDisposable { + Task InitializeDatabaseAsync(); + Task GetLyricsAnalyzerConfigAsync(); Task GetLyricsAnalyzerConfigAsync(string? parentActivityId); Task AddOrUpdateLyricsAnalyzerConfigAsync(LyricsAnalyzerConfig lyricsAnalyzerConfig); Task AddOrUpdateLyricsAnalyzerConfigAsync(LyricsAnalyzerConfig lyricsAnalyzerConfig, string? parentActivityId); - Task GetLyricsAnalyzerUserRateLimitAsync(ulong userId); - Task GetLyricsAnalyzerUserRateLimitAsync(ulong userId, string? parentActivityId); + Task GetLyricsAnalyzerUserRateLimitAsync(string userId); + Task GetLyricsAnalyzerUserRateLimitAsync(string userId, string? parentActivityId); Task AddOrUpdateLyricsAnalyzerUserRateLimitAsync(LyricsAnalyzerUserRateLimit lyricsAnalyzerUserRateLimit); Task AddOrUpdateLyricsAnalyzerUserRateLimitAsync(LyricsAnalyzerUserRateLimit lyricsAnalyzerUserRateLimit, string? parentActivityId);