Compare commits
2 Commits
5fef951d36
...
dfb66b4301
| Author | SHA1 | Date | |
|---|---|---|---|
|
dfb66b4301
|
|||
|
05f99f4b79
|
@@ -12,6 +12,7 @@
|
|||||||
<File Path="README.md" />
|
<File Path="README.md" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/src/">
|
<Folder Name="/src/">
|
||||||
|
<Project Path="src/YaeBlog.Abstractions/YaeBlog.Abstractions.csproj" />
|
||||||
<Project Path="src/YaeBlog.Tests/YaeBlog.Tests.csproj" />
|
<Project Path="src/YaeBlog.Tests/YaeBlog.Tests.csproj" />
|
||||||
<Project Path="src/YaeBlog/YaeBlog.csproj" />
|
<Project Path="src/YaeBlog/YaeBlog.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
|
|||||||
@@ -146,10 +146,6 @@ process {
|
|||||||
dotnet run -- serve
|
dotnet run -- serve
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
"list" {
|
|
||||||
dotnet run -- list
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Abstraction;
|
namespace YaeBlog.Abstractions;
|
||||||
|
|
||||||
public interface IEssayContentService
|
public interface IEssayContentService
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Abstraction;
|
namespace YaeBlog.Abstractions;
|
||||||
|
|
||||||
public interface IEssayScanService
|
public interface IEssayScanService
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Abstraction;
|
namespace YaeBlog.Abstractions;
|
||||||
|
|
||||||
public interface IPostRenderProcessor
|
public interface IPostRenderProcessor
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Abstraction;
|
namespace YaeBlog.Abstractions;
|
||||||
|
|
||||||
public interface IPreRenderProcessor
|
public interface IPreRenderProcessor
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单个博客文件的所有数据和元数据
|
/// 单个博客文件的所有数据和元数据
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public record BlogContents(ConcurrentBag<BlogContent> Drafts, ConcurrentBag<BlogContent> Posts)
|
public record BlogContents(ConcurrentBag<BlogContent> Drafts, ConcurrentBag<BlogContent> Posts)
|
||||||
: IEnumerable<BlogContent>
|
: IEnumerable<BlogContent>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public record BlogEssay(
|
public record BlogEssay(
|
||||||
string Title,
|
string Title,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public class BlogHeadline(string title, string selectorId)
|
public class BlogHeadline(string title, string selectorId)
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public record BlogImageInfo(FileInfo File, long Width, long Height, string MineType, byte[] Content, bool IsUsed)
|
public record BlogImageInfo(FileInfo File, long Width, long Height, string MineType, byte[] Content, bool IsUsed)
|
||||||
: IComparable<BlogImageInfo>
|
: IComparable<BlogImageInfo>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 友链模型类
|
/// 友链模型类
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
|
||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public class EssayTag(string tagName) : IEquatable<EssayTag>
|
public class EssayTag(string tagName) : IEquatable<EssayTag>
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public class GiteaOptions
|
public class GiteaOptions
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public record GitContributionItem(DateOnly Time, long ContributionCount)
|
public record GitContributionItem(DateOnly Time, long ContributionCount)
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace YaeBlog.Models;
|
namespace YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
public class MarkdownMetadata
|
public class MarkdownMetadata
|
||||||
{
|
{
|
||||||
9
src/YaeBlog.Abstractions/YaeBlog.Abstractions.csproj
Normal file
9
src/YaeBlog.Abstractions/YaeBlog.Abstractions.csproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
using Moq;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
using YaeBlog.Services;
|
using YaeBlog.Services;
|
||||||
|
|
||||||
namespace YaeBlog.Tests;
|
namespace YaeBlog.Tests;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
using Moq;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Tests;
|
namespace YaeBlog.Tests;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@using Microsoft.Extensions.Options
|
@using Microsoft.Extensions.Options
|
||||||
@using YaeBlog.Abstraction
|
@using YaeBlog.Abstractions
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
|
|
||||||
@inject IEssayContentService Contents
|
@inject IEssayContentService Contents
|
||||||
@inject IOptions<BlogOptions> Options
|
@inject IOptions<BlogOptions> Options
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@using System.Text.Encodings.Web
|
@using System.Text.Encodings.Web
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
|
|
||||||
<div class="flex flex-col p-3">
|
<div class="flex flex-col p-3">
|
||||||
<div class="text-3xl font-bold py-2">
|
<div class="text-3xl font-bold py-2">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
@using YaeBlog.Services
|
@using YaeBlog.Services
|
||||||
@inject GitHeapMapService GitHeapMapInstance
|
@inject GitHeapMapService GitHeapMapInstance
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/blog/archives"
|
@page "/blog/archives"
|
||||||
@using YaeBlog.Abstraction
|
@using YaeBlog.Abstractions
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
|
|
||||||
@inject IEssayContentService Contents
|
@inject IEssayContentService Contents
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/blog"
|
@page "/blog"
|
||||||
@using YaeBlog.Abstraction
|
@using YaeBlog.Abstractions
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
|
|
||||||
@inject IEssayContentService Contents
|
@inject IEssayContentService Contents
|
||||||
@inject NavigationManager NavigationInstance
|
@inject NavigationManager NavigationInstance
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@page "/blog/essays/{BlogKey}"
|
@page "/blog/essays/{BlogKey}"
|
||||||
@using System.Text.Encodings.Web
|
@using System.Text.Encodings.Web
|
||||||
@using YaeBlog.Abstraction
|
@using YaeBlog.Abstractions
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
|
|
||||||
@inject IEssayContentService Contents
|
@inject IEssayContentService Contents
|
||||||
@inject NavigationManager NavigationInstance
|
@inject NavigationManager NavigationInstance
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/friends"
|
@page "/friends"
|
||||||
@using Microsoft.Extensions.Options
|
@using Microsoft.Extensions.Options
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
@inject IOptions<BlogOptions> BlogOptionInstance
|
@inject IOptions<BlogOptions> BlogOptionInstance
|
||||||
|
|
||||||
<PageTitle>
|
<PageTitle>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@using YaeBlog.Abstraction
|
@using YaeBlog.Abstractions
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
@inject IEssayContentService EssayContentInstance
|
@inject IEssayContentService EssayContentInstance
|
||||||
|
|
||||||
<PageTitle>
|
<PageTitle>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@page "/blog/tags/"
|
@page "/blog/tags/"
|
||||||
@using System.Text.Encodings.Web
|
@using System.Text.Encodings.Web
|
||||||
@using YaeBlog.Abstraction
|
@using YaeBlog.Abstractions
|
||||||
@using YaeBlog.Models
|
@using YaeBlog.Abstractions.Models
|
||||||
|
|
||||||
@inject IEssayContentService Contents
|
@inject IEssayContentService Contents
|
||||||
@inject NavigationManager NavigationInstance
|
@inject NavigationManager NavigationInstance
|
||||||
|
|||||||
@@ -1,26 +1,73 @@
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Services;
|
using YaeBlog.Services;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
using YaeBlog.Processors;
|
using YaeBlog.Processors;
|
||||||
|
|
||||||
namespace YaeBlog.Extensions;
|
namespace YaeBlog.Extensions;
|
||||||
|
|
||||||
public static class WebApplicationBuilderExtensions
|
public static class HostApplicationBuilderExtensions
|
||||||
{
|
{
|
||||||
extension(WebApplicationBuilder builder)
|
extension(IHostApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
public WebApplicationBuilder AddYaeBlog()
|
public ConsoleInfoService AddYaeCommand(string[] arguments)
|
||||||
{
|
{
|
||||||
builder.ConfigureOptions<BlogOptions>(BlogOptions.OptionName)
|
builder.AddCommonServices();
|
||||||
.ConfigureOptions<GiteaOptions>(GiteaOptions.OptionName);
|
|
||||||
|
|
||||||
|
builder.Logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Warning);
|
||||||
|
|
||||||
|
builder.Services.AddTransient<ImageCompressService>();
|
||||||
|
builder.Services.AddHostedService<YaeCommandService>(provider =>
|
||||||
|
{
|
||||||
|
IEssayScanService essayScanService = provider.GetRequiredService<IEssayScanService>();
|
||||||
|
ImageCompressService imageCompressService = provider.GetRequiredService<ImageCompressService>();
|
||||||
|
ConsoleInfoService consoleInfoService = provider.GetRequiredService<ConsoleInfoService>();
|
||||||
|
IOptions<BlogOptions> blogOptions = provider.GetRequiredService<IOptions<BlogOptions>>();
|
||||||
|
ILogger<YaeCommandService> logger = provider.GetRequiredService<ILogger<YaeCommandService>>();
|
||||||
|
IHostApplicationLifetime hostApplicationLifetime =
|
||||||
|
provider.GetRequiredService<IHostApplicationLifetime>();
|
||||||
|
|
||||||
|
return new YaeCommandService(arguments, essayScanService, imageCompressService, consoleInfoService,
|
||||||
|
hostApplicationLifetime, blogOptions, logger);
|
||||||
|
});
|
||||||
|
|
||||||
|
ConsoleInfoService infoService = new();
|
||||||
|
builder.Services.AddSingleton<ConsoleInfoService>(_ => infoService);
|
||||||
|
|
||||||
|
return infoService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddCommonServices()
|
||||||
|
{
|
||||||
builder.Services.AddHttpClient()
|
builder.Services.AddHttpClient()
|
||||||
.AddMarkdig()
|
.AddMarkdig()
|
||||||
.AddYamlParser();
|
.AddYamlParser();
|
||||||
|
|
||||||
|
builder.ConfigureOptions<BlogOptions>(BlogOptions.OptionName)
|
||||||
|
.ConfigureOptions<GiteaOptions>(GiteaOptions.OptionName);
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<IEssayScanService, EssayScanService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IHostApplicationBuilder ConfigureOptions<T>(string optionSectionName) where T : class
|
||||||
|
{
|
||||||
|
builder.Services
|
||||||
|
.AddOptions<T>()
|
||||||
|
.Bind(builder.Configuration.GetSection(optionSectionName))
|
||||||
|
.ValidateDataAnnotations();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension(WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder AddYaeServer(ConsoleInfoService consoleInfoService)
|
||||||
|
{
|
||||||
|
builder.AddCommonServices();
|
||||||
|
|
||||||
builder.Services.AddSingleton<AngleSharp.IConfiguration>(_ => Configuration.Default)
|
builder.Services.AddSingleton<AngleSharp.IConfiguration>(_ => Configuration.Default)
|
||||||
|
.AddSingleton<ConsoleInfoService>(_ => consoleInfoService)
|
||||||
.AddSingleton<IEssayScanService, EssayScanService>()
|
.AddSingleton<IEssayScanService, EssayScanService>()
|
||||||
.AddSingleton<RendererService>()
|
.AddSingleton<RendererService>()
|
||||||
.AddSingleton<IEssayContentService, EssayContentService>()
|
.AddSingleton<IEssayContentService, EssayContentService>()
|
||||||
@@ -32,32 +79,9 @@ public static class WebApplicationBuilderExtensions
|
|||||||
.AddTransient<BlogHotReloadService>()
|
.AddTransient<BlogHotReloadService>()
|
||||||
.AddSingleton<GitHeapMapService>();
|
.AddSingleton<GitHeapMapService>();
|
||||||
|
|
||||||
return builder;
|
builder.Services.AddHostedService<StartServerService>();
|
||||||
}
|
|
||||||
|
|
||||||
public WebApplicationBuilder AddYaeCommand(string[] arguments)
|
|
||||||
{
|
|
||||||
builder.Services.AddHostedService<YaeCommandService>(provider =>
|
|
||||||
{
|
|
||||||
IEssayScanService essayScanService = provider.GetRequiredService<IEssayScanService>();
|
|
||||||
IOptions<BlogOptions> blogOptions = provider.GetRequiredService<IOptions<BlogOptions>>();
|
|
||||||
ILogger<YaeCommandService> logger = provider.GetRequiredService<ILogger<YaeCommandService>>();
|
|
||||||
IHostApplicationLifetime applicationLifetime = provider.GetRequiredService<IHostApplicationLifetime>();
|
|
||||||
|
|
||||||
return new YaeCommandService(arguments, essayScanService, provider, blogOptions, logger,
|
|
||||||
applicationLifetime);
|
|
||||||
});
|
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WebApplicationBuilder ConfigureOptions<T>(string optionSectionName) where T : class
|
|
||||||
{
|
|
||||||
builder.Services
|
|
||||||
.AddOptions<T>()
|
|
||||||
.Bind(builder.Configuration.GetSection(optionSectionName))
|
|
||||||
.ValidateDataAnnotations();
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Processors;
|
using YaeBlog.Processors;
|
||||||
using YaeBlog.Services;
|
using YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Extensions;
|
using YaeBlog.Extensions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Processors;
|
namespace YaeBlog.Processors;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Processors;
|
namespace YaeBlog.Processors;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Processors;
|
namespace YaeBlog.Processors;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
using YaeBlog.Components;
|
using YaeBlog.Components;
|
||||||
using YaeBlog.Extensions;
|
using YaeBlog.Extensions;
|
||||||
|
using YaeBlog.Services;
|
||||||
|
|
||||||
|
HostApplicationBuilder consoleBuilder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
|
ConsoleInfoService consoleInfoService = consoleBuilder.AddYaeCommand(args);
|
||||||
|
|
||||||
|
IHost consoleApp = consoleBuilder.Build();
|
||||||
|
await consoleApp.RunAsync();
|
||||||
|
|
||||||
|
if (consoleInfoService.IsOneShotCommand)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddRazorComponents()
|
builder.Services.AddRazorComponents()
|
||||||
.AddInteractiveServerComponents();
|
.AddInteractiveServerComponents();
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.AddYaeBlog();
|
builder.AddYaeServer(consoleInfoService);
|
||||||
builder.AddYaeCommand(args);
|
|
||||||
|
|
||||||
WebApplication application = builder.Build();
|
WebApplication application = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
14
src/YaeBlog/Services/ConsoleInfoService.cs
Normal file
14
src/YaeBlog/Services/ConsoleInfoService.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
public enum ServerCommand
|
||||||
|
{
|
||||||
|
Serve,
|
||||||
|
Watch
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ConsoleInfoService
|
||||||
|
{
|
||||||
|
public bool IsOneShotCommand { get; set; }
|
||||||
|
|
||||||
|
public ServerCommand Command { get; set; }
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ using System.Text.RegularExpressions;
|
|||||||
using Imageflow.Bindings;
|
using Imageflow.Bindings;
|
||||||
using Imageflow.Fluent;
|
using Imageflow.Fluent;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
using YamlDotNet.Core;
|
using YamlDotNet.Core;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using DotNext;
|
using DotNext;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Extensions;
|
using YaeBlog.Extensions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Text.Json;
|
|||||||
using DotNext;
|
using DotNext;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Imageflow.Fluent;
|
using Imageflow.Fluent;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
@@ -34,6 +34,7 @@ public sealed class ImageCompressService(IEssayScanService essayScanService, ILo
|
|||||||
|
|
||||||
if (needCompressContents.Count == 0)
|
if (needCompressContents.Count == 0)
|
||||||
{
|
{
|
||||||
|
logger.LogInformation("No candidates found to be compressed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ public sealed class ImageCompressService(IEssayScanService essayScanService, ILo
|
|||||||
|
|
||||||
foreach (BlogImageInfo image in uncompressedImages)
|
foreach (BlogImageInfo image in uncompressedImages)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Uncompressed image: {} belonging to blog {}.", image.File.Name,
|
logger.LogInformation("Uncompressed image: {filename} belonging to blog {blog}.", image.File.Name,
|
||||||
content.BlogName);
|
content.BlogName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ public sealed class ImageCompressService(IEssayScanService essayScanService, ILo
|
|||||||
|
|
||||||
logger.LogInformation("Compression ratio: {}%.", (double)compressedSize / uncompressedSize * 100.0);
|
logger.LogInformation("Compression ratio: {}%.", (double)compressedSize / uncompressedSize * 100.0);
|
||||||
|
|
||||||
if (dryRun is false)
|
if (!dryRun)
|
||||||
{
|
{
|
||||||
await Task.WhenAll(from content in compressedContent
|
await Task.WhenAll(from content in compressedContent
|
||||||
select essayScanService.SaveBlogContent(content, content.IsDraft));
|
select essayScanService.SaveBlogContent(content, content.IsDraft));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using YaeBlog.Extensions;
|
using YaeBlog.Extensions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services
|
namespace YaeBlog.Services
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ using System.Diagnostics;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Markdig;
|
using Markdig;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
|||||||
27
src/YaeBlog/Services/StartServerService.cs
Normal file
27
src/YaeBlog/Services/StartServerService.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
|
public sealed class StartServerService(ConsoleInfoService consoleInfoService,
|
||||||
|
RendererService rendererService,
|
||||||
|
BlogHotReloadService blogHotReloadService) : IHostedService
|
||||||
|
{
|
||||||
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
switch (consoleInfoService.Command)
|
||||||
|
{
|
||||||
|
case ServerCommand.Serve:
|
||||||
|
{
|
||||||
|
await rendererService.RenderAsync();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerCommand.Watch:
|
||||||
|
{
|
||||||
|
await blogHotReloadService.StartAsync(cancellationToken);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||||
|
}
|
||||||
@@ -2,30 +2,31 @@
|
|||||||
using System.CommandLine.Invocation;
|
using System.CommandLine.Invocation;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstractions;
|
||||||
using YaeBlog.Core.Exceptions;
|
using YaeBlog.Core.Exceptions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Abstractions.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
public class YaeCommandService(
|
public sealed class YaeCommandService(
|
||||||
string[] arguments,
|
string[] arguments,
|
||||||
IEssayScanService essayScanService,
|
IEssayScanService essayScanService,
|
||||||
IServiceProvider serviceProvider,
|
ImageCompressService imageCompressService,
|
||||||
|
ConsoleInfoService consoleInfoService,
|
||||||
|
IHostApplicationLifetime hostApplicationLifetime,
|
||||||
IOptions<BlogOptions> blogOptions,
|
IOptions<BlogOptions> blogOptions,
|
||||||
ILogger<YaeCommandService> logger,
|
ILogger<YaeCommandService> logger)
|
||||||
IHostApplicationLifetime applicationLifetime)
|
: BackgroundService
|
||||||
: IHostedService
|
|
||||||
{
|
{
|
||||||
private readonly BlogOptions _blogOptions = blogOptions.Value;
|
private readonly BlogOptions _blogOptions = blogOptions.Value;
|
||||||
private bool _oneShotCommandFlag = true;
|
private bool _oneShotCommandFlag = true;
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
RootCommand rootCommand = new("YaeBlog CLI");
|
RootCommand rootCommand = new("YaeBlog CLI");
|
||||||
|
|
||||||
RegisterServeCommand(rootCommand);
|
RegisterServeCommand(rootCommand);
|
||||||
RegisterWatchCommand(rootCommand, cancellationToken);
|
RegisterWatchCommand(rootCommand);
|
||||||
|
|
||||||
RegisterNewCommand(rootCommand);
|
RegisterNewCommand(rootCommand);
|
||||||
RegisterUpdateCommand(rootCommand);
|
RegisterUpdateCommand(rootCommand);
|
||||||
@@ -33,6 +34,10 @@ public class YaeCommandService(
|
|||||||
RegisterPublishCommand(rootCommand);
|
RegisterPublishCommand(rootCommand);
|
||||||
RegisterCompressCommand(rootCommand);
|
RegisterCompressCommand(rootCommand);
|
||||||
|
|
||||||
|
// Shit code: wait for the application starting.
|
||||||
|
// If the command service finished early before the application starting, there will be an ugly exception.
|
||||||
|
await Task.Delay(500, stoppingToken);
|
||||||
|
logger.LogInformation("Running YaeBlog Command.");
|
||||||
int exitCode = await rootCommand.InvokeAsync(arguments);
|
int exitCode = await rootCommand.InvokeAsync(arguments);
|
||||||
|
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
@@ -40,13 +45,14 @@ public class YaeCommandService(
|
|||||||
throw new BlogCommandException($"YaeBlog command exited with no-zero code {exitCode}");
|
throw new BlogCommandException($"YaeBlog command exited with no-zero code {exitCode}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_oneShotCommandFlag)
|
consoleInfoService.IsOneShotCommand = _oneShotCommandFlag;
|
||||||
{
|
|
||||||
applicationLifetime.StopApplication();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
if (!consoleInfoService.IsOneShotCommand)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Start YaeBlog command: {}", consoleInfoService.Command);
|
||||||
|
}
|
||||||
|
hostApplicationLifetime.StopApplication();
|
||||||
|
}
|
||||||
|
|
||||||
private void RegisterServeCommand(RootCommand rootCommand)
|
private void RegisterServeCommand(RootCommand rootCommand)
|
||||||
{
|
{
|
||||||
@@ -59,27 +65,23 @@ public class YaeCommandService(
|
|||||||
rootCommand.SetHandler(HandleServeCommand);
|
rootCommand.SetHandler(HandleServeCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleServeCommand(InvocationContext context)
|
private Task HandleServeCommand(InvocationContext context)
|
||||||
{
|
{
|
||||||
_oneShotCommandFlag = false;
|
_oneShotCommandFlag = false;
|
||||||
|
consoleInfoService.Command = ServerCommand.Serve;
|
||||||
|
|
||||||
logger.LogInformation("Failed to load cache, re-render essays.");
|
return Task.CompletedTask;
|
||||||
RendererService rendererService = serviceProvider.GetRequiredService<RendererService>();
|
|
||||||
await rendererService.RenderAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterWatchCommand(RootCommand rootCommand, CancellationToken cancellationToken)
|
private void RegisterWatchCommand(RootCommand rootCommand)
|
||||||
{
|
{
|
||||||
Command command = new("watch", "Start a blog watcher that re-render when file changes.");
|
Command command = new("watch", "Start a blog watcher that re-render when file changes.");
|
||||||
rootCommand.AddCommand(command);
|
rootCommand.AddCommand(command);
|
||||||
|
|
||||||
command.SetHandler(async _ =>
|
command.SetHandler(_ =>
|
||||||
{
|
{
|
||||||
_oneShotCommandFlag = false;
|
_oneShotCommandFlag = false;
|
||||||
|
consoleInfoService.Command = ServerCommand.Watch;
|
||||||
// BlogHotReloadService is derived from BackgroundService, but we do not let framework trigger it.
|
|
||||||
BlogHotReloadService blogHotReloadService = serviceProvider.GetRequiredService<BlogHotReloadService>();
|
|
||||||
await blogHotReloadService.StartAsync(cancellationToken);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,12 +272,6 @@ public class YaeCommandService(
|
|||||||
getDefaultValue: () => false);
|
getDefaultValue: () => false);
|
||||||
command.AddOption(dryRunOption);
|
command.AddOption(dryRunOption);
|
||||||
|
|
||||||
command.SetHandler(HandleCompressCommand, dryRunOption);
|
command.SetHandler(async dryRun => { await imageCompressService.Compress(dryRun); }, dryRunOption);
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleCompressCommand(bool dryRun)
|
|
||||||
{
|
|
||||||
ImageCompressService imageCompressService = serviceProvider.GetRequiredService<ImageCompressService>();
|
|
||||||
await imageCompressService.Compress(dryRun);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../../third-party/BlazorSvgComponents/src/BlazorSvgComponents/BlazorSvgComponents.csproj" />
|
<ProjectReference Include="../../third-party/BlazorSvgComponents/src/BlazorSvgComponents/BlazorSvgComponents.csproj" />
|
||||||
|
<ProjectReference Include="..\YaeBlog.Abstractions\YaeBlog.Abstractions.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user