437 lines
16 KiB
C#
437 lines
16 KiB
C#
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 <IP> <номер_диска> [пользователь] [пароль]");
|
|
//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 <IP> <номер_диска> ║");
|
|
Console.WriteLine("║ Вернет статус запрошенного диска ║");
|
|
Console.WriteLine("║ ║");
|
|
Console.WriteLine("║ DahuaDiskChecker.exe <IP> 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<string> 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<string> 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<Disks>(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<T>
|
|
{
|
|
[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<Tank> Tanks { get; set; }
|
|
}
|
|
|
|
public class Tank
|
|
{
|
|
[JsonPropertyName("Device")]
|
|
public List<JsonElement> 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; }
|
|
}
|
|
} |