diff --git a/src/Serein.Cli/Utils/CommandLineParserBuilder.cs b/src/Serein.Cli/Utils/CommandLineParserBuilder.cs index fd351fbb..76030010 100644 --- a/src/Serein.Cli/Utils/CommandLineParserBuilder.cs +++ b/src/Serein.Cli/Utils/CommandLineParserBuilder.cs @@ -4,7 +4,6 @@ using System.CommandLine.Invocation; using System.CommandLine.Parsing; using System.Text; -using Sentry; using Serein.Core.Utils; namespace Serein.Cli.Utils; @@ -34,8 +33,6 @@ public static Parser Build(Action mainMethod) private static void OnException(Exception e, InvocationContext? context) { - SentrySdk.CaptureException(e); - var fileName = CrashHelper.CreateLog(e); Console.ForegroundColor = ConsoleColor.Red; diff --git a/src/Serein.Core/Models/Plugins/Js/JsPlugin.cs b/src/Serein.Core/Models/Plugins/Js/JsPlugin.cs index 3317a9f1..0dc64484 100644 --- a/src/Serein.Core/Models/Plugins/Js/JsPlugin.cs +++ b/src/Serein.Core/Models/Plugins/Js/JsPlugin.cs @@ -51,7 +51,7 @@ JsPluginConfig config Info = pluginInfo; FileName = fileName; Config = config; - TimerFactory = new(_cancellationTokenSource.Token); + TimerFactory = new(Info.Name, _pluginLogger, _cancellationTokenSource.Token); Console = new(_pluginLogger, Info.Name); ScriptInstance = new(serviceProvider, this); Engine = serviceProvider.GetRequiredService().Create(this); diff --git a/src/Serein.Core/Services/Commands/HardwareInfoProvider.cs b/src/Serein.Core/Services/Commands/HardwareInfoProvider.cs index 2984bfed..c59d3fba 100644 --- a/src/Serein.Core/Services/Commands/HardwareInfoProvider.cs +++ b/src/Serein.Core/Services/Commands/HardwareInfoProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Timers; using Hardware.Info; @@ -42,6 +43,7 @@ public void Update() } lock (_lock) + { try { _isLoading = true; @@ -52,17 +54,49 @@ public void Update() } else { - Info.RefreshAll(); + Try(Info.RefreshBatteryList); + Try(Info.RefreshBIOSList); + Try(Info.RefreshComputerSystemList); + Try(() => Info.RefreshCPUList()); + Try(Info.RefreshDriveList); + Try(Info.RefreshKeyboardList); + Try(Info.RefreshMemoryList); + Try(Info.RefreshMemoryStatus); + Try(Info.RefreshMonitorList); + Try(Info.RefreshMotherboardList); + Try(Info.RefreshMouseList); + Try(() => Info.RefreshNetworkAdapterList()); + Try(Info.RefreshOperatingSystem); + Try(Info.RefreshPrinterList); + Try(Info.RefreshSoundDeviceList); + Try(Info.RefreshVideoControllerList); } } catch (Exception e) { - _logger.LogError("更新信息失败:{}", e.Message); - _logger.LogDebug(e, "更新信息失败"); + _logger.LogError("初始化失败:{}", e.Message); + _logger.LogDebug(e, "初始化失败"); } finally { _isLoading = false; } + } + + void Try( + Action action, + [CallerArgumentExpression(nameof(action))] string? expression = null + ) + { + try + { + action(); + } + catch (Exception e) + { + _logger.LogError("更新信息失败:{}({})", e.Message, expression); + _logger.LogDebug(e, "更新信息失败"); + } + } } } diff --git a/src/Serein.Core/Services/Plugins/Js/BuiltInModules/FileSystem.Synchronous.cs b/src/Serein.Core/Services/Plugins/Js/BuiltInModules/FileSystem.Synchronous.cs index 72f08f2c..368e4d93 100644 --- a/src/Serein.Core/Services/Plugins/Js/BuiltInModules/FileSystem.Synchronous.cs +++ b/src/Serein.Core/Services/Plugins/Js/BuiltInModules/FileSystem.Synchronous.cs @@ -10,10 +10,27 @@ namespace Serein.Core.Services.Plugins.Js.BuiltInModules; -#pragma warning disable CA1822 - public static partial class FileSystem { + internal static void DisposeAll() + { + foreach (var stream in FileStreams.Values) + { + stream.Close(); + stream.Dispose(); + } + FileStreams.Clear(); + } + + internal static readonly Dictionary FileStreams = []; + + private static FileStream GetFileStream(int fd) + { + return !FileStreams.TryGetValue(fd, out var stream) + ? throw new IOException("Invalid file descriptor") + : stream; + } + public static void AccessSync(string path, int mode = 0) { throw new NotSupportedException(); @@ -56,7 +73,10 @@ public static void ChownSync(string path, int uid, int gid) public static void CloseSync(int fd) { - throw new NotSupportedException(); + var fileStream = GetFileStream(fd); + fileStream.Close(); + fileStream.Dispose(); + FileStreams.Remove(fd); } public static void CopyFileSync(string src, string dest, int flags = 0) @@ -64,7 +84,7 @@ public static void CopyFileSync(string src, string dest, int flags = 0) File.Copy(src, dest, flags != 1); } - public static void Cp(string src, string dest, JsValue? options = default) + public static void CpSync(string src, string dest, JsValue? options = default) { throw new NotSupportedException(); } @@ -96,17 +116,19 @@ public static void FstatSync(int fd, JsValue? options = default) public static void FsyncSync(int fd) { - throw new NotSupportedException(); + GetFileStream(fd).Flush(); } - public static void FtruncateSync(int fd, int len) + public static void FtruncateSync(int fd, int len = 0) { - throw new NotSupportedException(); + GetFileStream(fd).SetLength(len); } - public static void FutimesSync(int fd, int atime, int mtime) + public static void FutimesSync(int fd, DateTime atime, DateTime mtime) { - throw new NotSupportedException(); + var fileStream = GetFileStream(fd); + File.SetLastAccessTime(fileStream.Name, atime); + File.SetLastWriteTime(fileStream.Name, mtime); } public static string[] GlobSync(string pattern, JsValue? options = default) @@ -211,7 +233,7 @@ public static void MkdirSync( { #pragma warning disable CA1416 Directory.CreateDirectory(path, (UnixFileMode)mode); -#pragma warning restore format +#pragma warning restore CA1416 } } @@ -227,9 +249,31 @@ public static void OpendirSync(string path, JsValue? options = default) throw new NotSupportedException(); } - public static void OpenSync(string path, string flags, JsValue? mode = default) + public static int OpenSync(string path, string flags, JsValue? mode = default) { - throw new NotSupportedException(); + var fileStream = new FileStream( + path, + flags switch + { + "r" => FileMode.Open, + "r+" => FileMode.Open, + "rs" => FileMode.Open, + "rs+" => FileMode.Open, + "w" => FileMode.Create, + "wx" => FileMode.CreateNew, + "w+" => FileMode.OpenOrCreate, + "wx+" => FileMode.CreateNew, + "a" => FileMode.Append, + "ax" => FileMode.Append, + "a+" => FileMode.Append, + "ax+" => FileMode.Append, + _ => throw new ArgumentException("Invalid flags", nameof(flags)), + } + ); + + FileStreams.Add(FileStreams.GetHashCode(), fileStream); + + return FileStreams.GetHashCode(); } public static string ReadFileSync(string path, JsValue? options = default) @@ -253,9 +297,9 @@ public static string ReadFileSync(string path, JsValue? options = default) } } - public static void ReaddirSync(string path, JsValue? options = default) + public static string[] ReaddirSync(string path, JsValue? options = default) { - throw new NotSupportedException(); + return Directory.GetFiles(path); } public static void ReadlinkSync(string path, JsValue? options = default) @@ -263,9 +307,11 @@ public static void ReadlinkSync(string path, JsValue? options = default) throw new NotSupportedException(); } - public static void ReadSync(int fd, byte[] buffer, int offset, int length, int position) + public static int ReadSync(int fd, byte[] buffer, int offset, int length, int position = 0) { - throw new NotSupportedException(); + var fileStream = GetFileStream(fd); + fileStream.Seek(position, SeekOrigin.Begin); + return fileStream.Read(buffer, offset, length); } public static void RealpathSync(string path, JsValue? options = default) @@ -344,6 +390,7 @@ public static void TruncateSync(string path, int len = 0) { using var file = File.Open(path, FileMode.Open); file.SetLength(len); + file.Flush(); file.Close(); } @@ -383,13 +430,37 @@ public static void WriteFileSync(string path, byte[] data, JsValue? options = de file.Close(); } - public static void WriteSync(int fd, byte[] buffer) + public static int WriteSync(int fd, byte[] buffer) { - throw new NotSupportedException(); + return WriteSync(fd, buffer, 0, buffer.Length, 0); } - public static void WriteSync(int fd, byte[] buffer, int offset, int length, int position) + public static int WriteSync( + int fd, + byte[] buffer, + int offset = 0, + int? length = null, + int position = 0 + ) { - throw new NotSupportedException(); + var l = length ?? (buffer.Length - offset); + + var fileStream = GetFileStream(fd); + fileStream.Seek(position, SeekOrigin.Begin); + fileStream.Write(buffer, offset, l); + fileStream.Flush(); + + return l; + } + + public static int WriteSync(int fd, string data, int position = 0, string encoding = "utf8") + { + var buffer = ( + encoding.Equals("utf8", StringComparison.InvariantCultureIgnoreCase) + ? EncodingMap.UTF8 + : Encoding.GetEncoding(encoding) + ).GetBytes(data); + + return WriteSync(fd, buffer, 0, buffer.Length, position); } } diff --git a/src/Serein.Core/Services/Plugins/Js/TimerFactory.cs b/src/Serein.Core/Services/Plugins/Js/TimerFactory.cs index 2d4cf2db..6ab6f846 100644 --- a/src/Serein.Core/Services/Plugins/Js/TimerFactory.cs +++ b/src/Serein.Core/Services/Plugins/Js/TimerFactory.cs @@ -3,6 +3,9 @@ using System.Threading; using Jint.Native; using Jint.Native.Function; +using Microsoft.Extensions.Logging; +using Serein.Core.Models.Output; +using Serein.Core.Utils.Extensions; using Timer = System.Timers.Timer; namespace Serein.Core.Services.Plugins.Js; @@ -13,8 +16,14 @@ public sealed class TimerFactory private long _intervalTimerId; private readonly Dictionary _timeoutTimers; private readonly Dictionary _intervalTimers; - - internal TimerFactory(CancellationToken cancellationToken) + private readonly IPluginLogger _pluginLogger; + private readonly string _name; + + internal TimerFactory( + string name, + IPluginLogger pluginLogger, + CancellationToken cancellationToken + ) { _timeoutTimers = []; _intervalTimers = []; @@ -36,6 +45,8 @@ internal TimerFactory(CancellationToken cancellationToken) _timeoutTimers.Clear(); _intervalTimers.Clear(); }); + _pluginLogger = pluginLogger; + _name = name; } public long SetTimeout(JsValue jsValue, long milliseconds, params JsValue[] args) @@ -92,7 +103,7 @@ public void ClearInterval(long id) } } - private static void SafeCall(Function function, params JsValue[] args) + private void SafeCall(Function function, params JsValue[] args) { var entered = false; @@ -108,6 +119,14 @@ private static void SafeCall(Function function, params JsValue[] args) throw new TimeoutException(); } } + catch (Exception e) + { + _pluginLogger.Log( + LogLevel.Error, + _name, + $"An error occurred while calling the function: {e.GetDetailString()}" + ); + } finally { if (entered) diff --git a/src/Serein.Core/Services/Plugins/PluginManager.cs b/src/Serein.Core/Services/Plugins/PluginManager.cs index a18ed290..5ad19487 100644 --- a/src/Serein.Core/Services/Plugins/PluginManager.cs +++ b/src/Serein.Core/Services/Plugins/PluginManager.cs @@ -11,6 +11,7 @@ using Serein.Core.Models.Plugins.Info; using Serein.Core.Services.Permissions; using Serein.Core.Services.Plugins.Js; +using Serein.Core.Services.Plugins.Js.BuiltInModules; using Serein.Core.Services.Plugins.Net; using Serein.Core.Services.Plugins.Storages; using Serein.Core.Utils; @@ -191,6 +192,7 @@ public void Unload() { _eventDispatcher.Dispatch(Event.PluginsUnloading); + FileSystem.DisposeAll(); _netPluginLoader.Unload(); _jsPluginLoader.Unload(); _sessionStorage.Clear(); diff --git a/src/Serein.Core/Services/Servers/ServerBase.cs b/src/Serein.Core/Services/Servers/ServerBase.cs index 84ab396e..1a94f5b0 100644 --- a/src/Serein.Core/Services/Servers/ServerBase.cs +++ b/src/Serein.Core/Services/Servers/ServerBase.cs @@ -166,18 +166,24 @@ protected void OnServerOutput(string line) return; } + _cache.Add(filtered); + + if (_cache.Count > 1) + { + _matcher.QueueServerOutputLine(Id, string.Join('\n', _cache)); + } + if ( - _settingProvider.Value.Application.PattenForEnableMatchingMuiltLines.Any( + !_settingProvider.Value.Application.PattenForEnableMatchingMuiltLines.Any( filtered.Contains ) ) { - _cache.Add(filtered); - _matcher.QueueServerOutputLine(Id, string.Join('\n', _cache)); + _cache.Clear(); } - else + else if (_cache.Count > 100) { - _cache.Clear(); + _cache.RemoveRange(0, _cache.Count - 100); } _matcher.QueueServerOutputLine(Id, filtered); diff --git a/src/Serein.Core/Services/Servers/ServerWithPty.cs b/src/Serein.Core/Services/Servers/ServerWithPty.cs index 1ffeb123..1e2caceb 100644 --- a/src/Serein.Core/Services/Servers/ServerWithPty.cs +++ b/src/Serein.Core/Services/Servers/ServerWithPty.cs @@ -51,6 +51,13 @@ protected override void StartProcess() } _isPreparing = true; + + var cwd = Path.GetDirectoryName(Configuration.FileName); + if (string.IsNullOrEmpty(cwd)) + { + cwd = Directory.GetCurrentDirectory(); + } + PtyProvider .SpawnAsync( new() @@ -58,9 +65,7 @@ protected override void StartProcess() Name = Id, App = Configuration.FileName, CommandLine = [Configuration.Argument], - Cwd = - Path.GetDirectoryName(Configuration.FileName) - ?? Directory.GetCurrentDirectory(), + Cwd = cwd, ForceWinPty = Environment.OSVersion.Platform == PlatformID.Win32NT, Rows = @@ -98,6 +103,7 @@ protected override void StartProcess() { _ptyConnection = null; _process = null; + _streamReader?.Close(); OnServerExit(e.ExitCode); _cancellationTokenSource.Cancel(); }; diff --git a/src/Serein.Core/Utils/UrlConstants.cs b/src/Serein.Core/Utils/UrlConstants.cs index cbc7aabc..a9ebd733 100644 --- a/src/Serein.Core/Utils/UrlConstants.cs +++ b/src/Serein.Core/Utils/UrlConstants.cs @@ -17,8 +17,8 @@ public static class UrlConstants public static readonly string Eula = "https://www.minecraft.net/zh-hans/eula"; - public static readonly string CommercialGuidelines = - "https://account.mojang.com/documents/commercial_guidelines"; + public static readonly string UsageGuidelines = + "https://www.minecraft.net/zh-hans/usage-guidelines"; public static readonly string Docs = "https://sereindev.github.io/"; diff --git a/src/Serein.Lite/Ui/Settings/AboutPage.Designer.cs b/src/Serein.Lite/Ui/Settings/AboutPage.Designer.cs index a79a935e..498eea64 100644 --- a/src/Serein.Lite/Ui/Settings/AboutPage.Designer.cs +++ b/src/Serein.Lite/Ui/Settings/AboutPage.Designer.cs @@ -229,8 +229,8 @@ private void InitializeComponent() DeclarationLinkLabel2.Size = new System.Drawing.Size(304, 31); DeclarationLinkLabel2.TabIndex = 13; DeclarationLinkLabel2.TabStop = true; - DeclarationLinkLabel2.Text = "MINECRAFT 商业使用准则"; - ToolTip.SetToolTip(DeclarationLinkLabel2, UrlConstants.CommercialGuidelines); + DeclarationLinkLabel2.Text = "MINECRAFT 使用准则"; + ToolTip.SetToolTip(DeclarationLinkLabel2, UrlConstants.UsageGuidelines); DeclarationLinkLabel2.VisitedLinkColor = System.Drawing.Color.RoyalBlue; DeclarationLinkLabel2.LinkClicked += DeclarationLinkLabel2_LinkClicked; // diff --git a/src/Serein.Lite/Ui/Settings/AboutPage.cs b/src/Serein.Lite/Ui/Settings/AboutPage.cs index fd5e083e..2456903a 100644 --- a/src/Serein.Lite/Ui/Settings/AboutPage.cs +++ b/src/Serein.Lite/Ui/Settings/AboutPage.cs @@ -24,7 +24,7 @@ private void DeclarationLinkLabel1_LinkClicked(object sender, LinkLabelLinkClick private void DeclarationLinkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - UrlConstants.CommercialGuidelines.OpenInBrowser(); + UrlConstants.UsageGuidelines.OpenInBrowser(); } private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) diff --git a/src/Serein.Plus/Models/ConsoleTextEditor/LineHeaderColorizer.cs b/src/Serein.Plus/Models/ConsoleTextEditor/LineHeaderColorizer.cs index 3c85bd6a..de2ed04e 100644 --- a/src/Serein.Plus/Models/ConsoleTextEditor/LineHeaderColorizer.cs +++ b/src/Serein.Plus/Models/ConsoleTextEditor/LineHeaderColorizer.cs @@ -118,7 +118,10 @@ protected override void ColorizeLine(DocumentLine line) return; } - ChangeLinePart(line.Offset, line.Offset + match.Value.Length, action); + if (action is not null) + { + ChangeLinePart(line.Offset, line.Offset + match.Value.Length, action); + } } private static readonly Regex HeaderRegex = GetHeaderRegex(); diff --git a/src/Serein.Plus/Pages/Settings/AboutPage.xaml b/src/Serein.Plus/Pages/Settings/AboutPage.xaml index d8ff019c..14b8db3c 100644 --- a/src/Serein.Plus/Pages/Settings/AboutPage.xaml +++ b/src/Serein.Plus/Pages/Settings/AboutPage.xaml @@ -92,7 +92,7 @@ FontSize="14" LineHeight="25" TextWrapping="Wrap"> - + @@ -103,8 +103,8 @@ MINECRAFT 最终用户许可协议 - - MINECRAFT 商业使用准则 + + MINECRAFT 使用准则 diff --git a/src/Shared/Utils/DialogFactory.cs b/src/Shared/Utils/DialogFactory.cs index 320d278c..686e1f8d 100644 --- a/src/Shared/Utils/DialogFactory.cs +++ b/src/Shared/Utils/DialogFactory.cs @@ -3,11 +3,13 @@ using Serein.Core.Utils; using Serein.Core.Utils.Extensions; #if LITE + using Ookii.Dialogs.WinForms; namespace Serein.Lite.Utils; #elif PLUS + using Ookii.Dialogs.Wpf; namespace Serein.Plus.Utils; @@ -35,7 +37,7 @@ public static void ShowWelcomeDialog() "如果你是第一次使用Serein,那么一定要仔细阅读以下内容,相信这些会对你有所帮助(๑•̀ㅂ•́)و✧", EnableHyperlinks = true, Footer = - $"使用此软件即视为你已阅读并同意了用户协议", + $"使用此软件即视为你已阅读并同意了使用协议", ExpandedInformation = "此软件与Mojang Studio、网易、Microsoft没有从属关系\n" + $"Serein is licensed under GPL-v3.0\n"