|
|
@ -9,6 +9,7 @@ using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using AngleSharp.Dom;
|
|
|
|
using AngleSharp.Dom;
|
|
|
|
using AngleSharp.Html.Dom;
|
|
|
|
using AngleSharp.Html.Dom;
|
|
|
|
|
|
|
|
using AsyncKeyedLock;
|
|
|
|
using CliFx.Infrastructure;
|
|
|
|
using CliFx.Infrastructure;
|
|
|
|
using DiscordChatExporter.Cli.Commands;
|
|
|
|
using DiscordChatExporter.Cli.Commands;
|
|
|
|
using DiscordChatExporter.Cli.Tests.Utils;
|
|
|
|
using DiscordChatExporter.Cli.Tests.Utils;
|
|
|
@ -20,7 +21,11 @@ namespace DiscordChatExporter.Cli.Tests.Infra;
|
|
|
|
|
|
|
|
|
|
|
|
public static class ExportWrapper
|
|
|
|
public static class ExportWrapper
|
|
|
|
{
|
|
|
|
{
|
|
|
|
private static readonly ConcurrentDictionary<string, SemaphoreSlim> Locks = new(StringComparer.Ordinal);
|
|
|
|
private static readonly AsyncKeyedLocker<string> Locker = new(o =>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
o.PoolSize = 20;
|
|
|
|
|
|
|
|
o.PoolInitialFill = 1;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly string DirPath = Path.Combine(
|
|
|
|
private static readonly string DirPath = Path.Combine(
|
|
|
|
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Directory.GetCurrentDirectory(),
|
|
|
|
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Directory.GetCurrentDirectory(),
|
|
|
@ -46,10 +51,7 @@ public static class ExportWrapper
|
|
|
|
var filePath = Path.Combine(DirPath, fileName);
|
|
|
|
var filePath = Path.Combine(DirPath, fileName);
|
|
|
|
|
|
|
|
|
|
|
|
// Lock separately for each channel and format
|
|
|
|
// Lock separately for each channel and format
|
|
|
|
var channelLock = Locks.GetOrAdd(filePath, _ => new SemaphoreSlim(1, 1));
|
|
|
|
using (await Locker.LockAsync(filePath))
|
|
|
|
await channelLock.WaitAsync();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Perform export only if it hasn't been done before
|
|
|
|
// Perform export only if it hasn't been done before
|
|
|
|
if (!File.Exists(filePath))
|
|
|
|
if (!File.Exists(filePath))
|
|
|
@ -65,10 +67,6 @@ public static class ExportWrapper
|
|
|
|
|
|
|
|
|
|
|
|
return await File.ReadAllTextAsync(filePath);
|
|
|
|
return await File.ReadAllTextAsync(filePath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
finally
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
channelLock.Release();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static async ValueTask<IHtmlDocument> ExportAsHtmlAsync(Snowflake channelId) => Html.Parse(
|
|
|
|
public static async ValueTask<IHtmlDocument> ExportAsHtmlAsync(Snowflake channelId) => Html.Parse(
|
|
|
|