208 lines
8.2 KiB
C#
208 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
|
|
namespace HanvonF710XAttendanceService
|
|
{
|
|
internal sealed class DeviceSettingsConfig
|
|
{
|
|
public string Mode { get; private set; }
|
|
public int? SiteId { get; private set; }
|
|
public List<DeviceRule> Devices { get; } = new List<DeviceRule>();
|
|
public TemplateTransferConfig TemplateTransfer { get; private set; }
|
|
|
|
public static bool TryLoad(string path, out DeviceSettingsConfig config, out string error)
|
|
{
|
|
config = null;
|
|
error = null;
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path))
|
|
{
|
|
error = "Device settings path is empty.";
|
|
return false;
|
|
}
|
|
|
|
if (!File.Exists(path))
|
|
{
|
|
config = new DeviceSettingsConfig();
|
|
return true;
|
|
}
|
|
|
|
var doc = XDocument.Load(path);
|
|
var root = doc.Root;
|
|
if (root == null || !string.Equals(root.Name.LocalName, "DeviceSettings", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
error = $"Invalid device settings root element. Expected <DeviceSettings>, found <{root?.Name.LocalName ?? "null"}>.";
|
|
return false;
|
|
}
|
|
|
|
var parsed = new DeviceSettingsConfig
|
|
{
|
|
Mode = (string)root.Attribute("Mode")
|
|
};
|
|
|
|
var rootSiteIdStr = (string)root.Attribute("SiteId") ?? (string)root.Attribute("SITE_ID") ?? (string)root.Attribute("SiteID");
|
|
if (!string.IsNullOrWhiteSpace(rootSiteIdStr) && int.TryParse(rootSiteIdStr.Trim(), out var rootSiteId))
|
|
{
|
|
parsed.SiteId = rootSiteId;
|
|
}
|
|
|
|
foreach (var deviceEl in root.Elements().Where(e => string.Equals(e.Name.LocalName, "Device", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
var ip = (string)deviceEl.Attribute("IpAddress") ?? (string)deviceEl.Attribute("Ip") ?? "";
|
|
var enabledStr = (string)deviceEl.Attribute("Enabled");
|
|
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(enabledStr))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!TryParseBool(enabledStr, out var enabled))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int? siteId = null;
|
|
var siteIdStr = (string)deviceEl.Attribute("SiteId") ?? (string)deviceEl.Attribute("SITE_ID") ?? (string)deviceEl.Attribute("SiteID");
|
|
if (!string.IsNullOrWhiteSpace(siteIdStr) && int.TryParse(siteIdStr.Trim(), out var parsedSiteId))
|
|
{
|
|
siteId = parsedSiteId;
|
|
}
|
|
|
|
parsed.Devices.Add(new DeviceRule(ip.Trim(), enabled, siteId));
|
|
}
|
|
|
|
// If SiteId is not specified at root, but devices specify a single consistent SiteId, use it.
|
|
if (!parsed.SiteId.HasValue)
|
|
{
|
|
var distinct = parsed.Devices.Where(d => d.SiteId.HasValue).Select(d => d.SiteId.Value).Distinct().ToList();
|
|
if (distinct.Count == 1)
|
|
{
|
|
parsed.SiteId = distinct[0];
|
|
}
|
|
}
|
|
|
|
var templateTransferEl = root.Elements().FirstOrDefault(e => string.Equals(e.Name.LocalName, "TemplateTransfer", StringComparison.OrdinalIgnoreCase));
|
|
if (templateTransferEl != null)
|
|
{
|
|
var ttEnabled = TryParseBool((string)templateTransferEl.Attribute("Enabled"), out var tt) && tt;
|
|
var ttConfig = new TemplateTransferConfig(ttEnabled);
|
|
|
|
foreach (var jobEl in templateTransferEl.Elements().Where(e => string.Equals(e.Name.LocalName, "Job", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
var id = (string)jobEl.Attribute("Id") ?? "";
|
|
var enabled = TryParseBool((string)jobEl.Attribute("Enabled"), out var jEnabled) && jEnabled;
|
|
var sourceIp = (string)jobEl.Attribute("SourceIp") ?? (string)jobEl.Attribute("SourceIP") ?? "";
|
|
|
|
if (string.IsNullOrWhiteSpace(id) || string.IsNullOrWhiteSpace(sourceIp))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var targets = new List<string>();
|
|
foreach (var targetEl in jobEl.Elements().Where(e => string.Equals(e.Name.LocalName, "Target", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
var tip = (string)targetEl.Attribute("Ip") ?? (string)targetEl.Attribute("IpAddress") ?? "";
|
|
if (!string.IsNullOrWhiteSpace(tip))
|
|
{
|
|
targets.Add(tip.Trim());
|
|
}
|
|
}
|
|
|
|
// Optional comma-separated list of employee IDs for DB_TO_DEVICE filtering
|
|
var empIdsAttr = (string)jobEl.Attribute("EmpIds") ?? (string)jobEl.Attribute("EmpIDs");
|
|
List<string> empIds = null;
|
|
if (!string.IsNullOrWhiteSpace(empIdsAttr))
|
|
{
|
|
empIds = empIdsAttr
|
|
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(v => v.Trim())
|
|
.Where(v => v.Length > 0)
|
|
.ToList();
|
|
}
|
|
|
|
ttConfig.Jobs.Add(new TemplateTransferJob(id.Trim(), enabled, sourceIp.Trim(), targets, empIds));
|
|
}
|
|
|
|
parsed.TemplateTransfer = ttConfig;
|
|
}
|
|
|
|
config = parsed;
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
error = $"Failed to load device settings: {ex.Message}";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool HasAnyAllowlistedDeviceIp()
|
|
=> Devices.Any(d => d.Enabled);
|
|
|
|
public HashSet<string> GetAllowlistedIps()
|
|
=> new HashSet<string>(Devices.Where(d => d.Enabled).Select(d => d.IpAddress), StringComparer.OrdinalIgnoreCase);
|
|
|
|
public HashSet<string> GetBlocklistedIps()
|
|
=> new HashSet<string>(Devices.Where(d => !d.Enabled).Select(d => d.IpAddress), StringComparer.OrdinalIgnoreCase);
|
|
|
|
private static bool TryParseBool(string value, out bool result)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
result = false;
|
|
return false;
|
|
}
|
|
|
|
return bool.TryParse(value.Trim(), out result);
|
|
}
|
|
}
|
|
|
|
internal sealed class DeviceRule
|
|
{
|
|
public DeviceRule(string ipAddress, bool enabled, int? siteId)
|
|
{
|
|
IpAddress = ipAddress ?? "";
|
|
Enabled = enabled;
|
|
SiteId = siteId;
|
|
}
|
|
|
|
public string IpAddress { get; }
|
|
public bool Enabled { get; }
|
|
public int? SiteId { get; }
|
|
}
|
|
|
|
internal sealed class TemplateTransferConfig
|
|
{
|
|
public TemplateTransferConfig(bool enabled)
|
|
{
|
|
Enabled = enabled;
|
|
}
|
|
|
|
public bool Enabled { get; }
|
|
public List<TemplateTransferJob> Jobs { get; } = new List<TemplateTransferJob>();
|
|
}
|
|
|
|
internal sealed class TemplateTransferJob
|
|
{
|
|
public TemplateTransferJob(string id, bool enabled, string sourceIp, List<string> targetIps, List<string> empIds)
|
|
{
|
|
Id = id ?? "";
|
|
Enabled = enabled;
|
|
SourceIp = sourceIp ?? "";
|
|
TargetIps = targetIps ?? new List<string>();
|
|
EmpIds = empIds ?? new List<string>();
|
|
}
|
|
|
|
public string Id { get; }
|
|
public bool Enabled { get; }
|
|
public string SourceIp { get; }
|
|
public List<string> TargetIps { get; }
|
|
public List<string> EmpIds { get; }
|
|
}
|
|
}
|
|
|