| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- using System.Net;
- using System.Net.Http;
- using System.Net.Http.Json;
- using System.Net.Sockets;
- using System.Text.Json;
- using QuickIP.Client.Models;
- namespace QuickIP.Client.Services;
- public sealed class AgentApiService
- {
- private readonly JsonSerializerOptions _jsonOptions = new()
- {
- PropertyNameCaseInsensitive = true,
- };
- public async Task<HealthCheckResult> CheckHealthAsync(string baseAddress, string password, string localIPv4, CancellationToken cancellationToken = default)
- {
- try
- {
- using var handler = new SocketsHttpHandler();
- if (!string.IsNullOrWhiteSpace(localIPv4))
- {
- handler.ConnectCallback = async (context, token) =>
- {
- var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind(new IPEndPoint(IPAddress.Parse(localIPv4), 0));
- await socket.ConnectAsync(context.DnsEndPoint, token);
- return new NetworkStream(socket, ownsSocket: true);
- };
- }
- using var client = new HttpClient(handler) { BaseAddress = new Uri(baseAddress), Timeout = TimeSpan.FromSeconds(5) };
- client.DefaultRequestHeaders.Add("X-Admin-Password", password);
- using var response = await client.GetAsync("/api/health", cancellationToken);
- return new HealthCheckResult
- {
- Success = response.IsSuccessStatusCode,
- StatusCode = (int)response.StatusCode,
- Message = response.IsSuccessStatusCode
- ? "HTTP 健康检查通过。"
- : $"HTTP 健康检查返回状态码 {(int)response.StatusCode}。",
- };
- }
- catch (Exception ex)
- {
- return new HealthCheckResult
- {
- Success = false,
- StatusCode = null,
- Message = ex.Message,
- };
- }
- }
- public async Task<RemoteDeviceInfo?> GetDeviceInfoAsync(string baseAddress, string password, string localIPv4, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.GetAsync("/api/device/info", cancellationToken);
- if (!response.IsSuccessStatusCode)
- {
- return null;
- }
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteDeviceInfo>>(stream, _jsonOptions, cancellationToken);
- return wrapper?.Data;
- }
- catch
- {
- return null;
- }
- }
- public async Task<RemoteInterfacesInfo?> GetInterfacesAsync(string baseAddress, string password, string localIPv4, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.GetAsync("/api/network/interfaces", cancellationToken);
- if (!response.IsSuccessStatusCode)
- {
- return null;
- }
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteInterfacesInfo>>(stream, _jsonOptions, cancellationToken);
- return wrapper?.Data;
- }
- catch
- {
- return null;
- }
- }
- public async Task<ApiCallResult<RemoteInterfaceConfig>> GetInterfaceConfigAsync(string baseAddress, string password, string localIPv4, string interfaceName, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.GetAsync($"/api/network/config?interface={Uri.EscapeDataString(interfaceName)}", cancellationToken);
- if (!response.IsSuccessStatusCode)
- {
- return new ApiCallResult<RemoteInterfaceConfig>
- {
- Success = false,
- StatusCode = (int)response.StatusCode,
- Message = $"读取接口配置失败,HTTP 状态码 {(int)response.StatusCode}。",
- };
- }
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteInterfaceConfig>>(stream, _jsonOptions, cancellationToken);
- if (wrapper?.Data is null)
- {
- return new ApiCallResult<RemoteInterfaceConfig>
- {
- Success = false,
- Message = "接口配置返回内容为空。",
- };
- }
- return new ApiCallResult<RemoteInterfaceConfig>
- {
- Success = true,
- StatusCode = (int)response.StatusCode,
- Message = "成功",
- Data = wrapper.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteInterfaceConfig>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- public async Task<ApiCallResult<RemoteValidateResult>> ValidateInterfaceConfigAsync(string baseAddress, string password, string localIPv4, RemoteInterfaceConfig input, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.PostAsJsonAsync("/api/network/validate", input, _jsonOptions, cancellationToken);
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteValidateResult>>(stream, _jsonOptions, cancellationToken);
- return new ApiCallResult<RemoteValidateResult>
- {
- Success = response.IsSuccessStatusCode && wrapper?.Data is not null,
- StatusCode = (int)response.StatusCode,
- Message = wrapper?.Message ?? (response.IsSuccessStatusCode ? "校验通过" : $"校验失败,HTTP 状态码 {(int)response.StatusCode}。"),
- Data = wrapper?.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteValidateResult>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- public async Task<ApiCallResult<RemoteApplyTaskResponse>> ApplyInterfaceConfigAsync(string baseAddress, string password, string localIPv4, RemoteInterfaceConfig input, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.PostAsJsonAsync("/api/network/apply", input, _jsonOptions, cancellationToken);
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteApplyTaskResponse>>(stream, _jsonOptions, cancellationToken);
- return new ApiCallResult<RemoteApplyTaskResponse>
- {
- Success = response.IsSuccessStatusCode && wrapper?.Data is not null,
- StatusCode = (int)response.StatusCode,
- Message = wrapper?.Message ?? (response.IsSuccessStatusCode ? "配置任务已提交" : $"提交失败,HTTP 状态码 {(int)response.StatusCode}。"),
- Data = wrapper?.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteApplyTaskResponse>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- public async Task<ApiCallResult<RemoteTaskResult>> GetTaskAsync(string baseAddress, string password, string localIPv4, string taskId, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.GetAsync($"/api/tasks/{Uri.EscapeDataString(taskId)}", cancellationToken);
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteTaskResult>>(stream, _jsonOptions, cancellationToken);
- return new ApiCallResult<RemoteTaskResult>
- {
- Success = response.IsSuccessStatusCode && wrapper?.Data is not null,
- StatusCode = (int)response.StatusCode,
- Message = wrapper?.Message ?? (response.IsSuccessStatusCode ? "成功" : $"任务查询失败,HTTP 状态码 {(int)response.StatusCode}。"),
- Data = wrapper?.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteTaskResult>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- public async Task<ApiCallResult<RemoteApplyTaskResponse>> ConfirmApplyTaskAsync(string baseAddress, string password, string localIPv4, string taskId, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.PostAsJsonAsync("/api/network/apply/confirm", new { task_id = taskId }, _jsonOptions, cancellationToken);
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteApplyTaskResponse>>(stream, _jsonOptions, cancellationToken);
- return new ApiCallResult<RemoteApplyTaskResponse>
- {
- Success = response.IsSuccessStatusCode,
- StatusCode = (int)response.StatusCode,
- Message = wrapper?.Message ?? (response.IsSuccessStatusCode ? "已确认保留配置" : $"确认失败,HTTP 状态码 {(int)response.StatusCode}。"),
- Data = wrapper?.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteApplyTaskResponse>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- public async Task<ApiCallResult<RemoteApplyTaskResponse>> CancelApplyTaskAsync(string baseAddress, string password, string localIPv4, string taskId, CancellationToken cancellationToken = default)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.PostAsJsonAsync("/api/network/apply/cancel", new { task_id = taskId }, _jsonOptions, cancellationToken);
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteApplyTaskResponse>>(stream, _jsonOptions, cancellationToken);
- return new ApiCallResult<RemoteApplyTaskResponse>
- {
- Success = response.IsSuccessStatusCode,
- StatusCode = (int)response.StatusCode,
- Message = wrapper?.Message ?? (response.IsSuccessStatusCode ? "已取消保留配置" : $"取消失败,HTTP 状态码 {(int)response.StatusCode}。"),
- Data = wrapper?.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteApplyTaskResponse>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- public Task<ApiCallResult<RemoteSystemActionResponse>> RebootAsync(string baseAddress, string password, string localIPv4, CancellationToken cancellationToken = default)
- {
- return PostSystemActionAsync(baseAddress, password, localIPv4, "/api/system/reboot", cancellationToken);
- }
- public Task<ApiCallResult<RemoteSystemActionResponse>> ShutdownAsync(string baseAddress, string password, string localIPv4, CancellationToken cancellationToken = default)
- {
- return PostSystemActionAsync(baseAddress, password, localIPv4, "/api/system/shutdown", cancellationToken);
- }
- private HttpClient CreateClient(string baseAddress, string password, string localIPv4)
- {
- var handler = new SocketsHttpHandler();
- if (!string.IsNullOrWhiteSpace(localIPv4))
- {
- handler.ConnectCallback = async (context, token) =>
- {
- var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind(new IPEndPoint(IPAddress.Parse(localIPv4), 0));
- await socket.ConnectAsync(context.DnsEndPoint, token);
- return new NetworkStream(socket, ownsSocket: true);
- };
- }
- var client = new HttpClient(handler) { BaseAddress = new Uri(baseAddress), Timeout = TimeSpan.FromSeconds(5) };
- client.DefaultRequestHeaders.Add("X-Admin-Password", password);
- return client;
- }
- private async Task<ApiCallResult<RemoteSystemActionResponse>> PostSystemActionAsync(string baseAddress, string password, string localIPv4, string path, CancellationToken cancellationToken)
- {
- try
- {
- using var client = CreateClient(baseAddress, password, localIPv4);
- using var response = await client.PostAsync(path, content: null, cancellationToken);
- await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
- var wrapper = await JsonSerializer.DeserializeAsync<ApiEnvelope<RemoteSystemActionResponse>>(stream, _jsonOptions, cancellationToken);
- return new ApiCallResult<RemoteSystemActionResponse>
- {
- Success = response.IsSuccessStatusCode && wrapper?.Data is not null,
- StatusCode = (int)response.StatusCode,
- Message = wrapper?.Message ?? (response.IsSuccessStatusCode ? "系统任务已提交" : $"提交失败,HTTP 状态码 {(int)response.StatusCode}。"),
- Data = wrapper?.Data,
- };
- }
- catch (Exception ex)
- {
- return new ApiCallResult<RemoteSystemActionResponse>
- {
- Success = false,
- Message = ex.Message,
- };
- }
- }
- private sealed class ApiEnvelope<T>
- {
- public int Code { get; set; }
- public string Message { get; set; } = string.Empty;
- public T? Data { get; set; }
- }
- }
|