Load DeviceSettings.config as an overlay on HikvisionServiceConfig

After loading serviceconfig.json, apply DeviceSettings.config values onto the existing config properties without changing runtime behavior or property names.
main
SYED MUSTUFA AHMED NAQVI 2026-08-05 15:36:09 +05:00
parent 3bc691933a
commit 920b8d1e0c
1 changed files with 90 additions and 2 deletions

View File

@ -237,7 +237,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
{ {
if (!File.Exists(configPath)) if (!File.Exists(configPath))
{ {
return new HikvisionServiceConfig var missingCfg = new HikvisionServiceConfig
{ {
LogDirectory = @"C:\Users\Public\HikvisionAttendanceService", LogDirectory = @"C:\Users\Public\HikvisionAttendanceService",
SqlConnectionString = "", SqlConnectionString = "",
@ -284,6 +284,9 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
UserSyncFaceCacheDirectory = "", UserSyncFaceCacheDirectory = "",
SyncPolicies = new UserSyncPoliciesConfig() SyncPolicies = new UserSyncPoliciesConfig()
}; };
ApplyDeviceSettingsOverlay(missingCfg, configPath);
NormalizeLoadedDeviceConfig(missingCfg);
return missingCfg;
} }
var raw = File.ReadAllText(configPath); var raw = File.ReadAllText(configPath);
@ -296,6 +299,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
{ {
var cfg = (HikvisionServiceConfig)serializer.ReadObject(ms); var cfg = (HikvisionServiceConfig)serializer.ReadObject(ms);
ApplyEnvironmentOverrides(cfg); ApplyEnvironmentOverrides(cfg);
ApplyDeviceSettingsOverlay(cfg, configPath);
NormalizeLoadedDeviceConfig(cfg); NormalizeLoadedDeviceConfig(cfg);
return cfg; return cfg;
} }
@ -308,6 +312,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
{ {
var cfg = (HikvisionServiceConfig)serializer.ReadObject(ms); var cfg = (HikvisionServiceConfig)serializer.ReadObject(ms);
ApplyEnvironmentOverrides(cfg); ApplyEnvironmentOverrides(cfg);
ApplyDeviceSettingsOverlay(cfg, configPath);
NormalizeLoadedDeviceConfig(cfg); NormalizeLoadedDeviceConfig(cfg);
return cfg; return cfg;
} }
@ -315,7 +320,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
} }
catch catch
{ {
return new HikvisionServiceConfig var fallbackCfg = new HikvisionServiceConfig
{ {
LogDirectory = @"C:\Users\Public\HikvisionAttendanceService", LogDirectory = @"C:\Users\Public\HikvisionAttendanceService",
SqlConnectionString = "", SqlConnectionString = "",
@ -362,6 +367,9 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
UserSyncFaceCacheDirectory = "", UserSyncFaceCacheDirectory = "",
SyncPolicies = new UserSyncPoliciesConfig() SyncPolicies = new UserSyncPoliciesConfig()
}; };
ApplyDeviceSettingsOverlay(fallbackCfg, configPath);
NormalizeLoadedDeviceConfig(fallbackCfg);
return fallbackCfg;
} }
} }
@ -481,6 +489,60 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
cfg.DbPort = parsedPort; cfg.DbPort = parsedPort;
} }
/// <summary>
/// Overlays device-scope / template-direction settings from DeviceSettings.config
/// (same folder as serviceconfig.json). Property names and behavior are unchanged.
/// </summary>
private static void ApplyDeviceSettingsOverlay(HikvisionServiceConfig cfg, string serviceConfigPath)
{
if (cfg == null)
return;
string dir;
try
{
dir = Path.GetDirectoryName(Path.GetFullPath(serviceConfigPath ?? "")) ?? "";
}
catch
{
dir = "";
}
if (string.IsNullOrWhiteSpace(dir))
dir = AppContext.BaseDirectory;
var path = Path.Combine(dir, "DeviceSettings.config");
if (!File.Exists(path))
return;
try
{
var raw = File.ReadAllText(path);
var serializer = new DataContractJsonSerializer(typeof(DeviceSettingsFile));
DeviceSettingsFile? overlay;
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(raw)))
overlay = serializer.ReadObject(ms) as DeviceSettingsFile;
if (overlay == null)
return;
if (!string.IsNullOrWhiteSpace(overlay.MachineScopeMode))
cfg.MachineScopeMode = overlay.MachineScopeMode;
if (overlay.ScopedMachineIps != null)
cfg.ScopedMachineIps = new List<string>(overlay.ScopedMachineIps);
cfg.EnableTemplateDeviceToDbSync = overlay.EnableTemplateDeviceToDbSync;
cfg.EnableTemplateDbToDeviceSync = overlay.EnableTemplateDbToDeviceSync;
if (overlay.SourceMachineIp != null)
cfg.SourceMachineIp = overlay.SourceMachineIp;
if (overlay.TargetMachineIps != null)
cfg.TargetMachineIps = new List<string>(overlay.TargetMachineIps);
if (overlay.SyncEmployeeIds != null)
cfg.SyncEmployeeIds = new List<string>(overlay.SyncEmployeeIds);
}
catch
{
// Keep serviceconfig / defaults if DeviceSettings.config cannot be parsed.
}
}
private static void NormalizeLoadedDeviceConfig(HikvisionServiceConfig? cfg) private static void NormalizeLoadedDeviceConfig(HikvisionServiceConfig? cfg)
{ {
if (cfg == null) if (cfg == null)
@ -524,6 +586,32 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
} }
} }
/// <summary>Device-scope and template-direction settings loaded from DeviceSettings.config.</summary>
[DataContract]
internal sealed class DeviceSettingsFile
{
[DataMember]
public string MachineScopeMode { get; set; } = "CENTRAL";
[DataMember]
public List<string> ScopedMachineIps { get; set; } = new List<string>();
[DataMember]
public bool EnableTemplateDeviceToDbSync { get; set; }
[DataMember]
public bool EnableTemplateDbToDeviceSync { get; set; }
[DataMember]
public string SourceMachineIp { get; set; } = "";
[DataMember]
public List<string> TargetMachineIps { get; set; } = new List<string>();
[DataMember]
public List<string> SyncEmployeeIds { get; set; } = new List<string>();
}
/// <summary>Policies for multi-device user/face sync (ISAPI). Loaded from service JSON only.</summary> /// <summary>Policies for multi-device user/face sync (ISAPI). Loaded from service JSON only.</summary>
[DataContract] [DataContract]
internal sealed class UserSyncPoliciesConfig internal sealed class UserSyncPoliciesConfig