239 lines
7.3 KiB
C#
239 lines
7.3 KiB
C#
using AmtScanner.Api.Data;
|
|
using AmtScanner.Api.Models;
|
|
using AmtScanner.Api.Services;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace AmtScanner.Api.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class PowerController : ControllerBase
|
|
{
|
|
private readonly AppDbContext _context;
|
|
private readonly IAmtPowerService _powerService;
|
|
private readonly ICredentialService _credentialService;
|
|
private readonly ILogger<PowerController> _logger;
|
|
|
|
public PowerController(
|
|
AppDbContext context,
|
|
IAmtPowerService powerService,
|
|
ICredentialService credentialService,
|
|
ILogger<PowerController> logger)
|
|
{
|
|
_context = context;
|
|
_powerService = powerService;
|
|
_credentialService = credentialService;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取设备电源状态
|
|
/// </summary>
|
|
[HttpGet("{deviceId}/state")]
|
|
public async Task<ActionResult<ApiResponse<PowerStateResponse>>> GetPowerState(long deviceId)
|
|
{
|
|
var device = await _context.AmtDevices.FindAsync(deviceId);
|
|
if (device == null)
|
|
{
|
|
return Ok(ApiResponse<PowerStateResponse>.Fail(404, "设备不存在"));
|
|
}
|
|
|
|
var credential = await _credentialService.GetDefaultCredentialAsync();
|
|
if (credential == null)
|
|
{
|
|
return Ok(ApiResponse<PowerStateResponse>.Fail(400, "没有配置默认凭据"));
|
|
}
|
|
|
|
var openPorts = new List<int>();
|
|
if (device.AmtOnline)
|
|
{
|
|
// 检测可用端口
|
|
openPorts = await DetectOpenPortsAsync(device.IpAddress);
|
|
}
|
|
|
|
if (openPorts.Count == 0)
|
|
{
|
|
return Ok(ApiResponse<PowerStateResponse>.Success(new PowerStateResponse
|
|
{
|
|
DeviceId = deviceId,
|
|
IpAddress = device.IpAddress,
|
|
Success = false,
|
|
Error = "设备离线或AMT端口不可用"
|
|
}));
|
|
}
|
|
|
|
// 解密密码
|
|
var decryptedPassword = _credentialService.DecryptPassword(credential.Password);
|
|
|
|
var result = await _powerService.GetPowerStateAsync(
|
|
device.IpAddress,
|
|
credential.Username,
|
|
decryptedPassword,
|
|
openPorts);
|
|
|
|
return Ok(ApiResponse<PowerStateResponse>.Success(new PowerStateResponse
|
|
{
|
|
DeviceId = deviceId,
|
|
IpAddress = device.IpAddress,
|
|
Success = result.Success,
|
|
PowerState = result.PowerState,
|
|
PowerStateText = result.PowerStateText,
|
|
Error = result.Error
|
|
}));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 开机
|
|
/// </summary>
|
|
[HttpPost("{deviceId}/power-on")]
|
|
public async Task<ActionResult<ApiResponse<PowerActionResponse>>> PowerOn(long deviceId)
|
|
{
|
|
return await ExecutePowerAction(deviceId, PowerAction.PowerOn);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 关机(优雅关机)
|
|
/// </summary>
|
|
[HttpPost("{deviceId}/power-off")]
|
|
public async Task<ActionResult<ApiResponse<PowerActionResponse>>> PowerOff(long deviceId)
|
|
{
|
|
return await ExecutePowerAction(deviceId, PowerAction.GracefulOff);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 强制关机
|
|
/// </summary>
|
|
[HttpPost("{deviceId}/force-off")]
|
|
public async Task<ActionResult<ApiResponse<PowerActionResponse>>> ForceOff(long deviceId)
|
|
{
|
|
return await ExecutePowerAction(deviceId, PowerAction.PowerOff);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重启(优雅重启)
|
|
/// </summary>
|
|
[HttpPost("{deviceId}/restart")]
|
|
public async Task<ActionResult<ApiResponse<PowerActionResponse>>> Restart(long deviceId)
|
|
{
|
|
return await ExecutePowerAction(deviceId, PowerAction.GracefulReset);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 强制重启
|
|
/// </summary>
|
|
[HttpPost("{deviceId}/force-restart")]
|
|
public async Task<ActionResult<ApiResponse<PowerActionResponse>>> ForceRestart(long deviceId)
|
|
{
|
|
return await ExecutePowerAction(deviceId, PowerAction.Reset);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 电源循环(硬重启)
|
|
/// </summary>
|
|
[HttpPost("{deviceId}/power-cycle")]
|
|
public async Task<ActionResult<ApiResponse<PowerActionResponse>>> PowerCycle(long deviceId)
|
|
{
|
|
return await ExecutePowerAction(deviceId, PowerAction.PowerCycle);
|
|
}
|
|
|
|
private async Task<ActionResult<ApiResponse<PowerActionResponse>>> ExecutePowerAction(long deviceId, PowerAction action)
|
|
{
|
|
var device = await _context.AmtDevices.FindAsync(deviceId);
|
|
if (device == null)
|
|
{
|
|
return Ok(ApiResponse<PowerActionResponse>.Fail(404, "设备不存在"));
|
|
}
|
|
|
|
var credential = await _credentialService.GetDefaultCredentialAsync();
|
|
if (credential == null)
|
|
{
|
|
return Ok(ApiResponse<PowerActionResponse>.Fail(400, "没有配置默认凭据"));
|
|
}
|
|
|
|
// 检测可用端口
|
|
var openPorts = await DetectOpenPortsAsync(device.IpAddress);
|
|
|
|
if (openPorts.Count == 0)
|
|
{
|
|
return Ok(ApiResponse<PowerActionResponse>.Success(new PowerActionResponse
|
|
{
|
|
DeviceId = deviceId,
|
|
IpAddress = device.IpAddress,
|
|
Action = action.ToString(),
|
|
Success = false,
|
|
Error = "AMT端口不可用"
|
|
}));
|
|
}
|
|
|
|
// 解密密码
|
|
var decryptedPassword = _credentialService.DecryptPassword(credential.Password);
|
|
|
|
var result = await _powerService.ChangePowerStateAsync(
|
|
device.IpAddress,
|
|
credential.Username,
|
|
decryptedPassword,
|
|
openPorts,
|
|
action);
|
|
|
|
return Ok(ApiResponse<PowerActionResponse>.Success(new PowerActionResponse
|
|
{
|
|
DeviceId = deviceId,
|
|
IpAddress = device.IpAddress,
|
|
Action = action.ToString(),
|
|
Success = result.Success,
|
|
Message = result.Message,
|
|
Error = result.Error
|
|
}));
|
|
}
|
|
|
|
private async Task<List<int>> DetectOpenPortsAsync(string ipAddress)
|
|
{
|
|
var openPorts = new List<int>();
|
|
int[] amtPorts = { 16992, 16993 };
|
|
|
|
foreach (var port in amtPorts)
|
|
{
|
|
try
|
|
{
|
|
using var client = new System.Net.Sockets.TcpClient();
|
|
var connectTask = client.ConnectAsync(ipAddress, port);
|
|
|
|
if (await Task.WhenAny(connectTask, Task.Delay(1000)) == connectTask)
|
|
{
|
|
if (client.Connected)
|
|
{
|
|
openPorts.Add(port);
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// 端口不可用
|
|
}
|
|
}
|
|
|
|
return openPorts;
|
|
}
|
|
}
|
|
|
|
public class PowerStateResponse
|
|
{
|
|
public long DeviceId { get; set; }
|
|
public string IpAddress { get; set; } = string.Empty;
|
|
public bool Success { get; set; }
|
|
public int PowerState { get; set; }
|
|
public string PowerStateText { get; set; } = string.Empty;
|
|
public string? Error { get; set; }
|
|
}
|
|
|
|
public class PowerActionResponse
|
|
{
|
|
public long DeviceId { get; set; }
|
|
public string IpAddress { get; set; } = string.Empty;
|
|
public string Action { get; set; } = string.Empty;
|
|
public bool Success { get; set; }
|
|
public string Message { get; set; } = string.Empty;
|
|
public string? Error { get; set; }
|
|
}
|