[FA-misc] Initial MassTransit implementation seems to work

This commit is contained in:
gamer147
2026-01-26 17:08:13 -05:00
parent e7435435c1
commit 579e05b853
96 changed files with 845 additions and 1229 deletions

View File

@@ -1,15 +1,15 @@
using FictionArchive.Common.Enums;
using FictionArchive.Service.FileService.IntegrationEvents;
using FictionArchive.Service.NovelService.Contracts;
using FictionArchive.Service.NovelService.Models.Configuration;
using FictionArchive.Service.NovelService.Models.Enums;
using FictionArchive.Service.NovelService.Models.Images;
using FictionArchive.Service.NovelService.Models.IntegrationEvents;
using FictionArchive.Service.NovelService.Models.Localization;
using FictionArchive.Service.NovelService.Models.Novels;
using FictionArchive.Service.NovelService.Models.SourceAdapters;
using FictionArchive.Service.NovelService.Services.SourceAdapters;
using FictionArchive.Service.Shared.Services.EventBus;
using FictionArchive.Service.Shared.Contracts.Events;
using HtmlAgilityPack;
using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
@@ -20,15 +20,15 @@ public class NovelUpdateService
private readonly NovelServiceDbContext _dbContext;
private readonly ILogger<NovelUpdateService> _logger;
private readonly IEnumerable<ISourceAdapter> _sourceAdapters;
private readonly IEventBus _eventBus;
private readonly IPublishEndpoint _publishEndpoint;
private readonly NovelUpdateServiceConfiguration _novelUpdateServiceConfiguration;
public NovelUpdateService(NovelServiceDbContext dbContext, ILogger<NovelUpdateService> logger, IEnumerable<ISourceAdapter> sourceAdapters, IEventBus eventBus, IOptions<NovelUpdateServiceConfiguration> novelUpdateServiceConfiguration)
public NovelUpdateService(NovelServiceDbContext dbContext, ILogger<NovelUpdateService> logger, IEnumerable<ISourceAdapter> sourceAdapters, IPublishEndpoint publishEndpoint, IOptions<NovelUpdateServiceConfiguration> novelUpdateServiceConfiguration)
{
_dbContext = dbContext;
_logger = logger;
_sourceAdapters = sourceAdapters;
_eventBus = eventBus;
_publishEndpoint = publishEndpoint;
_novelUpdateServiceConfiguration = novelUpdateServiceConfiguration.Value;
}
@@ -335,7 +335,8 @@ public class NovelUpdateService
.ThenInclude(volume => volume.Chapters)
.ThenInclude(chapter => chapter.Body)
.ThenInclude(localizationKey => localizationKey.Texts)
.Include(n => n.CoverImage)
.Include(n => n.CoverImage).Include(novel => novel.Volumes).ThenInclude(volume => volume.Chapters)
.ThenInclude(chapter => chapter.Name)
.FirstOrDefaultAsync(n =>
n.ExternalId == metadata.ExternalId &&
n.Source.Key == metadata.SourceDescriptor.Key);
@@ -393,14 +394,12 @@ public class NovelUpdateService
// Publish novel created event for new novels
if (existingNovel == null)
{
await _eventBus.Publish(new NovelCreatedEvent
{
NovelId = novel.Id,
Title = novel.Name.Texts.First(t => t.Language == novel.RawLanguage).Text,
OriginalLanguage = novel.RawLanguage,
Source = novel.Source.Key,
AuthorName = novel.Author.Name.Texts.First(t => t.Language == novel.RawLanguage).Text
});
await _publishEndpoint.Publish<INovelCreated>(new NovelCreated(
novel.Id,
novel.Name.Texts.First(t => t.Language == novel.RawLanguage).Text,
novel.RawLanguage,
novel.Source.Key,
novel.Author.Name.Texts.First(t => t.Language == novel.RawLanguage).Text));
}
// Publish chapter created events for new chapters
@@ -408,27 +407,23 @@ public class NovelUpdateService
{
foreach (var chapter in volume.Chapters.Where(c => !existingChapterIds.Contains(c.Id)))
{
await _eventBus.Publish(new ChapterCreatedEvent
{
ChapterId = chapter.Id,
NovelId = novel.Id,
VolumeId = volume.Id,
VolumeOrder = volume.Order,
ChapterOrder = chapter.Order,
ChapterTitle = chapter.Name.Texts.First(t => t.Language == novel.RawLanguage).Text
});
await _publishEndpoint.Publish<IChapterCreated>(new ChapterCreated(
chapter.Id,
novel.Id,
volume.Id,
(uint)volume.Order,
chapter.Order,
chapter.Name.Texts.First(t => t.Language == novel.RawLanguage).Text));
}
}
// Publish cover image event if needed
if (shouldPublishCoverEvent && novel.CoverImage != null && metadata.CoverImage != null)
{
await _eventBus.Publish(new FileUploadRequestCreatedEvent
{
RequestId = novel.CoverImage.Id,
FileData = metadata.CoverImage.Data,
FilePath = $"Novels/{novel.Id}/Images/cover.jpg"
});
await _publishEndpoint.Publish<IFileUploadRequestCreated>(new FileUploadRequestCreated(
novel.CoverImage.Id,
$"Novels/{novel.Id}/Images/cover.jpg",
metadata.CoverImage.Data));
}
// Publish chapter pull events for chapters without body content
@@ -440,12 +435,10 @@ public class NovelUpdateService
foreach (var chapter in chaptersNeedingPull)
{
await _eventBus.Publish(new ChapterPullRequestedEvent
{
NovelId = novel.Id,
VolumeId = volume.Id,
ChapterOrder = chapter.Order
});
await _publishEndpoint.Publish<IChapterPullRequested>(new ChapterPullRequested(
novel.Id,
volume.Id,
chapter.Order));
}
}
@@ -518,12 +511,10 @@ public class NovelUpdateService
foreach (var image in chapter.Images)
{
var data = rawChapter.ImageData.FirstOrDefault(img => img.Url == image.OriginalPath);
await _eventBus.Publish(new FileUploadRequestCreatedEvent()
{
FileData = data.Data,
FilePath = $"{novel.Id}/Images/Chapter-{chapter.Id}/{imgCount++}.jpg",
RequestId = image.Id
});
await _publishEndpoint.Publish<IFileUploadRequestCreated>(new FileUploadRequestCreated(
image.Id,
$"Novels/{novel.Id}/Images/Chapter-{chapter.Id}/{imgCount++}.jpg",
data.Data));
}
return chapter;
@@ -557,25 +548,17 @@ public class NovelUpdateService
await _dbContext.SaveChangesAsync();
}
public async Task<NovelUpdateRequestedEvent> QueueNovelImport(string novelUrl)
public async Task<NovelUpdateRequested> QueueNovelImport(string novelUrl)
{
var importNovelRequestEvent = new NovelUpdateRequestedEvent()
{
NovelUrl = novelUrl
};
await _eventBus.Publish(importNovelRequestEvent);
var importNovelRequestEvent = new NovelUpdateRequested(novelUrl);
await _publishEndpoint.Publish<INovelUpdateRequested>(importNovelRequestEvent);
return importNovelRequestEvent;
}
public async Task<ChapterPullRequestedEvent> QueueChapterPull(uint novelId, uint volumeId, uint chapterOrder)
public async Task<ChapterPullRequested> QueueChapterPull(uint novelId, uint volumeId, uint chapterOrder)
{
var chapterPullEvent = new ChapterPullRequestedEvent()
{
NovelId = novelId,
VolumeId = volumeId,
ChapterOrder = chapterOrder
};
await _eventBus.Publish(chapterPullEvent);
var chapterPullEvent = new ChapterPullRequested(novelId, volumeId, chapterOrder);
await _publishEndpoint.Publish<IChapterPullRequested>(chapterPullEvent);
return chapterPullEvent;
}