Added and implemented a basic command-line parser.

This replaces the switch-case in HandleCommandLine and HandleCommandLinePostConfigLoad
This commit is contained in:
White 2017-03-13 11:40:44 +10:30
parent 047f9e7475
commit fc7460c7d5
5 changed files with 600 additions and 202 deletions

View file

@ -41,6 +41,7 @@ using TShockAPI.ServerSideCharacters;
using Terraria.Utilities;
using Microsoft.Xna.Framework;
using TShockAPI.Sockets;
using TShockAPI.CLI;
namespace TShockAPI
{
@ -127,6 +128,10 @@ namespace TShockAPI
/// <summary>instance - Static reference to the TerrariaPlugin instance.</summary>
public static TerrariaPlugin instance;
/// <summary>
/// Static reference to a <see cref="CommandLineParser"/> used for simple command-line parsing
/// </summary>
public static CommandLineParser CliParser { get; } = new CommandLineParser();
/// <summary>
/// Used for implementing REST Tokens prior to the REST system starting up.
/// </summary>
public static Dictionary<string, SecureRest.TokenData> RESTStartupTokens = new Dictionary<string, SecureRest.TokenData>();
@ -204,6 +209,7 @@ namespace TShockAPI
try
{
CliParser.Reset();
HandleCommandLine(Environment.GetCommandLineArgs());
if (!Directory.Exists(SavePath))
@ -295,6 +301,7 @@ namespace TShockAPI
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"),
Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
CliParser.Reset();
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
Backups = new BackupManager(Path.Combine(SavePath, "backups"));
@ -609,217 +616,202 @@ namespace TShockAPI
/// <param name="parms">parms - The array of arguments passed in through the command line.</param>
private void HandleCommandLine(string[] parms)
{
string path;
for (int i = 0; i < parms.Length; i++)
string path = null;
//Generic method for doing a path sanity check
Action<string> pathChecker = (p) =>
{
switch (parms[i].ToLower())
if (!string.IsNullOrWhiteSpace(p) && p.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
case "-configpath":
{
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
SavePath = path;
ServerApi.LogWriter.PluginWriteLine(this, "Config path has been set to " + path, TraceLevel.Info);
}
break;
}
case "-worldpath":
{
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
Main.WorldPath = path;
ServerApi.LogWriter.PluginWriteLine(this, "World path has been set to " + path, TraceLevel.Info);
}
break;
}
case "-logpath":
{
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
LogPath = path;
ServerApi.LogWriter.PluginWriteLine(this, "Log path has been set to " + path, TraceLevel.Info);
}
break;
}
case "-logformat":
{
LogFormat = parms[++i];
break;
}
case "-logclear":
{
bool.TryParse(parms[++i], out LogClear);
break;
}
case "-dump":
{
Utils.PrepareLangForDump();
Lang.setLang(true);
ConfigFile.DumpDescriptions();
Permissions.DumpDescriptions();
ServerSideConfig.DumpDescriptions();
RestManager.DumpDescriptions();
Utils.DumpBuffs("BuffList.txt");
Utils.DumpItems("Items-1_0.txt", -48, 235);
Utils.DumpItems("Items-1_1.txt", 235, 604);
Utils.DumpItems("Items-1_2.txt", 604, 2749);
Utils.DumpItems("Items-1_3.txt", 2749, Main.maxItemTypes);
Utils.DumpNPCs("NPCs.txt");
Utils.DumpProjectiles("Projectiles.txt");
Utils.DumpPrefixes("Prefixes.txt");
Environment.Exit(1);
break;
}
case "-config":
{
string filePath = parms[++i];
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Loading dedicated config file: {0}", filePath), TraceLevel.Verbose);
Main.instance.LoadDedConfig(filePath);
break;
}
case "-port":
{
int serverPort;
if (int.TryParse(parms[++i], out serverPort))
{
Netplay.ListenPort = serverPort;
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Listening on port {0}.", serverPort), TraceLevel.Verbose);
}
else
{
// The server should not start up if this argument is invalid.
throw new InvalidOperationException("Invalid value given for command line argument \"-ip\".");
}
break;
}
case "-worldname":
{
string worldName = parms[++i];
Main.instance.SetWorldName(worldName);
ServerApi.LogWriter.PluginWriteLine(this, string.Format("World name will be overridden by: {0}", worldName), TraceLevel.Verbose);
break;
}
case "-autoshutdown":
{
Main.instance.EnableAutoShutdown();
break;
}
case "-autocreate":
{
string newOpt = parms[++i];
Main.instance.autoCreate(newOpt);
break;
}
case "-ip":
{
IPAddress ip;
if (IPAddress.TryParse(parms[++i], out ip))
{
Netplay.ServerIP = ip;
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Listening on IP {0}.", ip), TraceLevel.Verbose);
}
else
{
// The server should not start up if this argument is invalid.
throw new InvalidOperationException("Invalid value given for command line argument \"-ip\".");
}
break;
}
case "-connperip":
{
int limit;
if (int.TryParse(parms[++i], out limit))
{
/* Todo - Requires an OTAPI modification
Netplay.MaxConnections = limit;
ServerApi.LogWriter.PluginWriteLine(this, string.Format(
"Connections per IP have been limited to {0} connections.", limit), TraceLevel.Verbose);*/
ServerApi.LogWriter.PluginWriteLine(this, "\"-connperip\" is not supported in this version of TShock.", TraceLevel.Verbose);
}
else
ServerApi.LogWriter.PluginWriteLine(this, "Invalid value given for command line argument \"-connperip\".", TraceLevel.Warning);
break;
}
case "-killinactivesocket":
{
// Netplay.killInactive = true;
ServerApi.LogWriter.PluginWriteLine(this, "The argument -killinactivesocket is no longer present in Terraria.", TraceLevel.Warning);
break;
}
case "-lang":
{
int langIndex;
if (int.TryParse(parms[++i], out langIndex))
{
Lang.lang = langIndex;
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Language index set to {0}.", langIndex), TraceLevel.Verbose);
}
else
ServerApi.LogWriter.PluginWriteLine(this, "Invalid value given for command line argument \"-lang\".", TraceLevel.Warning);
break;
}
case "--provider-token":
{
StatTracker.ProviderToken = parms[++i];
break;
}
case "--stats-optout":
{
StatTracker.OptOut = true;
break;
}
case "--no-restart":
{
TShock.NoRestart = true;
break;
}
path = p;
}
}
};
//Prepare the parser with all the flags available
CliParser
.AddFlag("-configpath", pathChecker)
//The .After Action is run after the pathChecker Action
.After(() =>
{
SavePath = path ?? "tshock";
if (path != null)
{
ServerApi.LogWriter.PluginWriteLine(this, "Config path has been set to " + path, TraceLevel.Info);
}
})
.AddFlag("-worldpath", pathChecker)
.After(() =>
{
if (path != null)
{
Main.WorldPath = path;
ServerApi.LogWriter.PluginWriteLine(this, "World path has been set to " + path, TraceLevel.Info);
}
})
.AddFlag("-logpath", pathChecker)
.After(() =>
{
if (path != null)
{
LogPath = path;
ServerApi.LogWriter.PluginWriteLine(this, "Log path has been set to " + path, TraceLevel.Info);
}
})
.AddFlag("-logformat", (format) =>
{
if (!string.IsNullOrWhiteSpace(format)) { LogFormat = format; }
})
.AddFlag("-config", (cfg) =>
{
if (!string.IsNullOrWhiteSpace(cfg))
{
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Loading dedicated config file: {0}", cfg), TraceLevel.Verbose);
Main.instance.LoadDedConfig(cfg);
}
})
.AddFlag("-port", (p) =>
{
int port;
if (int.TryParse(p, out port))
{
Netplay.ListenPort = port;
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Listening on port {0}.", port), TraceLevel.Verbose);
}
})
.AddFlag("-worldname", (world) =>
{
if (!string.IsNullOrWhiteSpace(world))
{
Main.instance.SetWorldName(world);
ServerApi.LogWriter.PluginWriteLine(this, string.Format("World name will be overridden by: {0}", world), TraceLevel.Verbose);
}
})
.AddFlag("-ip", (ip) =>
{
IPAddress addr;
if (IPAddress.TryParse(ip, out addr))
{
Netplay.ServerIP = addr;
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Listening on IP {0}.", addr), TraceLevel.Verbose);
}
else
{
// The server should not start up if this argument is invalid.
throw new InvalidOperationException("Invalid value given for command line argument \"-ip\".");
}
})
.AddFlag("-lang", (l) =>
{
int lang;
if (int.TryParse(l, out lang))
{
Lang.lang = lang;
ServerApi.LogWriter.PluginWriteLine(this, string.Format("Language index set to {0}.", lang), TraceLevel.Verbose);
}
else
{
ServerApi.LogWriter.PluginWriteLine(this, "Invalid value given for command line argument \"-lang\".", TraceLevel.Warning);
}
})
.AddFlag("-autocreate", (size) =>
{
if (!string.IsNullOrWhiteSpace(size))
{
Main.instance.autoCreate(size);
}
})
.AddFlag("--provider-token", (token) => StatTracker.ProviderToken = token)
//Flags without arguments
.AddFlag("-logclear", () => LogClear = true)
.AddFlag("-autoshutdown", () => Main.instance.EnableAutoShutdown())
.AddFlag("-dump", () => Utils.Dump())
.AddFlag("--stats-optout", () => StatTracker.OptOut = true)
.AddFlag("--no-restart", () => NoRestart = true);
CliParser.ParseFromSource(parms);
/*"-connperip": Todo - Requires an OTAPI modification
{
int limit;
if (int.TryParse(parms[++i], out limit))
{
//Netplay.MaxConnections = limit;
//ServerApi.LogWriter.PluginWriteLine(this, string.Format(
// "Connections per IP have been limited to {0} connections.", limit), TraceLevel.Verbose);
ServerApi.LogWriter.PluginWriteLine(this, "\"-connperip\" is not supported in this version of TShock.", TraceLevel.Verbose);
}
else
ServerApi.LogWriter.PluginWriteLine(this, "Invalid value given for command line argument \"-connperip\".", TraceLevel.Warning);
}*/
}
/// <summary>HandleCommandLinePostConfigLoad - Handles additional command line options after the config file is read.</summary>
/// <param name="parms">parms - The array of arguments passed in through the command line.</param>
public static void HandleCommandLinePostConfigLoad(string[] parms)
{
for (int i = 0; i < parms.Length; i++)
{
switch (parms[i].ToLower())
{
case "-port":
int port = Convert.ToInt32(parms[++i]);
Netplay.ListenPort = port;
Config.ServerPort = port;
OverridePort = true;
Log.ConsoleInfo("Port overridden by startup argument. Set to " + port);
break;
case "-rest-token":
string token = Convert.ToString(parms[++i]);
FlagSet portSet = new FlagSet("-port");
FlagSet playerSet = new FlagSet("-maxplayers", "-players");
FlagSet restTokenSet = new FlagSet("--rest-token", "-rest-token");
FlagSet restEnableSet = new FlagSet("--rest-enabled", "-rest-enabled");
FlagSet restPortSet = new FlagSet("--rest-port", "-rest-port");
CliParser
.AddFlags(portSet, (p) =>
{
int port;
if (int.TryParse(p, out port))
{
Netplay.ListenPort = port;
Config.ServerPort = port;
OverridePort = true;
Log.ConsoleInfo("Port overridden by startup argument. Set to " + port);
}
})
.AddFlags(restTokenSet, (token) =>
{
RESTStartupTokens.Add(token, new SecureRest.TokenData { Username = "null", UserGroupName = "superadmin" });
Console.WriteLine("Startup parameter overrode REST token.");
break;
case "-rest-enabled":
Config.RestApiEnabled = Convert.ToBoolean(parms[++i]);
Console.WriteLine("Startup parameter overrode REST enable.");
break;
case "-rest-port":
Config.RestApiPort = Convert.ToInt32(parms[++i]);
})
.AddFlags(restEnableSet, (e) =>
{
bool enabled;
if (bool.TryParse(e, out enabled))
{
Config.RestApiEnabled = enabled;
Console.WriteLine("Startup parameter overrode REST enable.");
}
})
.AddFlags(restPortSet, (p) =>
{
int restPort;
if (int.TryParse(p, out restPort))
{
Config.RestApiPort = restPort;
Console.WriteLine("Startup parameter overrode REST port.");
break;
case "-maxplayers":
case "-players":
Config.MaxSlots = Convert.ToInt32(parms[++i]);
Console.WriteLine("Startup parameter overrode maximum player slot configuration value.");
break;
}
}
}
})
.AddFlags(playerSet, (p)=>
{
int slots;
if (int.TryParse(p, out slots))
{
Config.MaxSlots = slots;
Console.WriteLine("Startup parameter overrode maximum player slot configuration value.");
}
});
CliParser.ParseFromSource(parms);
}
/// <summary>AuthToken - The auth token used by the /auth system to grant temporary superadmin access to new admins.</summary>
@ -1014,7 +1006,8 @@ namespace TShockAPI
if (player.TilePlaceThreshold >= Config.TilePlaceThreshold)
{
player.Disable("Reached TilePlace threshold", flags);
lock (player.TilesCreated) {
lock (player.TilesCreated)
{
TSPlayer.Server.RevertTiles(player.TilesCreated);
player.TilesCreated.Clear();
}
@ -1382,7 +1375,7 @@ namespace TShockAPI
}
}
}
/// <summary>OnLeave - Called when a player leaves the server.</summary>
/// <param name="args">args - The LeaveEventArgs object.</param>
private void OnLeave(LeaveEventArgs args)