using CheckEVS; using System; using System.Net.Http; using System.Net.Http.Json; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace DahuaDiskChecker { class Program { static async Task Main(string[] args) { string server = string.Empty; //Console.WriteLine("=== ПРОВЕРКА СОСТОЯНИЯ ДИСКА DAHUA ==="); #if DEBUG Console.WriteLine("Введи ip-адрес EVS:"); server = Console.ReadLine(); Console.WriteLine("Введи номер диска: (0 - количество неисправных, 1-24 - статус указанного"); int diskNumber = Convert.ToInt32(Console.ReadLine()); #else // Парсинг аргументов if (args.Length < 2) { await PromoPrint(); //Console.WriteLine("Использование: DahuaDiskChecker.exe <номер_диска> [пользователь] [пароль]"); //Console.WriteLine("Пример: DahuaDiskChecker.exe 172.16.48.147 10 admin admin"); return; } server = args[0]; if (!int.TryParse(args[1], out int diskNumber)) { //Console.WriteLine("❌ Ошибка: номер диска должен быть числом"); return; } #endif string user = args.Length > 2 ? args[2] : "admin"; string password = args.Length > 3 ? args[3] : "4NUDZhJ7"; try { var checker = new DahuaDiskChecker(); string status = await checker.CheckDiskStatusAsync(server, diskNumber, user, password); // Вывод результата //Console.WriteLine(); //Console.WriteLine(new string('=', 40)); try { Convert.ToInt32(status); Console.WriteLine(status); } catch (Exception) { if (status == "NotFound") { Console.WriteLine("10"); } else if (status == "Good") { Console.WriteLine("0"); } else { Console.WriteLine("1"); } } #if DEBUG Console.ReadKey(); #endif //Console.WriteLine(new string('=', 40)); } catch (Exception ex) { Console.WriteLine($"❌ Ошибка: {ex.Message}"); } } private static async Task PromoPrint() { // ╔ ═ ╦ ╗ ║ ╟ ╤ │ ─ ┷ ╢ ╚ ╝ Console.WriteLine("╔════════════════════════════╤════════════╗"); Console.WriteLine("║ autor: mastankov │ ver: 0.1 ║"); Console.WriteLine("╟────────────────────────────┴────────────╢"); Console.WriteLine("║ Пример: ║"); Console.WriteLine("║ DahuaDiskChecker.exe <номер_диска> ║"); Console.WriteLine("║ Вернет статус запрошенного диска ║"); Console.WriteLine("║ ║"); Console.WriteLine("║ DahuaDiskChecker.exe 0 ║"); Console.WriteLine("║ Вернет количество неисправных дисков ║"); Console.WriteLine("║ ║"); Console.WriteLine("║ Нажми Enter, чтобы выйти ║"); Console.WriteLine("╚═════════════════════════════════════════╝"); //Console.ReadKey(); } } public class DahuaDiskChecker { private readonly HttpClient _httpClient; public DahuaDiskChecker() { _httpClient = new HttpClient(); _httpClient.Timeout = TimeSpan.FromSeconds(30); } // Вычисление MD5 хэша private string CalculateMD5(string input) { using (MD5 md5 = MD5.Create()) { byte[] inputBytes = Encoding.UTF8.GetBytes(input); byte[] hashBytes = md5.ComputeHash(inputBytes); StringBuilder sb = new StringBuilder(); foreach (byte b in hashBytes) { sb.Append(b.ToString("X2")); } return sb.ToString(); } } // Получение сессии private async Task GetSessionAsync(string server, string user, string password) { // 1. Challenge запрос var challengeRequest = new { method = "global.login", @params = new { userName = user, password = "", clientType = "Web3.0" }, id = 1, session = (string)null }; string json = JsonSerializer.Serialize(challengeRequest); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync($"http://{server}/RPC2_Login", content); response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync(); using JsonDocument doc = JsonDocument.Parse(responseJson); var root = doc.RootElement; if (!root.TryGetProperty("result", out var resultProp) || resultProp.GetBoolean()) throw new Exception("Не удалось получить challenge"); string realm = root.GetProperty("params").GetProperty("realm").GetString(); string random = root.GetProperty("params").GetProperty("random").GetString(); string session = root.GetProperty("session").GetString(); // 2. Вычисление пароля string pwdHash = CalculateMD5($"{user}:{realm}:{password}"); string passHash = CalculateMD5($"{user}:{random}:{pwdHash}"); // 3. Авторизация var authRequest = new { method = "global.login", @params = new { userName = user, clientType = "Web3.0", authorityType = "Default", passwordType = "Default", password = passHash }, id = 2, session = session }; json = JsonSerializer.Serialize(authRequest); content = new StringContent(json, Encoding.UTF8, "application/json"); response = await _httpClient.PostAsync($"http://{server}/RPC2_Login", content); response.EnsureSuccessStatusCode(); responseJson = await response.Content.ReadAsStringAsync(); using JsonDocument authDoc = JsonDocument.Parse(responseJson); var authRoot = authDoc.RootElement; if (!authRoot.TryGetProperty("result", out resultProp) || !resultProp.GetBoolean()) throw new Exception("Ошибка авторизации"); return authRoot.GetProperty("session").GetString(); } // Получение состояния диска public async Task CheckDiskStatusAsync(string server, int diskNumber, string user, string password) { try { // Получаем сессию string session = await GetSessionAsync(server, user, password); // Запрос информации о дисках var diskRequest = new { method = "storage.getTankInfo", @params = (object)null, id = 270, session }; string json = JsonSerializer.Serialize(diskRequest); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync($"http://{server}/RPC2", content); response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync(); var listDisk = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson).@params.tank[0].Device; if (diskNumber != 0) { // Парсим ответ для поиска диска string diskStatus = ParseDiskInfo(responseJson, diskNumber); return diskStatus ?? "NotFound"; } else { int countDiskWithError = 0; for (int i = 0; i < listDisk.Count - 2; i++) { if (listDisk[i].PreDiskCheck != "Good" && listDisk[i].PreDiskCheck != "Warn") countDiskWithError++; } return countDiskWithError.ToString(); } } catch (HttpRequestException ex) { throw new Exception($"Ошибка сети: {ex.Message}"); } catch (Exception ex) { throw new Exception($"Ошибка: {ex.Message}"); } } // Парсинг информации о дисках private string ParseDiskInfo(string jsonResponse, int diskNumber) { using JsonDocument doc = JsonDocument.Parse(jsonResponse); var root = doc.RootElement; // Проверяем успешность запроса if (!root.TryGetProperty("result", out var resultProp) || !resultProp.GetBoolean()) return null; // Ищем диски if (!root.TryGetProperty("params", out var paramsProp)) return null; if (!paramsProp.TryGetProperty("tank", out var tanksProp)) return null; // Перебираем все массивы танков (хранилищ) foreach (var tank in tanksProp.EnumerateArray()) { if (!tank.TryGetProperty("Device", out var devicesProp)) continue; // Перебираем устройства в танке foreach (var device in devicesProp.EnumerateArray()) { // Если устройство - строка (как в вашем примере) if (device.ValueKind == JsonValueKind.String) { string deviceStr = device.GetString(); if (deviceStr.Contains($"PhysicNo={diskNumber}")) { // Ищем PreDiskCheck int start = deviceStr.IndexOf("PreDiskCheck="); if (start == -1) return "Unknown"; start += "PreDiskCheck=".Length; int end = deviceStr.IndexOf(';', start); if (end == -1) end = deviceStr.Length; return deviceStr.Substring(start, end - start).Trim(); } } // Если устройство - объект else if (device.ValueKind == JsonValueKind.Object) { // Пробуем получить PhysicNo как строку или число string physicNo = null; if (device.TryGetProperty("PhysicNo", out var physicNoProp)) { if (physicNoProp.ValueKind == JsonValueKind.String) { physicNo = physicNoProp.GetString(); } else if (physicNoProp.ValueKind == JsonValueKind.Number) { physicNo = physicNoProp.GetInt32().ToString(); } } // Если нашли нужный диск if (physicNo == diskNumber.ToString()) { // Получаем статус if (device.TryGetProperty("PreDiskCheck", out var statusProp)) { return statusProp.GetString() ?? "Unknown"; } return "Unknown"; } } } } return null; } } // Классы для десериализации JSON public class DahuaResponse { [JsonPropertyName("result")] public bool Result { get; set; } [JsonPropertyName("session")] public string Session { get; set; } [JsonPropertyName("params")] public T Params { get; set; } [JsonPropertyName("error")] public ErrorInfo Error { get; set; } [JsonPropertyName("id")] public int Id { get; set; } } public class ChallengeData { [JsonPropertyName("authorization")] public string Authorization { get; set; } [JsonPropertyName("random")] public string Random { get; set; } [JsonPropertyName("realm")] public string Realm { get; set; } [JsonPropertyName("opaque")] public string Opaque { get; set; } } public class AuthData { [JsonPropertyName("keepAliveInterval")] public int KeepAliveInterval { get; set; } [JsonPropertyName("isPwdOverdue")] public bool IsPwdOverdue { get; set; } } public class TankInfoData { [JsonPropertyName("tank")] public List Tanks { get; set; } } public class Tank { [JsonPropertyName("Device")] public List Devices { get; set; } [JsonPropertyName("FreeSpace")] public double FreeSpace { get; set; } [JsonPropertyName("Level")] public int Level { get; set; } [JsonPropertyName("SlotNum")] public int SlotNum { get; set; } [JsonPropertyName("TankNo")] public int TankNo { get; set; } [JsonPropertyName("Temperature")] public double Temperature { get; set; } [JsonPropertyName("TotalSpace")] public double TotalSpace { get; set; } } public class Device { [JsonPropertyName("PhysicNo")] public string PhysicNo { get; set; } [JsonPropertyName("PreDiskCheck")] public string PreDiskCheck { get; set; } [JsonPropertyName("Name")] public string Name { get; set; } [JsonPropertyName("SerialNo")] public string SerialNo { get; set; } [JsonPropertyName("Temperature")] public string Temperature { get; set; } [JsonPropertyName("State")] public string State { get; set; } } public class ErrorInfo { [JsonPropertyName("code")] public int Code { get; set; } [JsonPropertyName("message")] public string Message { get; set; } } }