mirror of
https://github.com/excaliburpartners/OmniLinkBridge
synced 2024-12-22 10:42:24 +00:00
1.1.7 - Improve configuration environment and file loading
This commit is contained in:
parent
9a966225b6
commit
a5e9fae32e
|
@ -28,4 +28,4 @@ EXPOSE 8000/tcp
|
||||||
VOLUME /config
|
VOLUME /config
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=build /app .
|
COPY --from=build /app .
|
||||||
CMD [ "mono", "OmniLinkBridge.exe", "-i", "-c", "/config/OmniLinkBridge.ini", "-s", "/config/WebSubscriptions.json" ]
|
CMD [ "mono", "OmniLinkBridge.exe", "-i", "-c", "/config/OmniLinkBridge.ini", "-e", "-s", "/config/WebSubscriptions.json" ]
|
|
@ -12,6 +12,9 @@ namespace OmniLinkBridge.Notifications
|
||||||
|
|
||||||
public void Notify(string source, string description, NotificationPriority priority)
|
public void Notify(string source, string description, NotificationPriority priority)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(Global.mail_server))
|
||||||
|
return;
|
||||||
|
|
||||||
foreach (MailAddress address in Global.mail_to)
|
foreach (MailAddress address in Global.mail_to)
|
||||||
{
|
{
|
||||||
MailMessage mail = new MailMessage
|
MailMessage mail = new MailMessage
|
||||||
|
|
|
@ -28,6 +28,12 @@ namespace OmniLinkBridge
|
||||||
case "-c":
|
case "-c":
|
||||||
Global.config_file = args[++i];
|
Global.config_file = args[++i];
|
||||||
break;
|
break;
|
||||||
|
case "-e":
|
||||||
|
Settings.UseEnvironment = true;
|
||||||
|
break;
|
||||||
|
case "-d":
|
||||||
|
Settings.ShowDebug = true;
|
||||||
|
break;
|
||||||
case "-s":
|
case "-s":
|
||||||
Global.webapi_subscriptions_file = args[++i];
|
Global.webapi_subscriptions_file = args[++i];
|
||||||
break;
|
break;
|
||||||
|
@ -47,6 +53,9 @@ namespace OmniLinkBridge
|
||||||
|
|
||||||
log4net.Config.XmlConfigurator.Configure();
|
log4net.Config.XmlConfigurator.Configure();
|
||||||
|
|
||||||
|
if(Environment.UserInteractive || interactive)
|
||||||
|
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Settings.LoadSettings();
|
Settings.LoadSettings();
|
||||||
|
@ -57,7 +66,6 @@ namespace OmniLinkBridge
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Environment.UserInteractive || interactive)
|
if (Environment.UserInteractive || interactive)
|
||||||
{
|
{
|
||||||
if (IsRunningOnMono())
|
if (IsRunningOnMono())
|
||||||
|
@ -80,8 +88,6 @@ namespace OmniLinkBridge
|
||||||
Console.TreatControlCAsInput = false;
|
Console.TreatControlCAsInput = false;
|
||||||
Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
|
Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
|
||||||
|
|
||||||
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
|
|
||||||
|
|
||||||
server = new CoreServer();
|
server = new CoreServer();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -114,8 +120,11 @@ namespace OmniLinkBridge
|
||||||
static void ShowHelp()
|
static void ShowHelp()
|
||||||
{
|
{
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-s subscriptions_file] [-i]\n" +
|
AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-e] [-d] [-s subscriptions_file] [-i]\n" +
|
||||||
|
"\t[-debug-config] [-ignore-env]\n" +
|
||||||
"\t-c Specifies the configuration file. Default is OmniLinkBridge.ini\n" +
|
"\t-c Specifies the configuration file. Default is OmniLinkBridge.ini\n" +
|
||||||
|
"\t-e Check environment variables for configuration settings\n" +
|
||||||
|
"\t-d Show debug output for configuration loading\n" +
|
||||||
"\t-s Specifies the web api subscriptions file. Default is WebSubscriptions.json\n" +
|
"\t-s Specifies the web api subscriptions file. Default is WebSubscriptions.json\n" +
|
||||||
"\t-i Run in interactive mode");
|
"\t-i Run in interactive mode");
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.1.6.0")]
|
[assembly: AssemblyVersion("1.1.7.0")]
|
||||||
[assembly: AssemblyFileVersion("1.1.6.0")]
|
[assembly: AssemblyFileVersion("1.1.7.0")]
|
||||||
|
|
|
@ -13,87 +13,110 @@ namespace OmniLinkBridge
|
||||||
public static class Settings
|
public static class Settings
|
||||||
{
|
{
|
||||||
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
public static bool ShowDebug { get; set; }
|
||||||
|
public static bool UseEnvironment { get; set; }
|
||||||
|
|
||||||
public static void LoadSettings()
|
public static void LoadSettings()
|
||||||
{
|
{
|
||||||
NameValueCollection settings = LoadCollection(Global.config_file);
|
NameValueCollection settings = LoadCollection(Global.config_file);
|
||||||
|
|
||||||
// HAI / Leviton Omni Controller
|
// HAI / Leviton Omni Controller
|
||||||
Global.controller_address = settings.CheckEnv("controller_address");
|
Global.controller_address = settings.ValidateHasValue("controller_address");
|
||||||
Global.controller_port = ValidatePort(settings, "controller_port");
|
Global.controller_port = settings.ValidatePort("controller_port");
|
||||||
Global.controller_key1 = settings.CheckEnv("controller_key1");
|
Global.controller_key1 = settings.ValidateHasValue("controller_key1");
|
||||||
Global.controller_key2 = settings.CheckEnv("controller_key2");
|
Global.controller_key2 = settings.ValidateHasValue("controller_key2");
|
||||||
Global.controller_name = settings.CheckEnv("controller_name") ?? "OmniLinkBridge";
|
Global.controller_name = settings.CheckEnv("controller_name") ?? "OmniLinkBridge";
|
||||||
|
|
||||||
// Controller Time Sync
|
// Controller Time Sync
|
||||||
Global.time_sync = ValidateYesNo(settings, "time_sync");
|
Global.time_sync = settings.ValidateBool("time_sync");
|
||||||
Global.time_interval = ValidateInt(settings, "time_interval");
|
|
||||||
Global.time_drift = ValidateInt(settings, "time_drift");
|
if (Global.time_sync)
|
||||||
|
{
|
||||||
|
Global.time_interval = settings.ValidateInt("time_interval");
|
||||||
|
Global.time_drift = settings.ValidateInt("time_drift");
|
||||||
|
}
|
||||||
|
|
||||||
// Verbose Console
|
// Verbose Console
|
||||||
Global.verbose_unhandled = ValidateYesNo(settings, "verbose_unhandled");
|
Global.verbose_unhandled = settings.ValidateBool("verbose_unhandled");
|
||||||
Global.verbose_event = ValidateYesNo(settings, "verbose_event");
|
Global.verbose_event = settings.ValidateBool("verbose_event");
|
||||||
Global.verbose_area = ValidateYesNo(settings, "verbose_area");
|
Global.verbose_area = settings.ValidateBool("verbose_area");
|
||||||
Global.verbose_zone = ValidateYesNo(settings, "verbose_zone");
|
Global.verbose_zone = settings.ValidateBool("verbose_zone");
|
||||||
Global.verbose_thermostat_timer = ValidateYesNo(settings, "verbose_thermostat_timer");
|
Global.verbose_thermostat_timer = settings.ValidateBool("verbose_thermostat_timer");
|
||||||
Global.verbose_thermostat = ValidateYesNo(settings, "verbose_thermostat");
|
Global.verbose_thermostat = settings.ValidateBool("verbose_thermostat");
|
||||||
Global.verbose_unit = ValidateYesNo(settings, "verbose_unit");
|
Global.verbose_unit = settings.ValidateBool("verbose_unit");
|
||||||
Global.verbose_message = ValidateYesNo(settings, "verbose_message");
|
Global.verbose_message = settings.ValidateBool("verbose_message");
|
||||||
|
|
||||||
// mySQL Logging
|
// mySQL Logging
|
||||||
Global.mysql_logging = ValidateYesNo(settings, "mysql_logging");
|
Global.mysql_logging = settings.ValidateBool("mysql_logging");
|
||||||
Global.mysql_connection = settings.CheckEnv("mysql_connection");
|
Global.mysql_connection = settings.CheckEnv("mysql_connection");
|
||||||
|
|
||||||
// Web Service
|
// Web Service
|
||||||
Global.webapi_enabled = ValidateYesNo(settings, "webapi_enabled");
|
Global.webapi_enabled = settings.ValidateBool("webapi_enabled");
|
||||||
Global.webapi_port = ValidatePort(settings, "webapi_port");
|
|
||||||
Global.webapi_override_zone = LoadOverrideZone<WebAPI.OverrideZone>(settings, "webapi_override_zone");
|
if (Global.webapi_enabled)
|
||||||
|
{
|
||||||
|
Global.webapi_port = settings.ValidatePort("webapi_port");
|
||||||
|
Global.webapi_override_zone = settings.LoadOverrideZone<WebAPI.OverrideZone>("webapi_override_zone");
|
||||||
|
}
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
Global.mqtt_enabled = ValidateYesNo(settings, "mqtt_enabled");
|
Global.mqtt_enabled = settings.ValidateBool("mqtt_enabled");
|
||||||
Global.mqtt_server = settings.CheckEnv("mqtt_server");
|
|
||||||
Global.mqtt_port = ValidatePort(settings, "mqtt_port");
|
|
||||||
Global.mqtt_username = settings.CheckEnv("mqtt_username");
|
|
||||||
Global.mqtt_password = settings.CheckEnv("mqtt_password");
|
|
||||||
Global.mqtt_prefix = settings.CheckEnv("mqtt_prefix") ?? "omnilink";
|
|
||||||
Global.mqtt_discovery_prefix = settings.CheckEnv("mqtt_discovery_prefix") ?? "homeassistant";
|
|
||||||
Global.mqtt_discovery_name_prefix = settings.CheckEnv("mqtt_discovery_name_prefix") ?? string.Empty;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Global.mqtt_discovery_name_prefix))
|
if (Global.mqtt_enabled)
|
||||||
Global.mqtt_discovery_name_prefix += " ";
|
{
|
||||||
|
Global.mqtt_server = settings.CheckEnv("mqtt_server");
|
||||||
|
Global.mqtt_port = settings.ValidatePort("mqtt_port");
|
||||||
|
Global.mqtt_username = settings.CheckEnv("mqtt_username");
|
||||||
|
Global.mqtt_password = settings.CheckEnv("mqtt_password");
|
||||||
|
Global.mqtt_prefix = settings.CheckEnv("mqtt_prefix") ?? "omnilink";
|
||||||
|
Global.mqtt_discovery_prefix = settings.CheckEnv("mqtt_discovery_prefix") ?? "homeassistant";
|
||||||
|
Global.mqtt_discovery_name_prefix = settings.CheckEnv("mqtt_discovery_name_prefix") ?? string.Empty;
|
||||||
|
|
||||||
Global.mqtt_discovery_ignore_zones = ValidateRange(settings, "mqtt_discovery_ignore_zones");
|
if (!string.IsNullOrEmpty(Global.mqtt_discovery_name_prefix))
|
||||||
Global.mqtt_discovery_ignore_units = ValidateRange(settings, "mqtt_discovery_ignore_units");
|
Global.mqtt_discovery_name_prefix += " ";
|
||||||
Global.mqtt_discovery_override_zone = LoadOverrideZone<MQTT.OverrideZone>(settings, "mqtt_discovery_override_zone");
|
|
||||||
|
Global.mqtt_discovery_ignore_zones = settings.ValidateRange("mqtt_discovery_ignore_zones");
|
||||||
|
Global.mqtt_discovery_ignore_units = settings.ValidateRange("mqtt_discovery_ignore_units");
|
||||||
|
Global.mqtt_discovery_override_zone = settings.LoadOverrideZone<MQTT.OverrideZone>("mqtt_discovery_override_zone");
|
||||||
|
}
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
Global.notify_area = ValidateYesNo(settings, "notify_area");
|
Global.notify_area = settings.ValidateBool("notify_area");
|
||||||
Global.notify_message = ValidateYesNo(settings, "notify_message");
|
Global.notify_message = settings.ValidateBool("notify_message");
|
||||||
|
|
||||||
// Email Notifications
|
// Email Notifications
|
||||||
Global.mail_server = settings.CheckEnv("mail_server");
|
Global.mail_server = settings.CheckEnv("mail_server");
|
||||||
Global.mail_tls = ValidateYesNo(settings, "mail_tls");
|
|
||||||
Global.mail_port = ValidatePort(settings, "mail_port");
|
if (!string.IsNullOrEmpty(Global.mail_server))
|
||||||
Global.mail_username = settings.CheckEnv("mail_username");
|
{
|
||||||
Global.mail_password = settings.CheckEnv("mail_password");
|
Global.mail_tls = settings.ValidateBool("mail_tls");
|
||||||
Global.mail_from = ValidateMailFrom(settings, "mail_from");
|
Global.mail_port = settings.ValidatePort("mail_port");
|
||||||
Global.mail_to = ValidateMailTo(settings, "mail_to");
|
Global.mail_username = settings.CheckEnv("mail_username");
|
||||||
|
Global.mail_password = settings.CheckEnv("mail_password");
|
||||||
|
Global.mail_from = settings.ValidateMailFrom("mail_from");
|
||||||
|
Global.mail_to = settings.ValidateMailTo("mail_to");
|
||||||
|
}
|
||||||
|
|
||||||
// Prowl Notifications
|
// Prowl Notifications
|
||||||
Global.prowl_key = ValidateMultipleStrings(settings, "prowl_key");
|
Global.prowl_key = settings.ValidateMultipleStrings("prowl_key");
|
||||||
|
|
||||||
// Pushover Notifications
|
// Pushover Notifications
|
||||||
Global.pushover_token = settings.CheckEnv("pushover_token");
|
Global.pushover_token = settings.CheckEnv("pushover_token");
|
||||||
Global.pushover_user = ValidateMultipleStrings(settings, "pushover_user");
|
Global.pushover_user = settings.ValidateMultipleStrings("pushover_user");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CheckEnv(this NameValueCollection settings, string name)
|
private static string CheckEnv(this NameValueCollection settings, string name)
|
||||||
{
|
{
|
||||||
string env = Environment.GetEnvironmentVariable(name.ToUpper());
|
string env = UseEnvironment ? Environment.GetEnvironmentVariable(name.ToUpper()) : null;
|
||||||
return !string.IsNullOrEmpty(env) ? env : settings[name];
|
string value = !string.IsNullOrEmpty(env) ? env : settings[name];
|
||||||
|
|
||||||
|
if (ShowDebug)
|
||||||
|
log.Debug((!string.IsNullOrEmpty(env) ? "ENV" : "CONF").PadRight(5) + $"{name}: {value}");
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ConcurrentDictionary<int, T> LoadOverrideZone<T>(NameValueCollection settings, string section) where T : new()
|
private static ConcurrentDictionary<int, T> LoadOverrideZone<T>(this NameValueCollection settings, string section) where T : new()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -115,14 +138,14 @@ namespace OmniLinkBridge
|
||||||
|
|
||||||
T override_zone = new T();
|
T override_zone = new T();
|
||||||
|
|
||||||
if (((object)override_zone) is WebAPI.OverrideZone webapi_zone)
|
if (override_zone is WebAPI.OverrideZone webapi_zone)
|
||||||
{
|
{
|
||||||
if (!attributes.ContainsKey("device_type") || !Enum.TryParse(attributes["device_type"], out WebAPI.DeviceType attrib_device_type))
|
if (!attributes.ContainsKey("device_type") || !Enum.TryParse(attributes["device_type"], out WebAPI.DeviceType attrib_device_type))
|
||||||
throw new Exception("Missing or invalid device_type attribute");
|
throw new Exception("Missing or invalid device_type attribute");
|
||||||
|
|
||||||
webapi_zone.device_type = attrib_device_type;
|
webapi_zone.device_type = attrib_device_type;
|
||||||
}
|
}
|
||||||
else if (((object)override_zone) is MQTT.OverrideZone mqtt_zone)
|
else if (override_zone is MQTT.OverrideZone mqtt_zone)
|
||||||
{
|
{
|
||||||
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class))
|
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class))
|
||||||
throw new Exception("Missing or invalid device_class attribute");
|
throw new Exception("Missing or invalid device_class attribute");
|
||||||
|
@ -142,7 +165,20 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ValidateInt(NameValueCollection settings, string section)
|
private static string ValidateHasValue(this NameValueCollection settings, string section)
|
||||||
|
{
|
||||||
|
string value = settings.CheckEnv(section);
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
log.Error("Empty string specified for " + section);
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ValidateInt(this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -155,7 +191,7 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<int> ValidateRange(NameValueCollection settings, string section)
|
private static HashSet<int> ValidateRange(this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -168,7 +204,7 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ValidatePort(NameValueCollection settings, string section)
|
private static int ValidatePort(this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -186,7 +222,7 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MailAddress ValidateMailFrom(NameValueCollection settings, string section)
|
private static MailAddress ValidateMailFrom(this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -199,14 +235,16 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MailAddress[] ValidateMailTo(NameValueCollection settings, string section)
|
private static MailAddress[] ValidateMailTo(this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(settings.CheckEnv(section) == null)
|
string value = settings.CheckEnv(section);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
return new MailAddress[] {};
|
return new MailAddress[] {};
|
||||||
|
|
||||||
string[] emails = settings.CheckEnv(section).Split(',');
|
string[] emails = value.Split(',');
|
||||||
MailAddress[] addresses = new MailAddress[emails.Length];
|
MailAddress[] addresses = new MailAddress[emails.Length];
|
||||||
|
|
||||||
for(int i=0; i < emails.Length; i++)
|
for(int i=0; i < emails.Length; i++)
|
||||||
|
@ -221,7 +259,7 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string[] ValidateMultipleStrings(NameValueCollection settings, string section)
|
private static string[] ValidateMultipleStrings(this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -237,19 +275,19 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ValidateYesNo (NameValueCollection settings, string section)
|
private static bool ValidateBool (this NameValueCollection settings, string section)
|
||||||
{
|
{
|
||||||
string value = settings.CheckEnv(section);
|
string value = settings.CheckEnv(section);
|
||||||
|
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return false;
|
return false;
|
||||||
if (string.Compare(value, "yes", true) == 0)
|
if (string.Compare(value, "yes", true) == 0 || string.Compare(value, "true", true) == 0)
|
||||||
return true;
|
return true;
|
||||||
else if (string.Compare(value, "no", true) == 0)
|
else if (string.Compare(value, "no", true) == 0 || string.Compare(value, "false", true) == 0)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.Error("Invalid yes/no specified for " + section);
|
log.Error("Invalid yes/no or true/false specified for " + section);
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,6 +296,15 @@ namespace OmniLinkBridge
|
||||||
{
|
{
|
||||||
NameValueCollection settings = new NameValueCollection();
|
NameValueCollection settings = new NameValueCollection();
|
||||||
|
|
||||||
|
if (ShowDebug)
|
||||||
|
log.Debug($"Using settings file {sFile}");
|
||||||
|
|
||||||
|
if(!File.Exists(sFile))
|
||||||
|
{
|
||||||
|
log.Warn($"Unable to locate settings file {sFile}");
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FileStream fs = new FileStream(sFile, FileMode.Open, FileAccess.Read);
|
FileStream fs = new FileStream(sFile, FileMode.Open, FileAccess.Read);
|
||||||
|
@ -289,7 +336,7 @@ namespace OmniLinkBridge
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException ex)
|
catch (FileNotFoundException ex)
|
||||||
{
|
{
|
||||||
log.Error("Unable to parse settings file " + sFile, ex);
|
log.Error("Error parsing settings file " + sFile, ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue