using System.Net.Http; using System.Text; using System.Text.Json; using System.Net; using System.Net.Sockets; using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualBasic.Devices; namespace HeartbeatSender; public class heartbeatSender { private readonly HttpClient httpClient = new(); private string token = ""; private string branchName = ""; private string heartbeatDomain = ""; private CancellationTokenSource? cancellationTokenSource; public static Dictionary DbData = new Dictionary(); public heartbeatSender() { this.heartbeatDomain = Utils.Env.Get("HeartBeatUrl", ""); bool loginSuccess = LoginAndGetTokenAsync().GetAwaiter().GetResult(); Console.WriteLine(loginSuccess ? "心跳登入成功" : "心跳登入失敗"); // 在建構子中啟動背景心跳任務 _ = Task.Run(() => StartAsync()); } public async Task StartAsync() { cancellationTokenSource = new CancellationTokenSource(); while (!cancellationTokenSource.IsCancellationRequested) { try { if (string.IsNullOrEmpty(token)) { bool loginSuccess = await LoginAndGetTokenAsync(); Console.WriteLine(loginSuccess ? "心跳登入成功" : "心跳登入失敗"); } if (!string.IsNullOrEmpty(token)) { await SendHeartbeatAsync(); } await Task.Delay(TimeSpan.FromMinutes(1), cancellationTokenSource.Token); } catch (Exception ex) { Console.WriteLine($"心跳任務錯誤:{ex.Message}"); WriteLog(ex.Message); await Task.Delay(5000); // 錯誤後延遲再跑 } } } public void Stop() { try { cancellationTokenSource?.Cancel(); Console.WriteLine("心跳任務已停止"); } catch (Exception ex) { Console.WriteLine($"心跳任務錯誤:{ex.Message}"); WriteLog(ex.Message); } } public async Task LoginAndGetTokenAsync() { try { var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/receiveRegister"; var loginPayload = new { email = "MachineKTV@gmail.com", password = "aa147258-" }; var result = await SendPostAsync(url, loginPayload); if (result.ValueKind == JsonValueKind.Object && result.TryGetProperty("data", out JsonElement data)) { token = data.GetProperty("token").GetString()!; branchName = data.GetProperty("branch_name").GetString()!; var Dbdatas = data.GetProperty("other_set"); if (Dbdatas.ValueKind == JsonValueKind.Object) { foreach (JsonProperty property in Dbdatas.EnumerateObject()) { DbData.Add(property.Name.ToString(), property.Value.ToString()); } } return true; } return false; } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return default; } } public async Task SendHeartbeatAsync() { try { var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/heartbeat"; string hostName = Dns.GetHostName(); var heartbeatPayload = new { branch_name = branchName, hostname = "PC" + hostName[^3..], ip = GetLocalIPv4(), cpu = GetCpuUsage(), memory = GetTotalMemoryInMB(), disk = GetDiskTotalSizeInGB() }; await SendPostAsync(url, heartbeatPayload, token); Console.WriteLine($"心跳送出成功: {DateTime.Now:HH:mm:ss}"); } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return; } } private async Task SendPostAsync(string url, object payload, string? bearerToken = null) { try { var json = JsonSerializer.Serialize(payload); var content = new StringContent(json, Encoding.UTF8, "application/json"); var request = new HttpRequestMessage(HttpMethod.Post, url) { Content = content }; if (!string.IsNullOrWhiteSpace(bearerToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken); } var response = await httpClient.SendAsync(request); response.EnsureSuccessStatusCode(); string responseJson = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(responseJson); } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return default(T); } } private static string GetLocalIPv4() { try { foreach (var ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList) { if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip)) return ip.ToString(); } return "127.0.0.1"; } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return ""; } } private float GetCpuUsage() { try { using var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); cpuCounter.NextValue(); Thread.Sleep(100); return cpuCounter.NextValue(); } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return float.NaN; } } private float GetTotalMemoryInMB() { try { var ci = new ComputerInfo(); return (ci.TotalPhysicalMemory - ci.AvailablePhysicalMemory) / 1024f; } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return float.NaN; } } private float GetDiskTotalSizeInGB(string driveLetter = "C") { try { var drive = new DriveInfo(driveLetter); return drive.TotalSize / (1024f * 1024f * 1024f); } catch (Exception ex) { Console.WriteLine(ex.Message); WriteLog(ex.Message); return float.NaN; } } public static void WriteLog(string message) { // 指定日志文件的路径 string logFilePath = Path.Combine(Application.StartupPath, "txt", "mainlog.txt"); try { // 使用 StreamWriter 来向日志文件追加文本 using (StreamWriter writer = new StreamWriter(logFilePath, true)) { writer.WriteLine(String.Format("[{0}] {1}", DateTime.Now, message)); } } catch (Exception ex) { // 如果写入日志文件时发生错误,这里可以处理这些异常 // 例如:打印到控制台 Console.WriteLine(String.Format("Error writing to log file: {0}", ex.Message)); } } }