feat: 添加arp支持,仅支持管理员模式
This commit is contained in:
		
							
								
								
									
										10
									
								
								.justfile
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.justfile
									
									
									
									
									
								
							@@ -15,11 +15,15 @@ clean:
 | 
				
			|||||||
  rm -rf "dist"
 | 
					  rm -rf "dist"
 | 
				
			||||||
  rm -rf "wwwroot"
 | 
					  rm -rf "wwwroot"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
update:
 | 
					update: update-node update-dotnet
 | 
				
			||||||
  npm install
 | 
					 | 
				
			||||||
  dotnet restore ./server/server.csproj
 | 
					 | 
				
			||||||
  git submodule update --init --remote --recursive
 | 
					  git submodule update --init --remote --recursive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					update-node:
 | 
				
			||||||
 | 
					  npm install
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					update-dotnet:
 | 
				
			||||||
 | 
					  dotnet restore ./server/server.csproj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 生成Restful API到网页客户端
 | 
					# 生成Restful API到网页客户端
 | 
				
			||||||
gen-api:
 | 
					gen-api:
 | 
				
			||||||
  npm run gen-api
 | 
					  npm run gen-api
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -9,11 +9,8 @@ export {}
 | 
				
			|||||||
declare module 'vue' {
 | 
					declare module 'vue' {
 | 
				
			||||||
  export interface GlobalComponents {
 | 
					  export interface GlobalComponents {
 | 
				
			||||||
    Alert: typeof import('./src/components/Alert/Alert.vue')['default']
 | 
					    Alert: typeof import('./src/components/Alert/Alert.vue')['default']
 | 
				
			||||||
    AlertDemo: typeof import('./src/components/AlertDemo.vue')['default']
 | 
					 | 
				
			||||||
    BaseBoard: typeof import('./src/components/equipments/BaseBoard.vue')['default']
 | 
					    BaseBoard: typeof import('./src/components/equipments/BaseBoard.vue')['default']
 | 
				
			||||||
    BaseInputField: typeof import('./src/components/InputField/BaseInputField.vue')['default']
 | 
					    BaseInputField: typeof import('./src/components/InputField/BaseInputField.vue')['default']
 | 
				
			||||||
    Canvas: typeof import('./src/components/Canvas.vue')['default']
 | 
					 | 
				
			||||||
    ChannelConfig: typeof import('./src/components/LogicAnalyzer/ChannelConfig.vue')['default']
 | 
					 | 
				
			||||||
    CollapsibleSection: typeof import('./src/components/CollapsibleSection.vue')['default']
 | 
					    CollapsibleSection: typeof import('./src/components/CollapsibleSection.vue')['default']
 | 
				
			||||||
    ComponentSelector: typeof import('./src/components/LabCanvas/ComponentSelector.vue')['default']
 | 
					    ComponentSelector: typeof import('./src/components/LabCanvas/ComponentSelector.vue')['default']
 | 
				
			||||||
    DDR: typeof import('./src/components/equipments/DDR.vue')['default']
 | 
					    DDR: typeof import('./src/components/equipments/DDR.vue')['default']
 | 
				
