From cf5dae185193353629a16c8117e3fc3d3ee65075 Mon Sep 17 00:00:00 2001 From: Genteure Date: Mon, 19 Apr 2021 18:20:14 +0800 Subject: [PATCH] ToolBox: Better error handling --- .../Parser/FlvTagPipeReader.cs | 6 +- .../Parser/NotFlvFileException.cs | 16 ++ .../Parser/UnknownFlvTagTypeException.cs | 16 ++ BililiveRecorder.ToolBox/CommandResponse.cs | 18 ++ BililiveRecorder.ToolBox/Commands/Analyze.cs | 137 +++++++++++---- BililiveRecorder.ToolBox/Commands/Export.cs | 116 ++++++++++--- BililiveRecorder.ToolBox/Commands/Fix.cs | 163 +++++++++++------- BililiveRecorder.ToolBox/ICommandHandler.cs | 6 +- BililiveRecorder.ToolBox/ICommandRequest.cs | 4 +- BililiveRecorder.ToolBox/ResponseStatus.cs | 12 ++ BililiveRecorder.ToolBox/ToolCommand.cs | 29 +++- .../Pages/ToolboxAutoFixPage.xaml.cs | 68 +++++--- 12 files changed, 436 insertions(+), 155 deletions(-) create mode 100644 BililiveRecorder.Flv/Parser/NotFlvFileException.cs create mode 100644 BililiveRecorder.Flv/Parser/UnknownFlvTagTypeException.cs create mode 100644 BililiveRecorder.ToolBox/CommandResponse.cs create mode 100644 BililiveRecorder.ToolBox/ResponseStatus.cs diff --git a/BililiveRecorder.Flv/Parser/FlvTagPipeReader.cs b/BililiveRecorder.Flv/Parser/FlvTagPipeReader.cs index 506cbd2..54e02d0 100644 --- a/BililiveRecorder.Flv/Parser/FlvTagPipeReader.cs +++ b/BililiveRecorder.Flv/Parser/FlvTagPipeReader.cs @@ -138,10 +138,10 @@ namespace BililiveRecorder.Flv.Parser fileHeaderSlice.CopyTo(stackSpan); if (data[0] != 'F' || data[1] != 'L' || data[2] != 'V' || data[3] != 1) - throw new FlvException("Data is not FLV."); + throw new NotFlvFileException("Data is not FLV."); if (data[5] != 0 || data[6] != 0 || data[7] != 0 || data[8] != 9) - throw new FlvException("Not Supported FLV format."); + throw new NotFlvFileException("Not Supported FLV format."); buffer = buffer.Slice(fileHeaderSlice.End); @@ -180,7 +180,7 @@ namespace BililiveRecorder.Flv.Parser case TagType.Script: break; default: - throw new FlvException("Unexpected Tag Type: " + header[0]); + throw new UnknownFlvTagTypeException("Unknown Tag Type: " + header[0]); } // Read Tag Size diff --git a/BililiveRecorder.Flv/Parser/NotFlvFileException.cs b/BililiveRecorder.Flv/Parser/NotFlvFileException.cs new file mode 100644 index 0000000..484006b --- /dev/null +++ b/BililiveRecorder.Flv/Parser/NotFlvFileException.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.Serialization; + +namespace BililiveRecorder.Flv.Parser +{ + public class NotFlvFileException : FlvException + { + public NotFlvFileException() { } + + public NotFlvFileException(string message) : base(message) { } + + public NotFlvFileException(string message, Exception innerException) : base(message, innerException) { } + + protected NotFlvFileException(SerializationInfo info, StreamingContext context) : base(info, context) { } + } +} diff --git a/BililiveRecorder.Flv/Parser/UnknownFlvTagTypeException.cs b/BililiveRecorder.Flv/Parser/UnknownFlvTagTypeException.cs new file mode 100644 index 0000000..1f45ece --- /dev/null +++ b/BililiveRecorder.Flv/Parser/UnknownFlvTagTypeException.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.Serialization; + +namespace BililiveRecorder.Flv.Parser +{ + public class UnknownFlvTagTypeException : FlvException + { + public UnknownFlvTagTypeException() { } + + public UnknownFlvTagTypeException(string message) : base(message) { } + + public UnknownFlvTagTypeException(string message, Exception innerException) : base(message, innerException) { } + + protected UnknownFlvTagTypeException(SerializationInfo info, StreamingContext context) : base(info, context) { } + } +} diff --git a/BililiveRecorder.ToolBox/CommandResponse.cs b/BililiveRecorder.ToolBox/CommandResponse.cs new file mode 100644 index 0000000..43ba160 --- /dev/null +++ b/BililiveRecorder.ToolBox/CommandResponse.cs @@ -0,0 +1,18 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace BililiveRecorder.ToolBox +{ + public class CommandResponse where TResponse : class + { + [JsonConverter(typeof(StringEnumConverter))] + public ResponseStatus Status { get; set; } + + public TResponse? Result { get; set; } + + public string? ErrorMessage { get; set; } + + public Exception? Exception { get; set; } + } +} diff --git a/BililiveRecorder.ToolBox/Commands/Analyze.cs b/BililiveRecorder.ToolBox/Commands/Analyze.cs index 29c75b6..84b88ab 100644 --- a/BililiveRecorder.ToolBox/Commands/Analyze.cs +++ b/BililiveRecorder.ToolBox/Commands/Analyze.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.IO.Pipelines; using System.Linq; using System.Threading.Tasks; @@ -10,6 +11,7 @@ using BililiveRecorder.Flv.Grouping; using BililiveRecorder.Flv.Parser; using BililiveRecorder.Flv.Pipeline; using BililiveRecorder.Flv.Writer; +using BililiveRecorder.Flv.Xml; using Microsoft.Extensions.DependencyInjection; using Serilog; @@ -40,22 +42,56 @@ namespace BililiveRecorder.ToolBox.Commands { private static readonly ILogger logger = Log.ForContext(); - public Task Handle(AnalyzeRequest request) => this.Handle(request, null); + public Task> Handle(AnalyzeRequest request) => this.Handle(request, null); - public async Task Handle(AnalyzeRequest request, Func? progress) + public async Task> Handle(AnalyzeRequest request, Func? progress) { - var inputPath = Path.GetFullPath(request.Input); - - var memoryStreamProvider = new DefaultMemoryStreamProvider(); - var tagWriter = new AnalyzeMockFlvTagWriter(); - var comments = new List(); - var context = new FlvProcessingContext(); - var session = new Dictionary(); - + try { - using var inputStream = File.OpenRead(inputPath); + var memoryStreamProvider = new DefaultMemoryStreamProvider(); + var tagWriter = new AnalyzeMockFlvTagWriter(); + var comments = new List(); + var context = new FlvProcessingContext(); + var session = new Dictionary(); - using var grouping = new TagGroupReader(new FlvTagPipeReader(PipeReader.Create(inputStream), memoryStreamProvider, skipData: false, logger: logger)); + string? inputPath; + IFlvTagReader tagReader; + FileStream? flvFileStream = null; + + try + { + inputPath = Path.GetFullPath(request.Input); + if (inputPath.EndsWith(".gz", StringComparison.OrdinalIgnoreCase)) + tagReader = await Task.Run(() => + { + using var stream = new GZipStream(File.Open(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress); + var xmlFlvFile = (XmlFlvFile)XmlFlvFile.Serializer.Deserialize(stream); + return new FlvTagListReader(xmlFlvFile.Tags); + }); + else if (inputPath.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) + tagReader = await Task.Run(() => + { + using var stream = File.Open(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read); + var xmlFlvFile = (XmlFlvFile)XmlFlvFile.Serializer.Deserialize(stream); + return new FlvTagListReader(xmlFlvFile.Tags); + }); + else + { + flvFileStream = File.Open(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read); + tagReader = new FlvTagPipeReader(PipeReader.Create(flvFileStream), memoryStreamProvider, skipData: false, logger: logger); + } + } + catch (Exception ex) when (ex is not FlvException) + { + return new CommandResponse + { + Status = ResponseStatus.InputIOError, + Exception = ex, + ErrorMessage = ex.Message + }; + } + + using var grouping = new TagGroupReader(tagReader); using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true); var pipeline = new ProcessingPipelineBuilder(new ServiceCollection().BuildServiceProvider()).AddDefault().AddRemoveFillerData().Build(); @@ -82,32 +118,63 @@ namespace BililiveRecorder.ToolBox.Commands foreach (var tag in dataAction.Tags) tag.BinaryData?.Dispose(); - if (count++ % 10 == 0) - { - progress?.Invoke((double)inputStream.Position / inputStream.Length); - } + if (count++ % 10 == 0 && flvFileStream is not null && progress is not null) + await progress((double)flvFileStream.Position / flvFileStream.Length); } + + var response = await Task.Run(() => + { + var countableComments = comments.Where(x => x.T != CommentType.Logging).ToArray(); + return new AnalyzeResponse + { + InputPath = inputPath, + + NeedFix = tagWriter.OutputFileCount != 1 || countableComments.Any(), + Unrepairable = countableComments.Any(x => x.T == CommentType.Unrepairable), + + OutputFileCount = tagWriter.OutputFileCount, + + IssueTypeOther = countableComments.Count(x => x.T == CommentType.Other), + IssueTypeUnrepairable = countableComments.Count(x => x.T == CommentType.Unrepairable), + IssueTypeTimestampJump = countableComments.Count(x => x.T == CommentType.TimestampJump), + IssueTypeDecodingHeader = countableComments.Count(x => x.T == CommentType.DecodingHeader), + IssueTypeRepeatingData = countableComments.Count(x => x.T == CommentType.RepeatingData) + }; + }); + + return new CommandResponse + { + Status = ResponseStatus.OK, + Result = response + }; } - - var countableComments = comments.Where(x => x.T != CommentType.Logging); - - var response = new AnalyzeResponse + catch (NotFlvFileException ex) { - InputPath = inputPath, - - NeedFix = tagWriter.OutputFileCount != 1 || countableComments.Any(), - Unrepairable = countableComments.Any(x => x.T == CommentType.Unrepairable), - - OutputFileCount = tagWriter.OutputFileCount, - - IssueTypeOther = countableComments.Count(x => x.T == CommentType.Other), - IssueTypeUnrepairable = countableComments.Count(x => x.T == CommentType.Unrepairable), - IssueTypeTimestampJump = countableComments.Count(x => x.T == CommentType.TimestampJump), - IssueTypeDecodingHeader = countableComments.Count(x => x.T == CommentType.DecodingHeader), - IssueTypeRepeatingData = countableComments.Count(x => x.T == CommentType.RepeatingData) - }; - - return response; + return new CommandResponse + { + Status = ResponseStatus.NotFlvFile, + Exception = ex, + ErrorMessage = ex.Message + }; + } + catch (UnknownFlvTagTypeException ex) + { + return new CommandResponse + { + Status = ResponseStatus.UnknownFlvTagType, + Exception = ex, + ErrorMessage = ex.Message + }; + } + catch (Exception ex) + { + return new CommandResponse + { + Status = ResponseStatus.Error, + Exception = ex, + ErrorMessage = ex.Message + }; + } } public void PrintResponse(AnalyzeResponse response) diff --git a/BililiveRecorder.ToolBox/Commands/Export.cs b/BililiveRecorder.ToolBox/Commands/Export.cs index 1608887..d5f639e 100644 --- a/BililiveRecorder.ToolBox/Commands/Export.cs +++ b/BililiveRecorder.ToolBox/Commands/Export.cs @@ -26,41 +26,103 @@ namespace BililiveRecorder.ToolBox.Commands { private static readonly ILogger logger = Log.ForContext(); - public Task Handle(ExportRequest request) => this.Handle(request, null); + public Task> Handle(ExportRequest request) => this.Handle(request, null); - public async Task Handle(ExportRequest request, Func? progress) + public async Task> Handle(ExportRequest request, Func? progress) { - using var inputStream = File.OpenRead(request.Input); - using var outputStream = File.OpenWrite(request.Output); - - var tags = new List(); - + FileStream? inputStream = null, outputStream = null; + try { - using var reader = new FlvTagPipeReader(PipeReader.Create(inputStream), new DefaultMemoryStreamProvider(), skipData: true, logger: logger); - var count = 0; - while (true) + try { - var tag = await reader.ReadTagAsync(default).ConfigureAwait(false); - if (tag is null) break; - tags.Add(tag); - - if (count++ % 300 == 0) - progress?.Invoke((double)inputStream.Position / inputStream.Length); + inputStream = File.Open(request.Input, FileMode.Open, FileAccess.Read, FileShare.Read); } - } - - { - using var writer = new StreamWriter(new GZipStream(outputStream, CompressionLevel.Optimal)); - XmlFlvFile.Serializer.Serialize(writer, new XmlFlvFile + catch (Exception ex) { - Tags = tags - }); - } + return new CommandResponse + { + Status = ResponseStatus.InputIOError, + Exception = ex, + ErrorMessage = ex.Message + }; + } - return new ExportResponse(); + try + { + outputStream = File.OpenWrite(request.Output); + } + catch (Exception ex) + { + return new CommandResponse + { + Status = ResponseStatus.OutputIOError, + Exception = ex, + ErrorMessage = ex.Message + }; + } + + var tags = await Task.Run(async () => + { + var count = 0; + var tags = new List(); + using var reader = new FlvTagPipeReader(PipeReader.Create(inputStream), new DefaultMemoryStreamProvider(), skipData: true, logger: logger); + while (true) + { + var tag = await reader.ReadTagAsync(default).ConfigureAwait(false); + if (tag is null) break; + tags.Add(tag); + + if (count++ % 300 == 0 && progress is not null) + await progress((double)inputStream.Position / inputStream.Length); + } + return tags; + }); + + await Task.Run(() => + { + using var writer = new StreamWriter(new GZipStream(outputStream, CompressionLevel.Optimal)); + XmlFlvFile.Serializer.Serialize(writer, new XmlFlvFile + { + Tags = tags + }); + }); + + return new CommandResponse { Status = ResponseStatus.OK, Result = new ExportResponse() }; + } + catch (NotFlvFileException ex) + { + return new CommandResponse + { + Status = ResponseStatus.NotFlvFile, + Exception = ex, + ErrorMessage = ex.Message + }; + } + catch (UnknownFlvTagTypeException ex) + { + return new CommandResponse + { + Status = ResponseStatus.UnknownFlvTagType, + Exception = ex, + ErrorMessage = ex.Message + }; + } + catch (Exception ex) + { + return new CommandResponse + { + Status = ResponseStatus.Error, + Exception = ex, + ErrorMessage = ex.Message + }; + } + finally + { + inputStream?.Dispose(); + outputStream?.Dispose(); + } } - public void PrintResponse(ExportResponse response) - { } + public void PrintResponse(ExportResponse response) => Console.WriteLine("OK"); } } diff --git a/BililiveRecorder.ToolBox/Commands/Fix.cs b/BililiveRecorder.ToolBox/Commands/Fix.cs index 7fb9a7c..6c1c507 100644 --- a/BililiveRecorder.ToolBox/Commands/Fix.cs +++ b/BililiveRecorder.ToolBox/Commands/Fix.cs @@ -43,79 +43,126 @@ namespace BililiveRecorder.ToolBox.Commands { private static readonly ILogger logger = Log.ForContext(); - public Task Handle(FixRequest request) => this.Handle(request, null); + public Task> Handle(FixRequest request) => this.Handle(request, null); - public async Task Handle(FixRequest request, Func? progress) + public async Task> Handle(FixRequest request, Func? progress) { - var inputPath = Path.GetFullPath(request.Input); - - var outputPaths = new List(); - var targetProvider = new AutoFixFlvWriterTargetProvider(request.OutputBase); - targetProvider.BeforeFileOpen += (sender, path) => outputPaths.Add(path); - - var memoryStreamProvider = new DefaultMemoryStreamProvider(); - var tagWriter = new FlvTagFileWriter(targetProvider, memoryStreamProvider, logger); - - var comments = new List(); - var context = new FlvProcessingContext(); - var session = new Dictionary(); - + FileStream? inputStream = null; + try { - using var inputStream = File.OpenRead(inputPath); + var inputPath = Path.GetFullPath(request.Input); - using var grouping = new TagGroupReader(new FlvTagPipeReader(PipeReader.Create(inputStream), memoryStreamProvider, skipData: false, logger: logger)); - using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true); - var pipeline = new ProcessingPipelineBuilder(new ServiceCollection().BuildServiceProvider()).AddDefault().AddRemoveFillerData().Build(); + var outputPaths = new List(); + var targetProvider = new AutoFixFlvWriterTargetProvider(request.OutputBase); + targetProvider.BeforeFileOpen += (sender, path) => outputPaths.Add(path); + + var memoryStreamProvider = new DefaultMemoryStreamProvider(); + var tagWriter = new FlvTagFileWriter(targetProvider, memoryStreamProvider, logger); + + var comments = new List(); + var context = new FlvProcessingContext(); + var session = new Dictionary(); - var count = 0; - while (true) { - var group = await grouping.ReadGroupAsync(default).ConfigureAwait(false); - if (group is null) - break; - - context.Reset(group, session); - pipeline(context); - - if (context.Comments.Count > 0) + try { - comments.AddRange(context.Comments); - logger.Debug("修复逻辑输出 {@Comments}", context.Comments); + inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read); + } + catch (Exception ex) when (ex is not FlvException) + { + return new CommandResponse + { + Status = ResponseStatus.InputIOError, + Exception = ex, + ErrorMessage = ex.Message + }; } - await writer.WriteAsync(context).ConfigureAwait(false); + using var grouping = new TagGroupReader(new FlvTagPipeReader(PipeReader.Create(inputStream), memoryStreamProvider, skipData: false, logger: logger)); + using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true); + var pipeline = new ProcessingPipelineBuilder(new ServiceCollection().BuildServiceProvider()).AddDefault().AddRemoveFillerData().Build(); - foreach (var action in context.Actions) - if (action is PipelineDataAction dataAction) - foreach (var tag in dataAction.Tags) - tag.BinaryData?.Dispose(); - - if (count++ % 10 == 0) + var count = 0; + while (true) { - progress?.Invoke((double)inputStream.Position / inputStream.Length); + var group = await grouping.ReadGroupAsync(default).ConfigureAwait(false); + if (group is null) + break; + + context.Reset(group, session); + pipeline(context); + + if (context.Comments.Count > 0) + { + comments.AddRange(context.Comments); + logger.Debug("修复逻辑输出 {@Comments}", context.Comments); + } + + await writer.WriteAsync(context).ConfigureAwait(false); + + foreach (var action in context.Actions) + if (action is PipelineDataAction dataAction) + foreach (var tag in dataAction.Tags) + tag.BinaryData?.Dispose(); + + if (count++ % 10 == 0 && progress is not null) + await progress((double)inputStream.Position / inputStream.Length); } } + + var response = await Task.Run(() => + { + var countableComments = comments.Where(x => x.T != CommentType.Logging).ToArray(); + return new FixResponse + { + InputPath = inputPath, + OutputPaths = outputPaths.ToArray(), + OutputFileCount = outputPaths.Count, + + NeedFix = outputPaths.Count != 1 || countableComments.Any(), + Unrepairable = countableComments.Any(x => x.T == CommentType.Unrepairable), + + IssueTypeOther = countableComments.Count(x => x.T == CommentType.Other), + IssueTypeUnrepairable = countableComments.Count(x => x.T == CommentType.Unrepairable), + IssueTypeTimestampJump = countableComments.Count(x => x.T == CommentType.TimestampJump), + IssueTypeDecodingHeader = countableComments.Count(x => x.T == CommentType.DecodingHeader), + IssueTypeRepeatingData = countableComments.Count(x => x.T == CommentType.RepeatingData) + }; + }); + + return new CommandResponse { Status = ResponseStatus.OK, Result = response }; } - - var countableComments = comments.Where(x => x.T != CommentType.Logging); - - var response = new FixResponse + catch (NotFlvFileException ex) { - InputPath = inputPath, - OutputPaths = outputPaths.ToArray(), - OutputFileCount = outputPaths.Count, - - NeedFix = outputPaths.Count != 1 || countableComments.Any(), - Unrepairable = countableComments.Any(x => x.T == CommentType.Unrepairable), - - IssueTypeOther = countableComments.Count(x => x.T == CommentType.Other), - IssueTypeUnrepairable = countableComments.Count(x => x.T == CommentType.Unrepairable), - IssueTypeTimestampJump = countableComments.Count(x => x.T == CommentType.TimestampJump), - IssueTypeDecodingHeader = countableComments.Count(x => x.T == CommentType.DecodingHeader), - IssueTypeRepeatingData = countableComments.Count(x => x.T == CommentType.RepeatingData) - }; - - return response; + return new CommandResponse + { + Status = ResponseStatus.NotFlvFile, + Exception = ex, + ErrorMessage = ex.Message + }; + } + catch (UnknownFlvTagTypeException ex) + { + return new CommandResponse + { + Status = ResponseStatus.UnknownFlvTagType, + Exception = ex, + ErrorMessage = ex.Message + }; + } + catch (Exception ex) + { + return new CommandResponse + { + Status = ResponseStatus.Error, + Exception = ex, + ErrorMessage = ex.Message + }; + } + finally + { + inputStream?.Dispose(); + } } public void PrintResponse(FixResponse response) diff --git a/BililiveRecorder.ToolBox/ICommandHandler.cs b/BililiveRecorder.ToolBox/ICommandHandler.cs index 421fd87..bfdb607 100644 --- a/BililiveRecorder.ToolBox/ICommandHandler.cs +++ b/BililiveRecorder.ToolBox/ICommandHandler.cs @@ -2,9 +2,11 @@ using System.Threading.Tasks; namespace BililiveRecorder.ToolBox { - public interface ICommandHandler where TRequest : ICommandRequest + public interface ICommandHandler + where TRequest : ICommandRequest + where TResponse : class { - Task Handle(TRequest request); + Task> Handle(TRequest request); void PrintResponse(TResponse response); } } diff --git a/BililiveRecorder.ToolBox/ICommandRequest.cs b/BililiveRecorder.ToolBox/ICommandRequest.cs index 683b1d7..3109ce5 100644 --- a/BililiveRecorder.ToolBox/ICommandRequest.cs +++ b/BililiveRecorder.ToolBox/ICommandRequest.cs @@ -1,4 +1,6 @@ namespace BililiveRecorder.ToolBox { - public interface ICommandRequest { } + public interface ICommandRequest + where TResponse : class + { } } diff --git a/BililiveRecorder.ToolBox/ResponseStatus.cs b/BililiveRecorder.ToolBox/ResponseStatus.cs new file mode 100644 index 0000000..b8b7c08 --- /dev/null +++ b/BililiveRecorder.ToolBox/ResponseStatus.cs @@ -0,0 +1,12 @@ +namespace BililiveRecorder.ToolBox +{ + public enum ResponseStatus + { + Error = 0, + OK, + NotFlvFile, + UnknownFlvTagType, + InputIOError, + OutputIOError, + } +} diff --git a/BililiveRecorder.ToolBox/ToolCommand.cs b/BililiveRecorder.ToolBox/ToolCommand.cs index ad517bc..1890ae9 100644 --- a/BililiveRecorder.ToolBox/ToolCommand.cs +++ b/BililiveRecorder.ToolBox/ToolCommand.cs @@ -29,25 +29,27 @@ namespace BililiveRecorder.ToolBox }); } - private void RegisterCommand(string name, string? description, Action configure) - where IHandler : ICommandHandler - where IRequest : ICommandRequest + private void RegisterCommand(string name, string? description, Action configure) + where THandler : ICommandHandler + where TRequest : ICommandRequest + where TResponse : class { var cmd = new Command(name, description) { new Option("--json", "print result as json string"), new Option("--json-indented", "print result as indented json string") }; - cmd.Handler = CommandHandler.Create((IRequest r, bool json, bool jsonIndented) => RunSubCommand(r, json, jsonIndented)); + cmd.Handler = CommandHandler.Create((TRequest r, bool json, bool jsonIndented) => RunSubCommand(r, json, jsonIndented)); configure(cmd); this.Add(cmd); } - private static async Task RunSubCommand(IRequest request, bool json, bool jsonIndented) - where IHandler : ICommandHandler - where IRequest : ICommandRequest + private static async Task RunSubCommand(TRequest request, bool json, bool jsonIndented) + where THandler : ICommandHandler + where TRequest : ICommandRequest + where TResponse : class { - var handler = Activator.CreateInstance(); + var handler = Activator.CreateInstance(); var response = await handler.Handle(request).ConfigureAwait(false); @@ -58,7 +60,16 @@ namespace BililiveRecorder.ToolBox } else { - handler.PrintResponse(response); + if (response.Status == ResponseStatus.OK) + { + handler.PrintResponse(response.Result!); + } + else + { + Console.Write("Error: "); + Console.WriteLine(response.Status); + Console.WriteLine(response.ErrorMessage); + } } return 0; diff --git a/BililiveRecorder.WPF/Pages/ToolboxAutoFixPage.xaml.cs b/BililiveRecorder.WPF/Pages/ToolboxAutoFixPage.xaml.cs index f09c833..2931fed 100644 --- a/BililiveRecorder.WPF/Pages/ToolboxAutoFixPage.xaml.cs +++ b/BililiveRecorder.WPF/Pages/ToolboxAutoFixPage.xaml.cs @@ -1,21 +1,10 @@ using System; -using System.Collections.Generic; using System.IO; -using System.IO.Compression; -using System.IO.Pipelines; -using System.Linq; using System.Threading.Tasks; using System.Windows; -using BililiveRecorder.Flv; -using BililiveRecorder.Flv.Grouping; -using BililiveRecorder.Flv.Parser; -using BililiveRecorder.Flv.Pipeline; -using BililiveRecorder.Flv.Writer; -using BililiveRecorder.Flv.Xml; +using BililiveRecorder.ToolBox; using BililiveRecorder.ToolBox.Commands; using BililiveRecorder.WPF.Controls; -using BililiveRecorder.WPF.Models; -using Microsoft.Extensions.DependencyInjection; using Microsoft.WindowsAPICodePack.Dialogs; using Serilog; @@ -50,7 +39,8 @@ namespace BililiveRecorder.WPF.Pages NavigateToShortcut = true, Filters = { - new CommonFileDialogFilter("Flv files",".flv") + new CommonFileDialogFilter("Flv files",".flv"), + new CommonFileDialogFilter("Flv Xml files",".xml,.gz") } }; if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok) @@ -109,13 +99,25 @@ namespace BililiveRecorder.WPF.Pages }); }).ConfigureAwait(true); + if (resp.Status != ResponseStatus.OK) + { + logger.Warning(resp.Exception, "修复时发生错误 (@Status)", resp.Status); + await Task.Run(() => + { + // TODO 翻译 + // 例:在读取文件时发生了错误 + // 选择的不是 FLV 文件 + // FLV 文件格式错误 + MessageBox.Show($"错误类型: {resp.Status}\n{resp.ErrorMessage}", "修复时发生错误", MessageBoxButton.OK, MessageBoxImage.Warning); + }).ConfigureAwait(true); + } + progressDialog.Hide(); await showTask.ConfigureAwait(true); } catch (Exception ex) { - logger.Error(ex, "修复时发生错误"); - MessageBox.Show("修复时发生错误\n" + ex.Message); + logger.Error(ex, "修复时发生未处理的错误"); } finally { @@ -156,15 +158,29 @@ namespace BililiveRecorder.WPF.Pages }); }).ConfigureAwait(true); - this.analyzeResultDisplayArea.DataContext = resp; + if (resp.Status != ResponseStatus.OK) + { + logger.Warning(resp.Exception, "分析时发生错误 (@Status)", resp.Status); + await Task.Run(() => + { + // TODO 翻译 + // 例:在读取文件时发生了错误 + // 选择的不是 FLV 文件 + // FLV 文件格式错误 + MessageBox.Show($"错误类型: {resp.Status}\n{resp.ErrorMessage}", "分析时发生错误", MessageBoxButton.OK, MessageBoxImage.Warning); + }).ConfigureAwait(true); + } + else + { + this.analyzeResultDisplayArea.DataContext = resp.Result; + } progressDialog.Hide(); await showTask.ConfigureAwait(true); } catch (Exception ex) { - logger.Error(ex, "分析时发生错误"); - MessageBox.Show("分析时发生错误\n" + ex.Message); + logger.Error(ex, "分析时发生未处理的错误"); } finally { @@ -230,13 +246,25 @@ namespace BililiveRecorder.WPF.Pages }); }).ConfigureAwait(true); + if (resp.Status != ResponseStatus.OK) + { + logger.Warning(resp.Exception, "导出分析数据时发生错误 (@Status)", resp.Status); + await Task.Run(() => + { + // TODO 翻译 + // 例:在读取文件时发生了错误 + // 选择的不是 FLV 文件 + // FLV 文件格式错误 + MessageBox.Show($"错误类型: {resp.Status}\n{resp.ErrorMessage}", "导出分析数据时发生错误", MessageBoxButton.OK, MessageBoxImage.Warning); + }).ConfigureAwait(true); + } + progressDialog.Hide(); await showTask.ConfigureAwait(true); } catch (Exception ex) { - logger.Error(ex, "导出时发生错误"); - MessageBox.Show("导出时发生错误\n" + ex.Message); + logger.Error(ex, "导出时发生未处理的错误"); } finally {