using IFS.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace IFS
{
public class InvalidConfigurationException : Exception
{
public InvalidConfigurationException(string message) : base(message)
{
}
}
///
/// Encapsulates global server configuration information.
///
public static class Configuration
{
static Configuration()
{
ReadConfiguration();
//
// Ensure that required values were read from the config file. If not,
// throw so that startup is aborted.
//
if (string.IsNullOrWhiteSpace(FTPRoot) || !Directory.Exists(FTPRoot))
{
throw new InvalidConfigurationException("FTP root path is invalid.");
}
if (string.IsNullOrWhiteSpace(CopyDiskRoot) || !Directory.Exists(CopyDiskRoot))
{
throw new InvalidConfigurationException("CopyDisk root path is invalid.");
}
if (string.IsNullOrWhiteSpace(BootRoot) || !Directory.Exists(BootRoot))
{
throw new InvalidConfigurationException("Boot root path is invalid.");
}
if (string.IsNullOrWhiteSpace(BootRoot) || !Directory.Exists(MailRoot))
{
throw new InvalidConfigurationException("Mail root path is invalid.");
}
if (MaxWorkers < 1)
{
throw new InvalidConfigurationException("MaxWorkers must be >= 1.");
}
}
///
/// The type of interface (UDP or RAW) to communicate over
///
public static readonly string InterfaceType;
///
/// The name of the network interface to use
///
public static readonly string InterfaceName;
///
/// The network that this server lives on
///
public static readonly int ServerNetwork;
///
/// The host number for this server.
///
public static readonly int ServerHost;
///
/// The root directory for the FTP file store.
///
public static readonly string FTPRoot;
///
/// The root directory for the CopyDisk file store.
///
public static readonly string CopyDiskRoot;
///
/// The root directory for the Boot file store.
///
public static readonly string BootRoot;
///
/// The root directory for the Mail file store.
///
public static readonly string MailRoot;
///
/// The maximum number of worker threads for protocol handling.
///
public static readonly int MaxWorkers = 256;
///
/// The components to display logging messages for.
///
public static readonly LogComponent LogComponents;
///
/// The type (Verbosity) of messages to log.
///
public static readonly LogType LogTypes;
private static void ReadConfiguration()
{
using (StreamReader configStream = new StreamReader(Path.Combine("Conf", "ifs.cfg")))
{
//
// Config file consists of text lines containing name / value pairs:
// =
// Whitespace is ignored.
//
int lineNumber = 0;
while (!configStream.EndOfStream)
{
lineNumber++;
string line = configStream.ReadLine().Trim();
if (string.IsNullOrEmpty(line))
{
// Empty line, ignore.
continue;
}
if (line.StartsWith("#"))
{
// Comment to EOL, ignore.
continue;
}
// Find the '=' separating tokens and ensure there are just two.
string[] tokens = line.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
if (tokens.Length < 2)
{
Log.Write(LogType.Warning, LogComponent.Configuration,
"ifs.cfg line {0}: Invalid syntax.", lineNumber);
continue;
}
string parameter = tokens[0].Trim();
string value = tokens[1].Trim();
// Reflect over the public, static properties in this class and see if the parameter matches one of them
// If not, it's an error, if it is then we attempt to coerce the value to the correct type.
System.Reflection.FieldInfo[] info = typeof(Configuration).GetFields(BindingFlags.Public | BindingFlags.Static);
bool bMatch = false;
foreach (FieldInfo field in info)
{
// Case-insensitive compare.
if (field.Name.ToLowerInvariant() == parameter.ToLowerInvariant())
{
bMatch = true;
//
// Switch on the type of the field and attempt to convert the value to the appropriate type.
// At this time we support only strings and integers.
//
try
{
switch (field.FieldType.Name)
{
case "Int32":
{
int v = int.Parse(value);
field.SetValue(null, v);
}
break;
case "String":
{
field.SetValue(null, value);
}
break;
case "LogType":
{
field.SetValue(null, Enum.Parse(typeof(LogType), value, true));
}
break;
case "LogComponent":
{
field.SetValue(null, Enum.Parse(typeof(LogComponent), value, true));
}
break;
}
}
catch
{
Log.Write(LogType.Warning, LogComponent.Configuration,
"ifs.cfg line {0}: Value '{1}' is invalid for parameter '{2}'.", lineNumber, value, parameter);
}
}
}
if (!bMatch)
{
Log.Write(LogType.Warning, LogComponent.Configuration,
"ifs.cfg line {0}: Unknown configuration parameter '{1}'.", lineNumber, parameter);
}
}
}
}
}
}