add default port and rcon password hint during setup

This commit is contained in:
RaidMax
2021-11-14 21:38:00 -06:00
parent 072571d341
commit 08bcd23cbc
19 changed files with 232 additions and 47 deletions

View File

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using SharedLibraryCore.Interfaces;
namespace SharedLibraryCore.Configuration.Extensions
{
public static class ConfigurationExtensions
{
public static void TrySetIpAddress(this ServerConfiguration config)
{
try
{
var interfaces = NetworkInterface.GetAllNetworkInterfaces().Where(nic =>
nic.OperationalStatus == OperationalStatus.Up &&
(nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet && nic.GetIPProperties().UnicastAddresses
.Any(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork))).ToList();
var publicInterfaces = interfaces.Where(nic =>
nic.GetIPProperties().UnicastAddresses.Any(info =>
info.Address.AddressFamily == AddressFamily.InterNetwork && !info.Address.IsInternal()))
.ToList();
config.IPAddress = publicInterfaces.Any()
? publicInterfaces.First().GetIPProperties().UnicastAddresses.First().Address.ToString()
: IPAddress.Loopback.ToString();
}
catch
{
config.IPAddress = IPAddress.Loopback.ToString();
}
}
public static (string, string)[] TryGetRConPasswords(this IRConParser parser)
{
string searchPath = null;
var isRegistryKey = parser.Configuration.DefaultInstallationDirectoryHint.Contains("HKEY_");
try
{
if (isRegistryKey)
{
var result = Registry.GetValue(parser.Configuration.DefaultInstallationDirectoryHint, null, null);
if (result == null)
{
return new (string, string)[0];
}
searchPath = Path.Combine(result.ToString().Split(Path.DirectorySeparatorChar)
.Where(p => !p.Contains(".exe"))
.Select(p => p.Replace("\"", "")).ToArray());
}
else
{
var path = parser.Configuration.DefaultInstallationDirectoryHint.Replace("{LocalAppData}",
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
if (Directory.Exists(path))
{
searchPath = path;
}
}
if (string.IsNullOrEmpty(searchPath))
{
return new (string, string)[0];
}
var possibleFiles = Directory.GetFiles(searchPath, "*.cfg", SearchOption.AllDirectories);
if (!possibleFiles.Any())
{
return new (string, string)[0];
}
var possiblePasswords = possibleFiles.SelectMany(File.ReadAllLines)
.Select(line => Regex.Match(line, "^(\\/\\/)?.*rcon_password +\"?([^\\/\"\n]+)\"?"))
.Where(match => match.Success)
.Select(match =>
!string.IsNullOrEmpty(match.Groups[1].ToString())
? (match.Groups[2].ToString(),
Utilities.CurrentLocalization.LocalizationIndex["SETUP_RCON_PASSWORD_COMMENTED"])
: (match.Groups[2].ToString(), null));
return possiblePasswords.ToArray();
}
catch
{
return new (string, string)[0];
}
}
}
}

View File

@ -3,6 +3,7 @@ using SharedLibraryCore.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using SharedLibraryCore.Configuration.Extensions;
namespace SharedLibraryCore.Configuration
{
@ -10,96 +11,145 @@ namespace SharedLibraryCore.Configuration
{
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_IP")]
public string IPAddress { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PORT")]
public int Port { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PASSWORD")]
public string Password { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RULES")]
public string[] Rules { get; set; } = new string[0];
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_AUTO_MESSAGES")]
public string[] AutoMessages { get; set; } = new string[0];
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PATH")]
[ConfigurationOptional]
public string ManualLogPath { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RCON_PARSER")]
public string RConParserVersion { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_EVENT_PARSER")]
public string EventParserVersion { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RESERVED_SLOT")]
public int ReservedSlotNumber { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_GAME_LOG_SERVER")]
[ConfigurationOptional]
public Uri GameLogServerUrl { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_CUSTOM_HOSTNAME")]
[ConfigurationOptional]
public string CustomHostname { get; set; }
private readonly IList<IRConParser> rconParsers;
private readonly IList<IEventParser> eventParsers;
private readonly IList<IRConParser> _rconParsers;
private IRConParser _selectedParser;
public ServerConfiguration()
{
rconParsers = new List<IRConParser>();
eventParsers = new List<IEventParser>();
_rconParsers = new List<IRConParser>();
Rules = new string[0];
AutoMessages = new string[0];
}
public void AddRConParser(IRConParser parser)
{
rconParsers.Add(parser);
_rconParsers.Add(parser);
}
public void AddEventParser(IEventParser parser)
{
eventParsers.Add(parser);
}
public void ModifyParsers()
{
var loc = Utilities.CurrentLocalization.LocalizationIndex;
var parserVersions = rconParsers.Select(_parser => _parser.Name).ToArray();
var selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_RCON_PARSER_VERSION"]} ({IPAddress}:{Port})", parserVersions[0], null, parserVersions);
var parserVersions = _rconParsers.Select(p => p.Name).ToArray();
var (index, parser) = loc["SETUP_SERVER_RCON_PARSER_VERSION"].PromptSelection(parserVersions[0],
null, parserVersions);
if (selection.Item1 >= 0)
if (index < 0)
{
RConParserVersion = rconParsers.FirstOrDefault(_parser => _parser.Name == selection.Item2)?.Version;
if (selection.Item1 > 0 && !rconParsers[selection.Item1].CanGenerateLogPath)
{
Console.WriteLine(loc["SETUP_SERVER_NO_LOG"]);
ManualLogPath = Utilities.PromptString(loc["SETUP_SERVER_LOG_PATH"]);
}
return;
}
parserVersions = eventParsers.Select(_parser => _parser.Name).ToArray();
selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_EVENT_PARSER_VERSION"]} ({IPAddress}:{Port})", parserVersions[0], null, parserVersions);
_selectedParser = _rconParsers.FirstOrDefault(p => p.Name == parser);
RConParserVersion = _selectedParser?.Version;
EventParserVersion = _selectedParser?.Version;
if (selection.Item1 >= 0)
if (index <= 0 || _rconParsers[index].CanGenerateLogPath)
{
EventParserVersion = eventParsers.FirstOrDefault(_parser => _parser.Name == selection.Item2)?.Version;
return;
}
Console.WriteLine(loc["SETUP_SERVER_NO_LOG"]);
ManualLogPath = loc["SETUP_SERVER_LOG_PATH"].PromptString();
}
public IBaseConfiguration Generate()
{
ModifyParsers();
var loc = Utilities.CurrentLocalization.LocalizationIndex;
var shouldTryFindIp = loc["SETUP_SERVER_IP_AUTO"].PromptBool(defaultValue: true);
while (string.IsNullOrEmpty(IPAddress))
if (shouldTryFindIp)
{
var input = Utilities.PromptString(loc["SETUP_SERVER_IP"]);
IPAddress = input;
this.TrySetIpAddress();
Console.WriteLine(loc["SETUP_SERVER_IP_AUTO_RESULT"].FormatExt(IPAddress));
}
else
{
while (string.IsNullOrEmpty(IPAddress))
{
var input = loc["SETUP_SERVER_IP"].PromptString();
IPAddress = input;
}
}
var defaultPort = _selectedParser.Configuration.DefaultRConPort;
Port = loc["SETUP_SERVER_PORT"].PromptInt(null, 1, ushort.MaxValue, defaultValue:defaultPort);
if (!string.IsNullOrEmpty(_selectedParser.Configuration.DefaultInstallationDirectoryHint))
{
var shouldTryFindPassword = loc["SETUP_RCON_PASSWORD_AUTO"].PromptBool(defaultValue: true);
if (shouldTryFindPassword)
{
var passwords = _selectedParser.TryGetRConPasswords();
if (passwords.Length > 1)
{
var (index, value) =
loc["SETUP_RCON_PASSWORD_PROMPT"].PromptSelection("Other", null,
passwords.Select(pw =>
$"{pw.Item1}{(string.IsNullOrEmpty(pw.Item2) ? "" : " " + pw.Item2)}").ToArray());
if (index > 0)
{
Password = passwords[index - 1].Item1;
}
}
else if (passwords.Length > 0)
{
Password = passwords[0].Item1;
Console.WriteLine(loc["SETUP_RCON_PASSWORD_RESULT"].FormatExt(Password));
}
}
}
if (string.IsNullOrEmpty(Password))
{
Password = loc["SETUP_SERVER_RCON"].PromptString();
}
Port = Utilities.PromptInt(loc["SETUP_SERVER_PORT"], null, 1, ushort.MaxValue);
Password = Utilities.PromptString(loc["SETUP_SERVER_RCON"]);
AutoMessages = new string[0];
Rules = new string[0];
ReservedSlotNumber = loc["SETUP_SERVER_RESERVEDSLOT"].PromptInt(null, 0, 32);
ManualLogPath = null;
ModifyParsers();
return this;
}
@ -108,4 +158,4 @@ namespace SharedLibraryCore.Configuration
return "ServerConfiguration";
}
}
}
}

View File

@ -87,5 +87,15 @@ namespace SharedLibraryCore.Interfaces
/// specifies the characters used to split a line
/// </summary>
string NoticeLineSeparator { get; }
/// <summary>
/// Default port the game listens to RCon requests on
/// </summary>
int? DefaultRConPort { get; }
/// <summary>
/// Default Indicator of where the game is installed (ex file path or registry entry)
/// </summary>
string DefaultInstallationDirectoryHint { get; }
}
}

View File

@ -546,7 +546,7 @@ namespace SharedLibraryCore
/// <param name="description">description of the question's value</param>
/// <param name="defaultValue">default value to set if no input is entered</param>
/// <returns></returns>
public static bool PromptBool(string question, string description = null, bool defaultValue = true)
public static bool PromptBool(this string question, string description = null, bool defaultValue = true)
{
Console.Write($"{question}?{(string.IsNullOrEmpty(description) ? " " : $" ({description}) ")}[y/n]: ");
char response = Console.ReadLine().ToLower().FirstOrDefault();
@ -562,7 +562,7 @@ namespace SharedLibraryCore
/// <param name="description">description of the question's value</param>
/// <param name="selections">array of possible selections (should be able to convert to string)</param>
/// <returns></returns>
public static Tuple<int, T> PromptSelection<T>(string question, T defaultValue, string description = null, params T[] selections)
public static Tuple<int, T> PromptSelection<T>(this string question, T defaultValue, string description = null, params T[] selections)
{
bool hasDefault = false;
@ -634,7 +634,7 @@ namespace SharedLibraryCore
/// <param name="description">description of the question's value</param>
/// <param name="defaultValue">default value to set the return value to</param>
/// <returns></returns>
public static string PromptString(string question, string description = null, string defaultValue = null)
public static string PromptString(this string question, string description = null, string defaultValue = null)
{
string inputOrDefault()
{