2025-06-03 16:52:44 +08:00
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Text.Json; // 適用於 .NET Core 3.0+ / .NET 5/6/7/8
|
2025-05-14 16:25:24 +08:00
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Sockets;
|
2025-06-04 11:09:00 +08:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using Microsoft.VisualBasic.Devices;
|
2025-06-03 16:52:44 +08:00
|
|
|
|
|
|
|
|
|
namespace HeartbeatSender
|
|
|
|
|
{
|
2025-06-04 11:09:00 +08:00
|
|
|
|
|
2025-05-14 16:25:24 +08:00
|
|
|
|
public class heartbeatSender
|
|
|
|
|
{
|
2025-06-03 16:52:44 +08:00
|
|
|
|
private readonly HttpClient httpClient = new HttpClient();
|
|
|
|
|
private string token;
|
2025-06-17 09:23:56 +08:00
|
|
|
|
private string token_heartbeatUrl;
|
|
|
|
|
private string init_heartbeatUrl;
|
2025-06-03 16:52:44 +08:00
|
|
|
|
|
2025-06-17 09:23:56 +08:00
|
|
|
|
public heartbeatSender()
|
2025-06-03 16:52:44 +08:00
|
|
|
|
{
|
2025-06-17 09:23:56 +08:00
|
|
|
|
LoadHeartbeatUrls("txt/HeartBeat.txt");
|
2025-06-03 16:52:44 +08:00
|
|
|
|
}
|
2025-06-17 09:23:56 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 讀取URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="filePath">路徑</param>
|
|
|
|
|
private void LoadHeartbeatUrls(string filePath)
|
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(filePath))
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("找不到 HeartBeat.txt");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string[] lines = File.ReadAllLines(filePath);
|
|
|
|
|
|
|
|
|
|
foreach (string line in lines)
|
|
|
|
|
{
|
|
|
|
|
if (line.StartsWith("init:"))
|
|
|
|
|
{
|
|
|
|
|
init_heartbeatUrl = line.Substring("init:".Length).Trim();
|
|
|
|
|
}
|
|
|
|
|
else if (line.StartsWith("token:"))
|
|
|
|
|
{
|
|
|
|
|
token_heartbeatUrl = line.Substring("token:".Length).Trim();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("init URL: " + init_heartbeatUrl);
|
|
|
|
|
Console.WriteLine("token URL: " + token_heartbeatUrl);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-03 16:52:44 +08:00
|
|
|
|
public static string GetLocalIPv4()
|
|
|
|
|
{
|
|
|
|
|
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"; // fallback
|
|
|
|
|
}
|
|
|
|
|
public async Task<bool> LoginAndGetTokenAsync()
|
2025-05-14 16:25:24 +08:00
|
|
|
|
{
|
2025-06-17 09:23:56 +08:00
|
|
|
|
// init_heartbeat
|
|
|
|
|
//var loginUrl = "http://zqd.superstar.dnsnet.cc/api/room/receiveRegister";
|
2025-06-03 16:52:44 +08:00
|
|
|
|
string hostName = System.Net.Dns.GetHostName();
|
|
|
|
|
|
|
|
|
|
var loginPayload = new
|
|
|
|
|
{
|
|
|
|
|
branch_name = "測試",
|
|
|
|
|
room_name = "PC" + hostName.Substring(Math.Max(0, hostName.Length - 3)),
|
|
|
|
|
room_ip = GetLocalIPv4(),
|
|
|
|
|
email = "MachineKTV@gmail.com",
|
|
|
|
|
password = "aa147258-"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var json = JsonSerializer.Serialize(loginPayload);
|
|
|
|
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-06-17 09:23:56 +08:00
|
|
|
|
var response = await httpClient.PostAsync(init_heartbeatUrl, content);
|
2025-06-03 16:52:44 +08:00
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
|
|
|
|
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
|
// Console.WriteLine("API 回傳內容:" + responseJson);
|
|
|
|
|
|
|
|
|
|
using var doc = JsonDocument.Parse(responseJson);
|
|
|
|
|
if (doc.RootElement.TryGetProperty("data", out JsonElement dataElement) &&
|
|
|
|
|
dataElement.ValueKind == JsonValueKind.Object)
|
|
|
|
|
{
|
|
|
|
|
if (dataElement.TryGetProperty("token", out JsonElement tokenElement))
|
|
|
|
|
{
|
|
|
|
|
token = tokenElement.GetString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Console.WriteLine("登入成功,取得 token:" + token);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"登入失敗:{ex.Message}");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2025-05-14 16:25:24 +08:00
|
|
|
|
}
|
2025-06-03 16:52:44 +08:00
|
|
|
|
|
|
|
|
|
public async Task SendHeartbeatAsync()
|
2025-05-14 16:25:24 +08:00
|
|
|
|
{
|
2025-06-03 16:52:44 +08:00
|
|
|
|
if (string.IsNullOrEmpty(token))
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("請先登入取得 token");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//Console.WriteLine(GetLocalIPv4());
|
|
|
|
|
string hostName = System.Net.Dns.GetHostName();
|
|
|
|
|
|
|
|
|
|
var heartbeatData = new
|
|
|
|
|
{
|
|
|
|
|
branch_name = "測試",
|
|
|
|
|
hostname = "PC" + hostName.Substring(Math.Max(0, hostName.Length - 3)),
|
|
|
|
|
ip = GetLocalIPv4(),
|
2025-06-04 11:09:00 +08:00
|
|
|
|
cpu = GetCpuUsage(),
|
|
|
|
|
memory = GetTotalMemoryInMB(),
|
|
|
|
|
disk = GetDiskTotalSizeInGB()
|
2025-06-03 16:52:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var json = JsonSerializer.Serialize(heartbeatData);
|
|
|
|
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
2025-06-17 09:23:56 +08:00
|
|
|
|
// token_heartbeat
|
|
|
|
|
// heartbeatUrl = "http://zqd.superstar.dnsnet.cc/api/room/heartbeat";
|
|
|
|
|
var request = new HttpRequestMessage(HttpMethod.Post, token_heartbeatUrl);
|
2025-06-03 16:52:44 +08:00
|
|
|
|
request.Content = content;
|
|
|
|
|
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
|
|
|
|
// Console.WriteLine("送出的 JSON:");
|
|
|
|
|
// Console.WriteLine(json);
|
|
|
|
|
var response = await httpClient.SendAsync(request);
|
2025-05-14 16:25:24 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
2025-06-03 16:52:44 +08:00
|
|
|
|
|
|
|
|
|
// Console.WriteLine($"心跳送出狀態:{response.StatusCode}");
|
|
|
|
|
|
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
|
|
|
|
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
|
|
|
|
|
|
using var doc = JsonDocument.Parse(responseJson);
|
|
|
|
|
// Console.WriteLine("API 回傳內容:" + responseJson);
|
|
|
|
|
|
2025-05-14 16:25:24 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2025-06-03 16:52:44 +08:00
|
|
|
|
var errorContent = await response.Content.ReadAsStringAsync();
|
|
|
|
|
Console.WriteLine($"送出心跳錯誤:{ex.Message}");
|
|
|
|
|
Console.WriteLine($"後端回應內容:{errorContent}");
|
2025-05-14 16:25:24 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-03 16:52:44 +08:00
|
|
|
|
|
2025-06-04 11:09:00 +08:00
|
|
|
|
private float GetCpuUsage()
|
|
|
|
|
{
|
|
|
|
|
using var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
|
|
|
|
cpuCounter.NextValue(); // 需要呼叫兩次
|
2025-06-05 16:19:59 +08:00
|
|
|
|
System.Threading.Thread.Sleep(100);
|
2025-06-04 11:09:00 +08:00
|
|
|
|
return cpuCounter.NextValue(); // 回傳的是百分比,例如 25.3
|
|
|
|
|
}
|
|
|
|
|
private float GetTotalMemoryInMB()
|
|
|
|
|
{
|
|
|
|
|
var computerInfo = new ComputerInfo();
|
2025-06-24 10:35:01 +08:00
|
|
|
|
var totalMB = computerInfo.TotalPhysicalMemory / (1024f);
|
|
|
|
|
var availableMB = computerInfo.AvailablePhysicalMemory / (1024f);
|
|
|
|
|
var usedMB = totalMB - availableMB;
|
|
|
|
|
return usedMB; // 轉 MB
|
2025-06-04 11:09:00 +08:00
|
|
|
|
}
|
|
|
|
|
private float GetDiskTotalSizeInGB(string driveLetter = "C")
|
|
|
|
|
{
|
|
|
|
|
var drive = new DriveInfo(driveLetter);
|
|
|
|
|
return drive.TotalSize / (1024f * 1024f * 1024f); // 轉 GB
|
|
|
|
|
}
|
2025-05-14 16:25:24 +08:00
|
|
|
|
}
|
2025-06-03 16:52:44 +08:00
|
|
|
|
}
|