using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System.Diagnostics; using System.Net; using System.Windows.Controls; using System.Windows.Media; using XFEExtension.NetCore.FormatExtension; using XFEExtension.NetCore.XFEConsole; using XFEToolBox.Profiles.CrossVersionProfiles; using XFEToolBox.Utilities; using XFEToolBox.Views.Pages; namespace XFEToolBox.ViewModel.Pages; public partial class ConsolePageViewModel(ConsolePage viewPage) : ObservableObject { [ObservableProperty] private bool canStartServer = true; [ObservableProperty] private bool canStopServer = false; [ObservableProperty] private bool canRestartServer = false; [ObservableProperty] private bool canCleanUp = false; private bool lastLineIsEnd = true; private bool autoScroll = true; public ConsolePage ViewPage { get; set; } = viewPage; public XFEConsoleTerminalServer? TerminalServer { get; set; } public async Task StartConsoleServer() { TerminalServer = new XFEConsoleTerminalServer(ConsoleProfile.ConsolePort, ConsoleProfile.LocalHostOnly, ConsoleProfile.ConsolePassword); TerminalServer.ServerStarted += TerminalServer_ServerStarted; TerminalServer.Connected += TerminalServer_Connected; TerminalServer.Disconnected += TerminalServer_Disconnected; TerminalServer.MessageReceived += TerminalServer_MessageReceived; TerminalServer.ErrorOccurred += TerminalServer_ErrorOccurred; await TerminalServer.StartServer(); } public void ShutDownServer() { try { TerminalServer?.Server.Server.Close(); TerminalServer?.Server.Server.Abort(); } catch { } TerminalServer = null; } private async void TerminalServer_ErrorOccurred(XFEConsoleClientInfo sender, Exception e) { var code = e.InnerException?.InnerException is HttpListenerException ? (e.InnerException.InnerException as HttpListenerException)!.ErrorCode : 0; if (code != 995) await ShowMessageWithTimeLineAsync($"[foldblock color: white #ff0000 title: 错误:{e.Message} text: {e}]"); } private async void TerminalServer_MessageReceived(XFEConsoleClientInfo sender, string e) { var dictionary = new XFEDictionary(e); var isLine = dictionary["IsLine"] == "true"; var textMessage = dictionary["Text"]; if (lastLineIsEnd) await ShowMessageWithTimeLineAsync($"{sender.ClientName}> {textMessage}", isLine); else await ShowMessageAsync($"{textMessage}", isLine); } private async void TerminalServer_Disconnected(XFEConsoleTerminalServer sender, XFEConsoleClientInfo e) { await ShowMessageWithTimeLineAsync($"[color #9898e7]客户端断开连接 [color white]{e.ClientName}"); } private async void TerminalServer_Connected(XFEConsoleTerminalServer sender, XFEConsoleClientInfo e) { await ShowMessageWithTimeLineAsync($"[color #9898e7]客户端连接 [color white]{e.ClientName}"); } private async void TerminalServer_ServerStarted(XFEConsoleTerminalServer sender) { await ShowMessageWithTimeLineAsync($"控制台服务器已在端口:[hyperlink color: #05ff00 link: http://localhost:{ConsoleProfile.ConsolePort}/ text: {ConsoleProfile.ConsolePort}] 上运行"); } internal void ScrollChanged(object sender, ScrollChangedEventArgs e) { if (e.VerticalChange < 0) autoScroll = false; else if (e.VerticalChange > 0 && e.VerticalOffset + e.ViewportHeight == e.ExtentHeight) autoScroll = true; if (autoScroll) ViewPage.scrollViewer.ScrollToEnd(); } /// /// 显示消息 /// /// /// public void ShowMessage(string message, Color defaultColor, bool isLineEnd, bool forceLine = false) { if (!CanCleanUp) CanCleanUp = true; if (!lastLineIsEnd && !forceLine) { var lastControl = ViewPage.consoleStackPanel.Children.Count > 0 ? ViewPage.consoleStackPanel.Children[^1] : null; if (lastControl is TextBlock lastTextBlock) { ViewPage.Dispatcher.Invoke(() => { var inLineList = DecoratedTextConverter.ConvertToInlineList(message, defaultColor); lastTextBlock.Inlines.AddRange(inLineList); lastLineIsEnd = isLineEnd; }); } return; } ViewPage.Dispatcher.Invoke(() => { var textBlock = DecoratedTextConverter.ConvertToTextBlock(message, defaultColor); textBlock.TextWrapping = System.Windows.TextWrapping.Wrap; textBlock.FontSize = 13; textBlock.FontFamily = new FontFamily("Consolas"); ViewPage.consoleStackPanel.Children.Add(textBlock); }); lastLineIsEnd = isLineEnd; } /// /// 显示消息 /// /// /// public async Task ShowMessageAsync(string message, Color defaultColor, bool isLineEnd, bool forceLine = false) { if (!CanCleanUp) CanCleanUp = true; if (!lastLineIsEnd && !forceLine) { var lastControl = ViewPage.consoleStackPanel.Children.Count > 0 ? ViewPage.consoleStackPanel.Children[^1] : null; if (lastControl is TextBlock lastTextBlock) { var inLineList = await DecoratedTextConverter.ConvertToInlineListAsync(message, defaultColor, ViewPage.Dispatcher); ViewPage.Dispatcher.Invoke(() => { lastTextBlock.Inlines.AddRange(inLineList); lastLineIsEnd = isLineEnd; }); } return; } var textBlock = await DecoratedTextConverter.ConvertToTextBlockAsync(message, defaultColor, ViewPage.Dispatcher); textBlock.TextWrapping = System.Windows.TextWrapping.Wrap; textBlock.FontSize = 13; textBlock.FontFamily = new FontFamily("Consolas"); ViewPage.Dispatcher.Invoke(() => ViewPage.consoleStackPanel.Children.Add(textBlock)); lastLineIsEnd = isLineEnd; } /// /// 显示消息 /// /// public void ShowMessage(string message, bool isLineEnd = true, bool forceLine = false) => ShowMessage(message, Colors.White, isLineEnd, forceLine); /// /// 显示消息 /// /// public async Task ShowMessageAsync(string message, bool isLineEnd = true, bool forceLine = false) => await ShowMessageAsync(message, Colors.White, isLineEnd, forceLine); /// /// 显示附带时间轴的消息 /// /// public void ShowMessageWithTimeLine(string message, bool isLineEnd = true) => ShowMessage($"[{DateTime.Now:HH:mm:ss}] {message}", isLineEnd, true); /// /// 显示附带时间轴的消息 /// /// public async Task ShowMessageWithTimeLineAsync(string message, bool isLineEnd = true) => await ShowMessageAsync($"[{DateTime.Now:HH:mm:ss}] {message}", isLineEnd, true); #region Command [RelayCommand] private async Task StartServer() { CanRestartServer = false; CanStartServer = false; try { await ShowMessageWithTimeLineAsync("[color yellow]正在启动服务器..."); _ = StartConsoleServer(); CanStopServer = true; CanRestartServer = true; } catch (Exception ex) { await ShowMessageWithTimeLineAsync($"[color red]无法启动服务器:{ex}"); CanRestartServer = false; CanStopServer = false; CanStartServer = true; } } [RelayCommand] private async Task StopServer() { CanRestartServer = false; CanStopServer = false; try { ShutDownServer(); CanStartServer = true; await ShowMessageWithTimeLineAsync("[color yellow]服务器已关闭"); } catch (Exception ex) { await ShowMessageWithTimeLineAsync($"[color red]关闭服务器时出现错误:{ex}"); if (TerminalServer is not null && TerminalServer.Server.Server.IsListening) { CanRestartServer = true; CanStopServer = true; } else { CanStartServer = true; } } } [RelayCommand] private async Task RestartServer() { CanRestartServer = false; CanStartServer = false; CanStopServer = false; try { ShutDownServer(); await ShowMessageWithTimeLineAsync("[color yellow]服务器已关闭"); _ = StartConsoleServer(); CanStartServer = false; CanStopServer = true; CanRestartServer = true; await ShowMessageWithTimeLineAsync("[color yellow]服务器重启完成"); } catch (Exception ex) { await ShowMessageWithTimeLineAsync($"[color red]重启服务器时出现错误:{ex}"); if (TerminalServer is not null && TerminalServer.Server.Server.IsListening) { CanRestartServer = true; CanStopServer = true; CanStartServer = false; } else { CanRestartServer = false; CanStopServer = false; CanStartServer = true; } } } [RelayCommand] private void CleanUp() { CanCleanUp = false; ViewPage.consoleStackPanel.Children.Clear(); } #endregion }