[FA-4] Adds an event bus infrastructure, a RabbitMQ implementation and rewires existing mutations on NovelService to utilize it.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
using FictionArchive.Service.NovelService.Models.IntegrationEvents;
|
||||
using FictionArchive.Service.Shared.Services.EventBus;
|
||||
|
||||
namespace FictionArchive.Service.NovelService.Services.EventHandlers;
|
||||
|
||||
public class ChapterPullRequestedEventHandler : IIntegrationEventHandler<ChapterPullRequestedEvent>
|
||||
{
|
||||
private readonly NovelUpdateService _novelUpdateService;
|
||||
|
||||
public ChapterPullRequestedEventHandler(NovelUpdateService novelUpdateService)
|
||||
{
|
||||
_novelUpdateService = novelUpdateService;
|
||||
}
|
||||
|
||||
public async Task Handle(ChapterPullRequestedEvent @event)
|
||||
{
|
||||
await _novelUpdateService.PullChapterContents(@event.NovelId, @event.ChapterNumber);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using FictionArchive.Service.NovelService.Models.IntegrationEvents;
|
||||
using FictionArchive.Service.Shared.Services.EventBus;
|
||||
|
||||
namespace FictionArchive.Service.NovelService.Services.EventHandlers;
|
||||
|
||||
public class NovelUpdateRequestedEventHandler : IIntegrationEventHandler<NovelUpdateRequestedEvent>
|
||||
{
|
||||
private readonly ILogger<NovelUpdateRequestedEventHandler> _logger;
|
||||
private readonly IEventBus _eventBus;
|
||||
private readonly NovelUpdateService _novelUpdateService;
|
||||
|
||||
public NovelUpdateRequestedEventHandler(ILogger<NovelUpdateRequestedEventHandler> logger, IEventBus eventBus, NovelUpdateService novelUpdateService)
|
||||
{
|
||||
_logger = logger;
|
||||
_eventBus = eventBus;
|
||||
_novelUpdateService = novelUpdateService;
|
||||
}
|
||||
|
||||
public async Task Handle(NovelUpdateRequestedEvent @event)
|
||||
{
|
||||
await _novelUpdateService.ImportNovel(@event.NovelUrl);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using FictionArchive.Service.NovelService.Models.IntegrationEvents;
|
||||
using FictionArchive.Service.NovelService.Models.Localization;
|
||||
using FictionArchive.Service.Shared.Services.EventBus;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FictionArchive.Service.NovelService.Services.EventHandlers;
|
||||
|
||||
public class TranslationRequestCompletedEventHandler : IIntegrationEventHandler<TranslationRequestCompletedEvent>
|
||||
{
|
||||
private readonly ILogger<TranslationRequestCompletedEventHandler> _logger;
|
||||
private readonly NovelServiceDbContext _dbContext;
|
||||
|
||||
public TranslationRequestCompletedEventHandler(ILogger<TranslationRequestCompletedEventHandler> logger, NovelServiceDbContext dbContext)
|
||||
{
|
||||
_logger = logger;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task Handle(TranslationRequestCompletedEvent @event)
|
||||
{
|
||||
var localizationRequest = await _dbContext.LocalizationRequests.Include(r => r.KeyRequestedForTranslation)
|
||||
.ThenInclude(lk => lk.Texts)
|
||||
.FirstOrDefaultAsync(lk => lk.Id == @event.TranslationRequestId);
|
||||
if (localizationRequest == null)
|
||||
{
|
||||
// Not one of our requests, discard it
|
||||
return;
|
||||
}
|
||||
|
||||
localizationRequest.KeyRequestedForTranslation.Texts.Add(new LocalizationText()
|
||||
{
|
||||
Language = localizationRequest.TranslateTo,
|
||||
Text = @event.TranslatedText,
|
||||
TranslationEngine = localizationRequest.Engine
|
||||
});
|
||||
_dbContext.LocalizationRequests.Remove(localizationRequest);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using FictionArchive.Service.NovelService.Models.Localization;
|
||||
using FictionArchive.Service.NovelService.Models.Novels;
|
||||
using FictionArchive.Service.Shared.Services.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -11,4 +12,6 @@ public class NovelServiceDbContext(DbContextOptions options, ILogger<NovelServic
|
||||
public DbSet<Source> Sources { get; set; }
|
||||
public DbSet<TranslationEngine> TranslationEngines { get; set; }
|
||||
public DbSet<NovelTag> Tags { get; set; }
|
||||
public DbSet<LocalizationKey> LocalizationKeys { get; set; }
|
||||
public DbSet<LocalizationRequest> LocalizationRequests { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using FictionArchive.Service.NovelService.Models.Enums;
|
||||
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 Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FictionArchive.Service.NovelService.Services;
|
||||
|
||||
public class NovelUpdateService
|
||||
{
|
||||
private readonly NovelServiceDbContext _dbContext;
|
||||
private readonly ILogger<NovelUpdateService> _logger;
|
||||
private readonly IEnumerable<ISourceAdapter> _sourceAdapters;
|
||||
|
||||
public NovelUpdateService(NovelServiceDbContext dbContext, ILogger<NovelUpdateService> logger, IEnumerable<ISourceAdapter> sourceAdapters)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
_sourceAdapters = sourceAdapters;
|
||||
}
|
||||
|
||||
public async Task<Novel> ImportNovel(string novelUrl)
|
||||
{
|
||||
NovelMetadata? metadata = null;
|
||||
foreach (ISourceAdapter sourceAdapter in _sourceAdapters)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public async Task<Chapter> PullChapterContents(uint novelId, uint chapterNumber)
|
||||
{
|
||||
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()
|
||||
{
|
||||
Text = rawChapter,
|
||||
Language = novel.RawLanguage
|
||||
});
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return chapter;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user