fix: IDeserializer并非线程安全
This commit is contained in:
parent
800f439564
commit
66ecaa4c90
|
@ -4,6 +4,8 @@ public class BlogEssay
|
||||||
{
|
{
|
||||||
public required string Title { get; init; }
|
public required string Title { get; init; }
|
||||||
|
|
||||||
|
public required string FileName { get; init; }
|
||||||
|
|
||||||
public required DateTime PublishTime { get; init; }
|
public required DateTime PublishTime { get; init; }
|
||||||
|
|
||||||
public List<string> Tags { get; } = [];
|
public List<string> Tags { get; } = [];
|
||||||
|
|
|
@ -6,5 +6,5 @@ public class MarkdownMetadata
|
||||||
|
|
||||||
public DateTime? Date { get; set; }
|
public DateTime? Date { get; set; }
|
||||||
|
|
||||||
public List<string> Tags { get; set; } = [];
|
public List<string>? Tags { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using Markdig;
|
using System.Diagnostics;
|
||||||
|
using Markdig;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Core.Models;
|
using YaeBlog.Core.Models;
|
||||||
|
using YamlDotNet.Core;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
namespace YaeBlog.Core.Services;
|
namespace YaeBlog.Core.Services;
|
||||||
|
@ -12,33 +14,61 @@ public class RendererService(ILogger<RendererService> logger,
|
||||||
IDeserializer yamlDeserializer,
|
IDeserializer yamlDeserializer,
|
||||||
EssayContentService essayContentService)
|
EssayContentService essayContentService)
|
||||||
{
|
{
|
||||||
|
private readonly Stopwatch _stopwatch = new();
|
||||||
|
|
||||||
public async Task RenderAsync()
|
public async Task RenderAsync()
|
||||||
{
|
{
|
||||||
|
_stopwatch.Start();
|
||||||
|
logger.LogInformation("Render essays start.");
|
||||||
|
|
||||||
List<BlogContent> contents = await essayScanService.ScanAsync();
|
List<BlogContent> contents = await essayScanService.ScanAsync();
|
||||||
|
|
||||||
Parallel.ForEach(contents, content =>
|
List<BlogEssay> essays = [];
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
MarkdownMetadata? metadata = TryParseMetadata(content);
|
foreach (BlogContent content in contents)
|
||||||
|
{
|
||||||
|
MarkdownMetadata? metadata = TryParseMetadata(content);
|
||||||
|
BlogEssay essay = new()
|
||||||
|
{
|
||||||
|
Title = metadata?.Title ?? content.FileName,
|
||||||
|
FileName = content.FileName,
|
||||||
|
PublishTime = metadata?.Date ?? DateTime.Now,
|
||||||
|
HtmlContent = content.FileContent
|
||||||
|
};
|
||||||
|
|
||||||
BlogEssay essay = new()
|
if (metadata?.Tags is not null)
|
||||||
{
|
{
|
||||||
Title = metadata?.Title ?? content.FileName,
|
essay.Tags.AddRange(metadata.Tags);
|
||||||
PublishTime = metadata?.Date ?? DateTime.Now,
|
}
|
||||||
HtmlContent = Markdown.ToHtml(content.FileContent, markdownPipeline)
|
essays.Add(essay);
|
||||||
};
|
|
||||||
if (metadata is not null)
|
|
||||||
{
|
|
||||||
essay.Tags.AddRange(essay.Tags);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!essayContentService.TryAdd(essay.Title, essay))
|
Parallel.ForEach(essays, essay =>
|
||||||
|
{
|
||||||
|
|
||||||
|
BlogEssay newEssay = new()
|
||||||
|
{
|
||||||
|
Title = essay.Title,
|
||||||
|
FileName = essay.FileName,
|
||||||
|
PublishTime = essay.PublishTime,
|
||||||
|
HtmlContent = Markdown.ToHtml(essay.HtmlContent, markdownPipeline)
|
||||||
|
};
|
||||||
|
newEssay.Tags.AddRange(essay.Tags);
|
||||||
|
|
||||||
|
if (!essayContentService.TryAdd(newEssay.FileName, newEssay))
|
||||||
{
|
{
|
||||||
throw new BlogFileException(
|
throw new BlogFileException(
|
||||||
$"There are two essays with the same name: '{content.FileName}'.");
|
$"There are two essays with the same name: '{newEssay.FileName}'.");
|
||||||
}
|
}
|
||||||
logger.LogDebug("Render markdown file {}.", essay);
|
logger.LogDebug("Render markdown file {}.", newEssay);
|
||||||
logger.LogDebug("{}", essay.HtmlContent);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_stopwatch.Stop();
|
||||||
|
logger.LogInformation("Render finished, consuming {} s.",
|
||||||
|
_stopwatch.Elapsed.ToString("s\\.fff"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private MarkdownMetadata? TryParseMetadata(BlogContent content)
|
private MarkdownMetadata? TryParseMetadata(BlogContent content)
|
||||||
|
@ -60,14 +90,23 @@ public class RendererService(ILogger<RendererService> logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
string yamlContent = fileContent[..lastPos];
|
string yamlContent = fileContent[..lastPos];
|
||||||
MarkdownMetadata metadata = yamlDeserializer.Deserialize<MarkdownMetadata>(yamlContent);
|
|
||||||
logger.LogDebug("Title: {}, Publish Date: {}.",
|
|
||||||
metadata.Title, metadata.Date);
|
|
||||||
|
|
||||||
// 返回去掉元数据之后的文本
|
// 返回去掉元数据之后的文本
|
||||||
lastPos += 3;
|
lastPos += 3;
|
||||||
content.FileContent = fileContent[lastPos..];
|
content.FileContent = fileContent[lastPos..];
|
||||||
|
|
||||||
return null;
|
try
|
||||||
|
{
|
||||||
|
MarkdownMetadata metadata =
|
||||||
|
yamlDeserializer.Deserialize<MarkdownMetadata>(yamlContent);
|
||||||
|
logger.LogDebug("Title: {}, Publish Date: {}.",
|
||||||
|
metadata.Title, metadata.Date);
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
catch (YamlException e)
|
||||||
|
{
|
||||||
|
logger.LogWarning("Failed to parse '{}' metadata: {}", yamlContent, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user