			||||||
@@ -22,16 +19,10 @@ declare module 'vue' {
 | 
				
			|||||||
    DiagramCanvas: typeof import('./src/components/LabCanvas/DiagramCanvas.vue')['default']
 | 
					    DiagramCanvas: typeof import('./src/components/LabCanvas/DiagramCanvas.vue')['default']
 | 
				
			||||||
    Dialog: typeof import('./src/components/Dialog.vue')['default']
 | 
					    Dialog: typeof import('./src/components/Dialog.vue')['default']
 | 
				
			||||||
    ETH: typeof import('./src/components/equipments/ETH.vue')['default']
 | 
					    ETH: typeof import('./src/components/equipments/ETH.vue')['default']
 | 
				
			||||||
    FunctionBar: typeof import('./src/components/FunctionBar.vue')['default']
 | 
					 | 
				
			||||||
    HDMI: typeof import('./src/components/equipments/HDMI.vue')['default']
 | 
					    HDMI: typeof import('./src/components/equipments/HDMI.vue')['default']
 | 
				
			||||||
    IpInputField: typeof import('./src/components/InputField/IpInputField.vue')['default']
 | 
					    IpInputField: typeof import('./src/components/InputField/IpInputField.vue')['default']
 | 
				
			||||||
    ItemList: typeof import('./src/components/LabCanvas/ItemList.vue')['default']
 | 
					    ItemList: typeof import('./src/components/LabCanvas/ItemList.vue')['default']
 | 
				
			||||||
    LabCanvas: typeof import('./src/components/LabCanvasNew/LabCanvas.vue')['default']
 | 
					 | 
				
			||||||
    LabCanvasNew: typeof import('./src/components/LabCanvas/LabCanvasNew.vue')['default']
 | 
					 | 
				
			||||||
    LabComponentsDrawer: typeof import('./src/components/LabCanvasNew/LabComponentsDrawer.vue')['default']
 | 
					 | 
				
			||||||
    LabComponentsDrawerNew: typeof import('./src/components/LabCanvas/LabComponentsDrawerNew.vue')['default']
 | 
					 | 
				
			||||||
    LogicalWaveFormDisplay: typeof import('./src/components/LogicAnalyzer/LogicalWaveFormDisplay.vue')['default']
 | 
					    LogicalWaveFormDisplay: typeof import('./src/components/LogicAnalyzer/LogicalWaveFormDisplay.vue')['default']
 | 
				
			||||||
    LoginCard: typeof import('./src/components/LoginCard.vue')['default']
 | 
					 | 
				
			||||||
    MarkdownRenderer: typeof import('./src/components/MarkdownRenderer.vue')['default']
 | 
					    MarkdownRenderer: typeof import('./src/components/MarkdownRenderer.vue')['default']
 | 
				
			||||||
    MechanicalButton: typeof import('./src/components/equipments/MechanicalButton.vue')['default']
 | 
					    MechanicalButton: typeof import('./src/components/equipments/MechanicalButton.vue')['default']
 | 
				
			||||||
    MotherBoard: typeof import('./src/components/equipments/MotherBoard.vue')['default']
 | 
					    MotherBoard: typeof import('./src/components/equipments/MotherBoard.vue')['default']
 | 
				
			||||||
@@ -43,29 +34,15 @@ declare module 'vue' {
 | 
				
			|||||||
    PortInputField: typeof import('./src/components/InputField/PortInputField.vue')['default']
 | 
					    PortInputField: typeof import('./src/components/InputField/PortInputField.vue')['default']
 | 
				
			||||||
    PropertyEditor: typeof import('./src/components/PropertyEditor.vue')['default']
 | 
					    PropertyEditor: typeof import('./src/components/PropertyEditor.vue')['default']
 | 
				
			||||||
    PropertyPanel: typeof import('./src/components/PropertyPanel.vue')['default']
 | 
					    PropertyPanel: typeof import('./src/components/PropertyPanel.vue')['default']
 | 
				
			||||||
    RekaSplitterGroup: typeof import('reka-ui')['SplitterGroup']
 | 
					 | 
				
			||||||
    RouterLink: typeof import('vue-router')['RouterLink']
 | 
					    RouterLink: typeof import('vue-router')['RouterLink']
 | 
				
			||||||
    RouterView: typeof import('vue-router')['RouterView']
 | 
					    RouterView: typeof import('vue-router')['RouterView']
 | 
				
			||||||
    ScrollAreaCorner: typeof import('reka-ui')['ScrollAreaCorner']
 | 
					 | 
				
			||||||
    ScrollAreaRoot: typeof import('reka-ui')['ScrollAreaRoot']
 | 
					 | 
				
			||||||
    ScrollAreaScrollbar: typeof import('reka-ui')['ScrollAreaScrollbar']
 | 
					 | 
				
			||||||
    ScrollAreaThumb: typeof import('reka-ui')['ScrollAreaThumb']
 | 
					 | 
				
			||||||
    ScrollAreaViewport: typeof import('reka-ui')['ScrollAreaViewport']
 | 
					 | 
				
			||||||
    SD: typeof import('./src/components/equipments/SD.vue')['default']
 | 
					    SD: typeof import('./src/components/equipments/SD.vue')['default']
 | 
				
			||||||
    SevenSegmentDisplay: typeof import('./src/components/equipments/SevenSegmentDisplay.vue')['default']
 | 
					    SevenSegmentDisplay: typeof import('./src/components/equipments/SevenSegmentDisplay.vue')['default']
 | 
				
			||||||
    SFP: typeof import('./src/components/equipments/SFP.vue')['default']
 | 
					    SFP: typeof import('./src/components/equipments/SFP.vue')['default']
 | 
				
			||||||
    Sidebar: typeof import('./src/components/Sidebar.vue')['default']
 | 
					    Sidebar: typeof import('./src/components/Sidebar.vue')['default']
 | 
				
			||||||
    SMA: typeof import('./src/components/equipments/SMA.vue')['default']
 | 
					    SMA: typeof import('./src/components/equipments/SMA.vue')['default']
 | 
				
			||||||
    SMT_LED: typeof import('./src/components/equipments/SMT_LED.vue')['default']
 | 
					    SMT_LED: typeof import('./src/components/equipments/SMT_LED.vue')['default']
 | 
				
			||||||
    SplitterGroup: typeof import('reka-ui')['SplitterGroup']
 | 
					 | 
				
			||||||
    SplitterPanel: typeof import('reka-ui')['SplitterPanel']
 | 
					 | 
				
			||||||
    SplitterResizeHandle: typeof import('reka-ui')['SplitterResizeHandle']
 | 
					 | 
				
			||||||
    Switch: typeof import('./src/components/equipments/Switch.vue')['default']
 | 
					    Switch: typeof import('./src/components/equipments/Switch.vue')['default']
 | 
				
			||||||
    TabsContent: typeof import('reka-ui')['TabsContent']
 | 
					 | 
				
			||||||
    TabsIndicator: typeof import('reka-ui')['TabsIndicator']
 | 
					 | 
				
			||||||
    TabsList: typeof import('reka-ui')['TabsList']
 | 
					 | 
				
			||||||
    TabsRoot: typeof import('reka-ui')['TabsRoot']
 | 
					 | 
				
			||||||
    TabsTrigger: typeof import('reka-ui')['TabsTrigger']
 | 
					 | 
				
			||||||
    ThemeControlButton: typeof import('./src/components/ThemeControlButton.vue')['default']
 | 
					    ThemeControlButton: typeof import('./src/components/ThemeControlButton.vue')['default']
 | 
				
			||||||
    ThemeControlToggle: typeof import('./src/components/ThemeControlToggle.vue')['default']
 | 
					    ThemeControlToggle: typeof import('./src/components/ThemeControlToggle.vue')['default']
 | 
				
			||||||
    TriggerSettings: typeof import('./src/components/LogicAnalyzer/TriggerSettings.vue')['default']
 | 
					    TriggerSettings: typeof import('./src/components/LogicAnalyzer/TriggerSettings.vue')['default']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
            sqls
 | 
					            sqls
 | 
				
			||||||
            sql-studio
 | 
					            sql-studio
 | 
				
			||||||
            zlib
 | 
					            zlib
 | 
				
			||||||
 | 
					            bash
 | 
				
			||||||
            # Backend
 | 
					            # Backend
 | 
				
			||||||
            (dotnetCorePackages.combinePackages [
 | 
					            (dotnetCorePackages.combinePackages [
 | 
				
			||||||
              dotnetCorePackages.sdk_9_0
 | 
					              dotnetCorePackages.sdk_9_0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ using System.Text.RegularExpressions;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public static class Arp
 | 
					public static class Arp
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 读取所有 ARP 记录
 | 
					    /// 读取所有 ARP 记录
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -41,6 +43,28 @@ public static class Arp
 | 
				
			|||||||
        return entries;
 | 
					        return entries;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 通过 Ping 动态更新指定 IP 的 ARP 记录
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="ipAddress">要更新的 IP 地址</param>
 | 
				
			||||||
 | 
					    /// <returns>是否成功发送 Ping</returns>
 | 
				
			||||||
 | 
					    public static async Task<bool> UpdateArpEntryByPingAsync(string ipAddress)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
				
			||||||
 | 
					            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            using var ping = new System.Net.NetworkInformation.Ping();
 | 
				
			||||||
 | 
					            var reply = await ping.SendPingAsync(ipAddress, 100);
 | 
				
			||||||
 | 
					            return reply.Status == System.Net.NetworkInformation.IPStatus.Success;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 添加 ARP 记录
 | 
					    /// 添加 ARP 记录
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -48,7 +72,7 @@ public static class Arp
 | 
				
			|||||||
    /// <param name="macAddress">MAC 地址</param>
 | 
					    /// <param name="macAddress">MAC 地址</param>
 | 
				
			||||||
    /// <param name="interfaceName">网络接口名称(可选)</param>
 | 
					    /// <param name="interfaceName">网络接口名称(可选)</param>
 | 
				
			||||||
    /// <returns>是否成功</returns>
 | 
					    /// <returns>是否成功</returns>
 | 
				
			||||||
    public static async Task<bool> AddArpEntryAsync(string ipAddress, string macAddress, string interfaceName = null)
 | 
					    public static async Task<bool> AddArpEntryAsync(string ipAddress, string macAddress, string? interfaceName = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
					        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
				
			||||||
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
					            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
				
			||||||
@@ -74,7 +98,7 @@ public static class Arp
 | 
				
			|||||||
    /// <param name="ipAddress">要删除的 IP 地址</param>
 | 
					    /// <param name="ipAddress">要删除的 IP 地址</param>
 | 
				
			||||||
    /// <param name="interfaceName">网络接口名称(可选)</param>
 | 
					    /// <param name="interfaceName">网络接口名称(可选)</param>
 | 
				
			||||||
    /// <returns>是否成功</returns>
 | 
					    /// <returns>是否成功</returns>
 | 
				
			||||||
    public static async Task<bool> DeleteArpEntryAsync(string ipAddress, string interfaceName = null)
 | 
					    public static async Task<bool> DeleteArpEntryAsync(string ipAddress, string? interfaceName = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
					        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
				
			||||||
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
					            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
				
			||||||
@@ -149,15 +173,13 @@ public static class Arp
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static string GetArpListCommand()
 | 
					    private static string GetArpListCommand()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
 | 
					        return "arp -a";
 | 
				
			||||||
            ? "arp -a"
 | 
					 | 
				
			||||||
            : "arp -a";
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取 ARP 添加命令
 | 
					    /// 获取 ARP 添加命令
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static string GetArpAddCommand(string ipAddress, string macAddress, string interfaceName)
 | 
					    private static string GetArpAddCommand(string ipAddress, string macAddress, string? interfaceName)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
					        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -186,7 +208,7 @@ public static class Arp
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取 ARP 删除命令
 | 
					    /// 获取 ARP 删除命令
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static string GetArpDeleteCommand(string ipAddress, string interfaceName)
 | 
					    private static string GetArpDeleteCommand(string ipAddress, string? interfaceName)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
					        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -238,14 +260,7 @@ public static class Arp
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static string GetArpQueryCommand(string ipAddress)
 | 
					    private static string GetArpQueryCommand(string ipAddress)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
					        return $"arp -a {ipAddress}";
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return $"arp -a {ipAddress}";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return $"arp -n {ipAddress}";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -284,6 +299,8 @@ public static class Arp
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            logger.Debug($"Executing command: {processInfo.FileName} {processInfo.Arguments}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            using var process = new Process { StartInfo = processInfo };
 | 
					            using var process = new Process { StartInfo = processInfo };
 | 
				
			||||||
            process.Start();
 | 
					            process.Start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -292,6 +309,11 @@ public static class Arp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            await process.WaitForExitAsync();
 | 
					            await process.WaitForExitAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            logger.Debug($"Command output: {output}");
 | 
				
			||||||
 | 
					            if (!string.IsNullOrWhiteSpace(error))
 | 
				
			||||||
 | 
					                logger.Debug($"Command error: {error}");
 | 
				
			||||||
 | 
					            logger.Debug($"Command exit code: {process.ExitCode}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new CommandResult
 | 
					            return new CommandResult
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                IsSuccess = process.ExitCode == 0,
 | 
					                IsSuccess = process.ExitCode == 0,
 | 
				
			||||||
@@ -302,6 +324,7 @@ public static class Arp
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            logger.Error(ex, $"Command execution failed: {command}");
 | 
				
			||||||
            return new CommandResult
 | 
					            return new CommandResult
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                IsSuccess = false,
 | 
					                IsSuccess = false,
 | 
				
			||||||
@@ -358,8 +381,8 @@ public static class Arp
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static ArpEntry? ParseUnixArpEntry(string line)
 | 
					    private static ArpEntry? ParseUnixArpEntry(string line)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Unix/Linux arp -a 输出格式: hostname (ip) at mac [ether] on interface
 | 
					        // Unix/Linux arp -a 输出格式: hostname (ip) at mac [ether] PERM on interface
 | 
				
			||||||
        var pattern = @"(\S+)\s+\((\d+\.\d+\.\d+\.\d+)\)\s+at\s+([a-fA-F0-9:]{17})\s+\[(\w+)\]\s+on\s+(\S+)";
 | 
					        var pattern = @"(\S+)\s+\((\d+\.\d+\.\d+\.\d+)\)\s+at\s+([a-fA-F0-9:]{17})\s+\[(\w+)\]\s+(\w+)\s+on\s+(\S+)";
 | 
				
			||||||
        var match = Regex.Match(line, pattern);
 | 
					        var match = Regex.Match(line, pattern);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (match.Success)
 | 
					        if (match.Success)
 | 
				
			||||||
@@ -369,8 +392,8 @@ public static class Arp
 | 
				
			|||||||
                Hostname = match.Groups[1].Value,
 | 
					                Hostname = match.Groups[1].Value,
 | 
				
			||||||
                IpAddress = match.Groups[2].Value,
 | 
					                IpAddress = match.Groups[2].Value,
 | 
				
			||||||
                MacAddress = match.Groups[3].Value,
 | 
					                MacAddress = match.Groups[3].Value,
 | 
				
			||||||
                Type = match.Groups[4].Value,
 | 
					                Type = match.Groups[5].Value,
 | 
				
			||||||
                Interface = match.Groups[5].Value
 | 
					                Interface = match.Groups[6].Value
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -390,6 +413,26 @@ public static class Arp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 判断当前进程是否具有管理员(或 root)权限
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>如果有管理员权限返回 true,否则返回 false</returns>
 | 
				
			||||||
 | 
					    public static bool IsAdministrator()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Windows: 检查当前用户是否为管理员
 | 
				
			||||||
 | 
					            using var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
 | 
				
			||||||
 | 
					            var principal = new System.Security.Principal.WindowsPrincipal(identity);
 | 
				
			||||||
 | 
					            return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Unix/Linux/macOS: 检查是否为 root 用户
 | 
				
			||||||
 | 
					            return Environment.UserName == "root" || (Environment.GetEnvironmentVariable("USER") == "root");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
@@ -397,12 +440,30 @@ public static class Arp
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class ArpEntry
 | 
					public class ArpEntry
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string Hostname { get; set; } = string.Empty;
 | 
					    public string Hostname { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string IpAddress { get; set; } = string.Empty;
 | 
					    public string IpAddress { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string MacAddress { get; set; } = string.Empty;
 | 
					    public string MacAddress { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string Type { get; set; } = string.Empty;
 | 
					    public string Type { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string Interface { get; set; } = string.Empty;
 | 
					    public string Interface { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public override string ToString()
 | 
					    public override string ToString()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $"{IpAddress} -> {MacAddress} ({Interface})";
 | 
					        return $"{IpAddress} -> {MacAddress} ({Interface})";
 | 
				
			||||||
@@ -414,8 +475,20 @@ public class ArpEntry
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class CommandResult
 | 
					public class CommandResult
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public bool IsSuccess { get; set; }
 | 
					    public bool IsSuccess { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string Output { get; set; } = string.Empty;
 | 
					    public string Output { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public string Error { get; set; } = string.Empty;
 | 
					    public string Error { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// [TODO:description]
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public int ExitCode { get; set; }
 | 
					    public int ExitCode { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public static class MsgBus
 | 
					public static class MsgBus
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static readonly UDPServer udpServer = new UDPServer(1234, 12);
 | 
					    private static readonly UDPServer udpServer = new UDPServer(1234, 12);
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取UDP服务器
 | 
					    /// 获取UDP服务器
 | 
				
			||||||
@@ -19,8 +21,13 @@ public static class MsgBus
 | 
				
			|||||||
    /// 通信总线初始化
 | 
					    /// 通信总线初始化
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <returns>无</returns>
 | 
					    /// <returns>无</returns>
 | 
				
			||||||
    public static void Init()
 | 
					    public async static void Init()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        if (!Arp.IsAdministrator())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            logger.Error($"非管理员运行,ARP无法更新,请用管理员权限运行");
 | 
				
			||||||
 | 
					            // throw new Exception($"非管理员运行,ARP无法更新,请用管理员权限运行");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        udpServer.Start();
 | 
					        udpServer.Start();
 | 
				
			||||||
        isRunning = true;
 | 
					        isRunning = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,7 +128,7 @@ public class UDPServer
 | 
				
			|||||||
                if (IsPortInUse(currentPort))
 | 
					                if (IsPortInUse(currentPort))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    throw new ArgumentException(
 | 
					                    throw new ArgumentException(
 | 
				
			||||||
                        $"Port {currentPort} is already in use.",
 | 
					                        $"端口{currentPort}已被占用,无法启动UDP Server",
 | 
				
			||||||
                        nameof(port)
 | 
					                        nameof(port)
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user