[FA-4] Adds an event bus infrastructure, a RabbitMQ implementation and rewires existing mutations on NovelService to utilize it.

This commit is contained in:
gamer147
2025-11-19 21:45:33 -05:00
parent 716087e4a4
commit e9423bfa66
42 changed files with 1037 additions and 263 deletions

View File

@@ -1,107 +1,37 @@
using FictionArchive.Service.NovelService.Models.Enums;
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;
using FictionArchive.Service.NovelService.Services.SourceAdapters;
using FictionArchive.Service.Shared.Services.EventBus;
using Microsoft.EntityFrameworkCore;
namespace FictionArchive.Service.NovelService.GraphQL;
public class Mutation
{
// TODO Make this kick off a job in the background somehow. Probably want to think of how jobs will work across services
// Also of course need to make it a proper 'upsert'
public async Task<Novel> ImportNovel(string novelUrl, NovelServiceDbContext dbContext,
IEnumerable<ISourceAdapter> adapters)
public async Task<NovelUpdateRequestedEvent> ImportNovel(string novelUrl, IEventBus eventBus)
{
NovelMetadata? metadata = null;
foreach (ISourceAdapter sourceAdapter in adapters)
var importNovelRequestEvent = new NovelUpdateRequestedEvent()
{
if (await sourceAdapter.CanProcessNovel(novelUrl))
{
metadata = await sourceAdapter.GetMetadata(novelUrl);
}
}
if (metadata == null)
{
throw new NotSupportedException("The provided novel url is currently unsupported.");
}
var systemTags = metadata.SystemTags.Select(tag => new NovelTag()
{
Key = tag,
DisplayName = LocalizationKey.CreateFromText(tag, metadata.RawLanguage),
TagType = TagType.System
});
var sourceTags = metadata.SourceTags.Select(tag => new NovelTag()
{
Key = tag,
DisplayName = LocalizationKey.CreateFromText(tag, metadata.RawLanguage),
TagType = TagType.External
});
var addedNovel = dbContext.Novels.Add(new Novel()
{
Author = new Person()
{
Name = LocalizationKey.CreateFromText(metadata.AuthorName, metadata.RawLanguage),
ExternalUrl = metadata.AuthorUrl,
},
RawLanguage = metadata.RawLanguage,
Url = metadata.Url,
ExternalId = metadata.ExternalId,
Chapters = metadata.Chapters.Select(chapter =>
{
return new Chapter()
{
Order = chapter.Order,
Url = chapter.Url,
Revision = chapter.Revision,
Name = LocalizationKey.CreateFromText(chapter.Name, metadata.RawLanguage),
Body = new LocalizationKey()
{
Texts = new List<LocalizationText>()
}
};
}).ToList(),
Description = LocalizationKey.CreateFromText(metadata.Description, metadata.RawLanguage),
Name = LocalizationKey.CreateFromText(metadata.Name, metadata.RawLanguage),
RawStatus = metadata.RawStatus,
Tags = sourceTags.Concat(systemTags).ToList(),
Source = new Source()
{
Name = metadata.SourceDescriptor.Name,
Url = metadata.SourceDescriptor.Url,
Key = metadata.SourceDescriptor.Key,
}
});
await dbContext.SaveChangesAsync();
return addedNovel.Entity;
NovelUrl = novelUrl
};
await eventBus.Publish(importNovelRequestEvent);
return importNovelRequestEvent;
}
public async Task<Chapter> FetchChapterContents(uint novelId,
public async Task<ChapterPullRequestedEvent> FetchChapterContents(uint novelId,
uint chapterNumber,
NovelServiceDbContext dbContext,
IEnumerable<ISourceAdapter> sourceAdapters)
IEventBus eventBus)
{
var novel = await dbContext.Novels.Where(novel => novel.Id == novelId)
.Include(novel => novel.Chapters)
.ThenInclude(chapter => chapter.Body)
.ThenInclude(body => body.Texts)
.Include(novel => novel.Source)
.FirstOrDefaultAsync();
var chapter = novel.Chapters.Where(chapter => chapter.Order == chapterNumber).FirstOrDefault();
var adapter = sourceAdapters.FirstOrDefault(adapter => adapter.SourceDescriptor.Key == novel.Source.Key);
var rawChapter = await adapter.GetRawChapter(chapter.Url);
chapter.Body.Texts.Add(new LocalizationText()
var chapterPullEvent = new ChapterPullRequestedEvent()
{
Text = rawChapter,
Language = novel.RawLanguage
});
await dbContext.SaveChangesAsync();
return chapter;
NovelId = novelId,
ChapterNumber = chapterNumber
};
await eventBus.Publish(chapterPullEvent);
return chapterPullEvent;
}
}