From 56529f285d03a2f4bf3f7a3ba0980518905b8e11 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 18:57:19 -0600 Subject: [PATCH 01/30] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 7510fdd..697c263 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -6,7 +6,7 @@ on: jobs: build: - runs-on: windows-latest + runs-on: self-hosted steps: - name: Checkout uses: actions/checkout@v3 From 082d061c32151f269b0f6d3ddfa3267364b3cbcf Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 18:59:02 -0600 Subject: [PATCH 02/30] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 697c263..7510fdd 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -6,7 +6,7 @@ on: jobs: build: - runs-on: self-hosted + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v3 From 0625bc529499a06fd53bce71a83e16e237cff4c8 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 19:18:55 -0600 Subject: [PATCH 03/30] Update codeql.yml --- .github/workflows/codeql.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 397f2f3..a66c6a5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,6 +12,8 @@ name: "CodeQL" on: + push: + branches: [ "dev" ] pull_request: # The branches below must be a subset of the branches above branches: [ "dev" ] From 6f94e4b23a8c68e242cbd9fa53e48ab3d3da24c4 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 19:59:44 -0600 Subject: [PATCH 04/30] Update codeql.yml --- .github/workflows/codeql.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a66c6a5..473e1c8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -70,3 +70,11 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 + - name: Get current date + id: date + run: echo "::set-output name=date::$(date +'%Y-%m-%d')" + - name: Create Artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.branch-name.outputs.current_branch }}-codeql-${{steps.date.outputs.date}} + path: ./PlayerCountDiscordBot/results/csharp.sarif From 04031e4c62c8978430a78b8189dd3addb2e9f05e Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 20:07:52 -0600 Subject: [PATCH 05/30] Update codeql.yml --- .github/workflows/codeql.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 473e1c8..a66c6a5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -70,11 +70,3 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - name: Create Artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ steps.branch-name.outputs.current_branch }}-codeql-${{steps.date.outputs.date}} - path: ./PlayerCountDiscordBot/results/csharp.sarif From e735bc09888ef5e21a73dcfbd6e32db568dbfadc Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 22:12:52 -0600 Subject: [PATCH 06/30] BattleMetrics Update Add Battle Metrics to supported services. Change config to group application variables away from bot specific variables. Add auth parameter to HTTPExecuter. Sorry for the config change so soon :( --- DiscordPlayerCountBot/Bot/Bot.cs | 13 +-- DiscordPlayerCountBot/Bot/BotConfig.cs | 8 +- DiscordPlayerCountBot/Bot/BotInformation.cs | 6 +- .../Configuration/DockerConfiguration.cs | 6 +- .../Configuration/StandardConfiguration.cs | 3 +- .../Data/BattleMetrics/ServerListResponse.cs | 77 +++++++++++++++ .../Data/Steam/SteamServerListResponse.cs | 2 +- .../Data/Steam/SteamServerListSubClass.cs | 4 +- DiscordPlayerCountBot/Enum/DataProvider.cs | 3 +- DiscordPlayerCountBot/Http/HttpExecuter.cs | 25 ++--- DiscordPlayerCountBot/Http/IHttpExecuter.cs | 13 +-- .../Base/BattleMetricsParameters.cs | 41 ++++++++ .../QueryParams/Base/QueryParameterBuilder.cs | 2 +- .../Base/IServerInformationProvider.cs | 3 +- .../Base/ServerInformationProvider.cs | 3 +- .../Providers/BattleMetricsProvider.cs | 96 +++++++++++++++++++ .../Providers/CFXProvider.cs | 7 +- .../Providers/MinecraftProvider.cs | 3 +- .../Providers/ScumProvider.cs | 3 +- .../Providers/SteamProvider.cs | 17 +++- .../Services/BattleMetricsService.cs | 20 ++++ .../Services/IBattleMetricsService.cs | 10 ++ .../Services/ISteamService.cs | 2 +- .../Services/SteamService.cs | 9 +- DiscordPlayerCountBot/docker-compose.yml | 2 +- 25 files changed, 321 insertions(+), 57 deletions(-) create mode 100644 DiscordPlayerCountBot/Data/BattleMetrics/ServerListResponse.cs create mode 100644 DiscordPlayerCountBot/Http/QueryParams/Base/BattleMetricsParameters.cs create mode 100644 DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs create mode 100644 DiscordPlayerCountBot/Services/BattleMetricsService.cs create mode 100644 DiscordPlayerCountBot/Services/IBattleMetricsService.cs diff --git a/DiscordPlayerCountBot/Bot/Bot.cs b/DiscordPlayerCountBot/Bot/Bot.cs index 8211df9..d2a1efc 100644 --- a/DiscordPlayerCountBot/Bot/Bot.cs +++ b/DiscordPlayerCountBot/Bot/Bot.cs @@ -19,16 +19,16 @@ public class Bot public BotInformation Information { get; set; } public DiscordSocketClient DiscordClient { get; set; } public Dictionary DataProviders { get; set; } = new(); + public Dictionary ApplicationTokens { get; set; } = new(); private ILog Logger = LogManager.GetLogger(typeof(Bot)); - public Bot(BotInformation info) + public Bot(BotInformation info, Dictionary applicationTokens) { - if (info is null) - { - throw new ArgumentNullException(nameof(info)); - } + if (info is null) throw new ArgumentNullException(nameof(info)); + if (applicationTokens is null) throw new ArgumentException(nameof(applicationTokens)); + ApplicationTokens = applicationTokens; Information = info; DiscordClient = new DiscordSocketClient(new DiscordSocketConfig() @@ -45,6 +45,7 @@ public void InitDataProviders() DataProviders.Add((int)DataProvider.CFX, new CFXProvider()); DataProviders.Add((int)DataProvider.SCUM, new ScumProvider()); DataProviders.Add((int)DataProvider.MINECRAFT, new MinecraftProvider()); + DataProviders.Add((int)DataProvider.BATTLEMETRICS, new BattleMetricsProvider()); } public async Task StartAsync() @@ -78,7 +79,7 @@ public async Task UpdateAsync() } var dataProvider = DataProviders[dataProviderType]; - var serverInformation = await dataProvider.GetServerInformation(Information); + var serverInformation = await dataProvider.GetServerInformation(Information, ApplicationTokens); if (serverInformation == null) { diff --git a/DiscordPlayerCountBot/Bot/BotConfig.cs b/DiscordPlayerCountBot/Bot/BotConfig.cs index a5110b2..85fd43b 100644 --- a/DiscordPlayerCountBot/Bot/BotConfig.cs +++ b/DiscordPlayerCountBot/Bot/BotConfig.cs @@ -9,10 +9,10 @@ public class BotConfig public int UpdateTime { get; set; } [JsonProperty] - public string SteamAPIKey { get; set; } + public List ServerInformation { get; set; } = new(); [JsonProperty] - public List ServerInformation { get; set; } = new(); + public Dictionary ApplicationTokens { get; set; } = new(); public void CreateDefaults() { @@ -26,7 +26,9 @@ public void CreateDefaults() UseNameAsLabel = false }); UpdateTime = 30; - SteamAPIKey = "SteamAPIKeyHere"; + + ApplicationTokens.Add("SteamAPIKey", ""); + ApplicationTokens.Add("BattleMetricsKey", ""); } } } diff --git a/DiscordPlayerCountBot/Bot/BotInformation.cs b/DiscordPlayerCountBot/Bot/BotInformation.cs index 54edb1e..303f1c3 100644 --- a/DiscordPlayerCountBot/Bot/BotInformation.cs +++ b/DiscordPlayerCountBot/Bot/BotInformation.cs @@ -28,14 +28,14 @@ public class BotInformation [JsonProperty] public ulong? ChannelID { get; set; } - [JsonIgnore] - public string SteamAPIToken { get; set; } - public Tuple GetAddressAndPort() { string[] splitData = Address.Split(":"); try { + if (splitData.Length == 1) + return new Tuple(splitData[0], 0); + ushort port = ushort.Parse(splitData[1]); return new Tuple(splitData[0], port); } diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index 8de9ea0..c1a8803 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -25,6 +25,7 @@ public async Task, int>> Configure() var botTags = Environment.GetEnvironmentVariable("BOT_USENAMETAGS")?.Split(";"); var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")?.Split(";"); + var applicationTokens = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")?.Split(";").ToDictionary(data => data.Split(",")[0]) ?? new(); var channelIDs = new List(); if (Environment.GetEnvironmentVariables().Contains("BOT_CHANNELIDS")) @@ -80,11 +81,10 @@ public async Task, int>> Configure() Status = activity, UseNameAsLabel = useNameAsLabel, ChannelID = channelID ?? null, - ProviderType = (int)EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")), - SteamAPIToken = Environment.GetEnvironmentVariable("STEAM_API_KEY") ?? "", + ProviderType = (int)EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")) }; - var bot = new Bot(info); + var bot = new Bot(info, applicationTokens); await bot.StartAsync(); bots.Add(bot.Information.Address, bot); } diff --git a/DiscordPlayerCountBot/Configuration/StandardConfiguration.cs b/DiscordPlayerCountBot/Configuration/StandardConfiguration.cs index 6c61525..4c3e8b9 100644 --- a/DiscordPlayerCountBot/Configuration/StandardConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/StandardConfiguration.cs @@ -38,8 +38,7 @@ public async Task, int>> Configure() foreach (var info in config.ServerInformation) { - info.SteamAPIToken = config.SteamAPIKey; - var bot = new Bot(info); + var bot = new Bot(info, config.ApplicationTokens); await bot.StartAsync(); bots.Add(bot.Information.Address, bot); } diff --git a/DiscordPlayerCountBot/Data/BattleMetrics/ServerListResponse.cs b/DiscordPlayerCountBot/Data/BattleMetrics/ServerListResponse.cs new file mode 100644 index 0000000..5f2d543 --- /dev/null +++ b/DiscordPlayerCountBot/Data/BattleMetrics/ServerListResponse.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +namespace DiscordPlayerCountBot.Data +{ +#nullable enable + public class BattleMetricsServerDetails + { + public List modIds { get; set; } = new List(); + public List modHashes { get; set; } = new List(); + public string? map { get; set; } + public string? time { get; set; } + public string? time_i { get; set; } + public bool? official { get; set; } + public string? gamemode { get; set; } + public List? modNames { get; set; } + public bool? pve { get; set; } + public bool? modded { get; set; } + public bool? crossplay { get; set; } + public string? session_flags { get; set; } + public string? serverSteamId { get; set; } + } + + public class BattleMetricsServerAttributes + { + public string? id { get; set; } + public string? name { get; set; } + public string? address { get; set; } + public string? ip { get; set; } + public int? port { get; set; } + public int? players { get; set; } + public int? maxPlayers { get; set; } + public int? rank { get; set; } + public List location { get; set; } = new List(); + public string? status { get; set; } + public BattleMetricsServerDetails? details { get; set; } + public bool? @private { get; set; } + public DateTime? createdAt { get; set; } + public DateTime? updatedAt { get; set; } + public int? portQuery { get; set; } + public string? country { get; set; } + public string? queryStatus { get; set; } + } + + public class BattleMetricsServerData + { + public string? type { get; set; } + public string? id { get; set; } + public BattleMetricsServerAttributes? attributes { get; set; } + public BattleMetricsServerRelationships? relationships { get; set; } + } + + public class BattleMetricsServerGame + { + public BattleMetricsServerData? data { get; set; } + } + + public class BattleMetricsServerRelationships + { + public BattleMetricsServerGame? game { get; set; } + } + + public class Links + { + public string? prev { get; set; } + public string? next { get; set; } + } + + public class BattleMetricsServerRoot + { + public List? data { get; set; } + public Links? links { get; set; } + public List? included { get; set; } + } + +#nullable disable +} \ No newline at end of file diff --git a/DiscordPlayerCountBot/Data/Steam/SteamServerListResponse.cs b/DiscordPlayerCountBot/Data/Steam/SteamServerListResponse.cs index 720ab2b..dc4935e 100644 --- a/DiscordPlayerCountBot/Data/Steam/SteamServerListResponse.cs +++ b/DiscordPlayerCountBot/Data/Steam/SteamServerListResponse.cs @@ -12,7 +12,7 @@ public SteamServerListResponse() response = new SteamServerListSubClass(); } - public SteamApiResponseData? GetServerDataByPort(string port) + public SteamApiResponseData? GetServerDataByPort(int port) { return response.GetAddressDataByPort(port); } diff --git a/DiscordPlayerCountBot/Data/Steam/SteamServerListSubClass.cs b/DiscordPlayerCountBot/Data/Steam/SteamServerListSubClass.cs index 1183645..f81d9d0 100644 --- a/DiscordPlayerCountBot/Data/Steam/SteamServerListSubClass.cs +++ b/DiscordPlayerCountBot/Data/Steam/SteamServerListSubClass.cs @@ -13,11 +13,11 @@ public SteamServerListSubClass() servers = new List(); } - public SteamApiResponseData? GetAddressDataByPort(string port) + public SteamApiResponseData? GetAddressDataByPort(int port) { foreach (SteamApiResponseData data in servers) { - if (data.addr.Split(":")[1] == port) + if (int.Parse(data.addr.Split(":")[1]) == port) { return data; } diff --git a/DiscordPlayerCountBot/Enum/DataProvider.cs b/DiscordPlayerCountBot/Enum/DataProvider.cs index 77c74f7..d25c0fb 100644 --- a/DiscordPlayerCountBot/Enum/DataProvider.cs +++ b/DiscordPlayerCountBot/Enum/DataProvider.cs @@ -5,6 +5,7 @@ public enum DataProvider STEAM, CFX, SCUM, - MINECRAFT + MINECRAFT, + BATTLEMETRICS } } diff --git a/DiscordPlayerCountBot/Http/HttpExecuter.cs b/DiscordPlayerCountBot/Http/HttpExecuter.cs index b935e52..010c5e8 100644 --- a/DiscordPlayerCountBot/Http/HttpExecuter.cs +++ b/DiscordPlayerCountBot/Http/HttpExecuter.cs @@ -23,32 +23,32 @@ public void Dispose() GC.SuppressFinalize(this); } - public async Task GET(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default) + public async Task GET(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default, Tuple? authToken = null) { - return await ExecuteHttpRequest(endPoint, HttpMethod.Get, queryBuilder, body); + return await ExecuteHttpRequest(endPoint, HttpMethod.Get, queryBuilder, body, authToken); } - public async Task POST(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default) + public async Task POST(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default, Tuple? authToken = null) { - return await ExecuteHttpRequest(endPoint, HttpMethod.Post, queryBuilder, body); + return await ExecuteHttpRequest(endPoint, HttpMethod.Post, queryBuilder, body, authToken); } - public async Task PATCH(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default) + public async Task PATCH(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default, Tuple? authToken = null) { - return await ExecuteHttpRequest(endPoint, HttpMethod.Patch, queryBuilder, body); + return await ExecuteHttpRequest(endPoint, HttpMethod.Patch, queryBuilder, body, authToken); } - public async Task PUT(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default) + public async Task PUT(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default, Tuple? authToken = null) { - return await ExecuteHttpRequest(endPoint, HttpMethod.Put, queryBuilder, body); + return await ExecuteHttpRequest(endPoint, HttpMethod.Put, queryBuilder, body, authToken); } - public async Task DELETE(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default) + public async Task DELETE(string endPoint, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default, Tuple? authToken = null) { - return await ExecuteHttpRequest(endPoint, HttpMethod.Delete, queryBuilder, body); + return await ExecuteHttpRequest(endPoint, HttpMethod.Delete, queryBuilder, body, authToken); } - private async Task ExecuteHttpRequest(string endPoint, HttpMethod method, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default) + private async Task ExecuteHttpRequest(string endPoint, HttpMethod method, IQueryParameterBuilder? queryBuilder = null, TRequest? body = default, Tuple? authToken = null) { if (HttpClient == null) return default; @@ -57,6 +57,9 @@ public void Dispose() using var request = new HttpRequestMessage(method, fullPath); + if (authToken != null) + request.Headers.Add(authToken?.Item1!, authToken?.Item2); + if (body != null) request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); diff --git a/DiscordPlayerCountBot/Http/IHttpExecuter.cs b/DiscordPlayerCountBot/Http/IHttpExecuter.cs index 5596c64..9308468 100644 --- a/DiscordPlayerCountBot/Http/IHttpExecuter.cs +++ b/DiscordPlayerCountBot/Http/IHttpExecuter.cs @@ -1,13 +1,14 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace DiscordPlayerCountBot.Http { public interface IHttpExecuter { - Task DELETE(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body); - Task GET(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body); - Task PATCH(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body); - Task POST(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body); - Task PUT(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body); + Task DELETE(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body, Tuple? authToken = null); + Task GET(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body, Tuple? authToken = null); + Task PATCH(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body, Tuple? authToken = null); + Task POST(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body, Tuple? authToken = null); + Task PUT(string endPoint, IQueryParameterBuilder queryBuilder, TRequest? body, Tuple? authToken = null); } } \ No newline at end of file diff --git a/DiscordPlayerCountBot/Http/QueryParams/Base/BattleMetricsParameters.cs b/DiscordPlayerCountBot/Http/QueryParams/Base/BattleMetricsParameters.cs new file mode 100644 index 0000000..cd891de --- /dev/null +++ b/DiscordPlayerCountBot/Http/QueryParams/Base/BattleMetricsParameters.cs @@ -0,0 +1,41 @@ +using DiscordPlayerCountBot.Attributes; +using System; +using System.Linq; + +namespace DiscordPlayerCountBot.Http +{ + + public class BattleMetricsParameters : QueryParameterBuilder + { + public override string CreateQueryParameterString() + { + var filterString = ""; + var type = GetType(); + + int i = 0; + type.GetProperties().ToList().ForEach(property => + { + var propertyValue = property.GetValue(this); + + if (propertyValue != null) + { + if (Attribute.GetCustomAttribute(property, typeof(NameAttribute)) is not NameAttribute nameAttribute) + { + throw new Exception("TODO: Throw actual error, not generic exception. Due to coding standards, we need attributes on parameters."); + } + + if (i == 0) + filterString += "?"; + + if (i > 0) + filterString += "&"; + + filterString += $"filter[{nameAttribute.Name}]={propertyValue}"; + i++; + } + }); + + return filterString; + } + } +} diff --git a/DiscordPlayerCountBot/Http/QueryParams/Base/QueryParameterBuilder.cs b/DiscordPlayerCountBot/Http/QueryParams/Base/QueryParameterBuilder.cs index 54db9e4..fe1d40b 100644 --- a/DiscordPlayerCountBot/Http/QueryParams/Base/QueryParameterBuilder.cs +++ b/DiscordPlayerCountBot/Http/QueryParams/Base/QueryParameterBuilder.cs @@ -5,7 +5,7 @@ namespace DiscordPlayerCountBot.Http { public class QueryParameterBuilder : IQueryParameterBuilder { - public string CreateQueryParameterString() + public virtual string CreateQueryParameterString() { var type = GetType(); var properties = type.GetProperties(); diff --git a/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs b/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs index 9f32807..a02d638 100644 --- a/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs +++ b/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using PlayerCountBot; @@ -8,6 +9,6 @@ public interface IServerInformationProvider { bool WasLastExecutionAFailure { get; set; } Exception? LastException { get; set; } - Task GetServerInformation(BotInformation information); + Task GetServerInformation(BotInformation information, Dictionary applicationVariables); } } diff --git a/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs b/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs index 709b082..92f39ae 100644 --- a/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs +++ b/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using PlayerCountBot; @@ -9,6 +10,6 @@ public abstract class ServerInformationProvider : IServerInformationProvider public bool WasLastExecutionAFailure { get; set; } = false; public Exception? LastException { get; set; } - public abstract Task GetServerInformation(BotInformation information); + public abstract Task GetServerInformation(BotInformation information, Dictionary applicationVariables); } } diff --git a/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs b/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs new file mode 100644 index 0000000..0b5dc93 --- /dev/null +++ b/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using DiscordPlayerCountBot.Providers.Base; +using DiscordPlayerCountBot.Services; +using log4net; +using PlayerCountBot; + +namespace DiscordPlayerCountBot.Providers +{ + public class BattleMetricsProvider : ServerInformationProvider + { + private ILog Logger = LogManager.GetLogger(typeof(BattleMetricsProvider)); + + public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) + { + var service = new BattleMetricsService(); + + try + { + var addressAndPort = information.GetAddressAndPort(); + var server = await service.GetPlayerInformationAsync(addressAndPort.Item1, applicationVariables["BattleMetricsKey"]); + + if (server == null) + throw new ApplicationException("Server cannot be null. Is your server offline?"); + + + if (WasLastExecutionAFailure) + { + Logger.Info($"[Battle Metrics Provider] - Bot for Address: {information.Address} successfully fetched data after failure."); + LastException = null; + WasLastExecutionAFailure = false; + } + + return new GenericServerInformation() + { + Address = addressAndPort.Item1, + CurrentPlayers = server.attributes?.players ?? 0, + MaxPlayers = server.attributes?.maxPlayers ?? 0, + Port = addressAndPort.Item2, + PlayersInQueue = 0 + }; + } + catch (Exception e) + { + if (e.Message == LastException?.Message) + return null; + + WasLastExecutionAFailure = true; + LastException = e; + + if (e is KeyNotFoundException keyNotFoundException) + { + Logger.Error($"[Battle Metrics Provider] - BattleMetricKey is missing from Application variable configuration."); + return null; + } + + if (e is HttpRequestException requestException) + { + Logger.Error($"[Battle Metrics Provider] - The BattleMetric host has failed to respond."); + return null; + } + + if (e is WebException webException) + { + if (webException.Status == WebExceptionStatus.Timeout) + { + Logger.Error($"[Battle Metrics Provider] - Speaking with BattleMetric has timed out."); + return null; + } + else if (webException.Status == WebExceptionStatus.ConnectFailure) + { + Logger.Error($"[Battle Metrics Provider] - Could not connect to BattleMetric."); + return null; + } + else + { + Logger.Error($"[Battle Metrics Provider] - There was an error speaking with your BattleMetric server.", e); + return null; + } + } + + if (e is ApplicationException applicationException) + { + Logger.Error($"[Battle Metrics Provider] - {e.Message}"); + return null; + } + + Logger.Error($"[Battle Metrics Provider] - There was an error speaking with BattleMetric.", e); + throw; + } + } + } +} diff --git a/DiscordPlayerCountBot/Providers/CFXProvider.cs b/DiscordPlayerCountBot/Providers/CFXProvider.cs index 2026de7..951c5a0 100644 --- a/DiscordPlayerCountBot/Providers/CFXProvider.cs +++ b/DiscordPlayerCountBot/Providers/CFXProvider.cs @@ -1,19 +1,22 @@ using System; +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; using log4net; +using log4net.Repository.Hierarchy; using PlayerCountBot; namespace DiscordPlayerCountBot.Providers { + public class CFXProvider : ServerInformationProvider { - private ILog Logger = LogManager.GetLogger(typeof(SteamProvider)); + private ILog Logger = LogManager.GetLogger(typeof(CFXProvider)); - public async override Task GetServerInformation(BotInformation information) + public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new CFXService(); diff --git a/DiscordPlayerCountBot/Providers/MinecraftProvider.cs b/DiscordPlayerCountBot/Providers/MinecraftProvider.cs index 8d5ce6b..cf97713 100644 --- a/DiscordPlayerCountBot/Providers/MinecraftProvider.cs +++ b/DiscordPlayerCountBot/Providers/MinecraftProvider.cs @@ -6,13 +6,14 @@ using System.Net.Http; using System.Net; using System.Threading.Tasks; +using System.Collections.Generic; namespace DiscordPlayerCountBot.Providers { public class MinecraftProvider : ServerInformationProvider { private ILog Logger = LogManager.GetLogger(typeof(MinecraftProvider)); - public async override Task GetServerInformation(BotInformation information) + public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new MinecraftService(); var addressAndPort = information.GetAddressAndPort(); diff --git a/DiscordPlayerCountBot/Providers/ScumProvider.cs b/DiscordPlayerCountBot/Providers/ScumProvider.cs index bf805e4..b043ce5 100644 --- a/DiscordPlayerCountBot/Providers/ScumProvider.cs +++ b/DiscordPlayerCountBot/Providers/ScumProvider.cs @@ -3,6 +3,7 @@ using log4net; using PlayerCountBot; using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -14,7 +15,7 @@ public class ScumProvider : ServerInformationProvider { private ILog Logger = LogManager.GetLogger(typeof(ScumProvider)); - public async override Task GetServerInformation(BotInformation information) + public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new ScumService(); var addressAndPort = information.GetAddressAndPort(); diff --git a/DiscordPlayerCountBot/Providers/SteamProvider.cs b/DiscordPlayerCountBot/Providers/SteamProvider.cs index 33fdf1d..f2cc09b 100644 --- a/DiscordPlayerCountBot/Providers/SteamProvider.cs +++ b/DiscordPlayerCountBot/Providers/SteamProvider.cs @@ -3,6 +3,7 @@ using log4net; using PlayerCountBot; using System; +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -13,14 +14,14 @@ public class SteamProvider : ServerInformationProvider { private ILog Logger = LogManager.GetLogger(typeof(SteamProvider)); - public async override Task GetServerInformation(BotInformation information) + public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new SteamService(); - var serverPortAndAddress = information.GetAddressAndPort(); try { - var response = await service.GetSteamApiResponse(information); + var addressAndPort = information.GetAddressAndPort(); + var response = await service.GetSteamApiResponse(addressAndPort.Item1, addressAndPort.Item2, applicationVariables["SteamAPIKey"]); if (response == null) throw new ApplicationException($"Server Address: {information.Address} was not found in Steam's directory."); @@ -34,8 +35,8 @@ public class SteamProvider : ServerInformationProvider return new() { - Address = serverPortAndAddress.Item1, - Port = serverPortAndAddress.Item2, + Address = addressAndPort.Item1, + Port = addressAndPort.Item2, CurrentPlayers = response.players, MaxPlayers = response.max_players, PlayersInQueue = response.GetQueueCount() @@ -49,6 +50,12 @@ public class SteamProvider : ServerInformationProvider WasLastExecutionAFailure = true; LastException = e; + if (e is KeyNotFoundException keyNotFoundException) + { + Logger.Error($"[SteamProvider] - SteamAPIKey is missing from Application variable configuration."); + return null; + } + if (e is HttpRequestException requestException) { Logger.Error($"[SteamProvider] - The Steam has failed to respond."); diff --git a/DiscordPlayerCountBot/Services/BattleMetricsService.cs b/DiscordPlayerCountBot/Services/BattleMetricsService.cs new file mode 100644 index 0000000..8f90020 --- /dev/null +++ b/DiscordPlayerCountBot/Services/BattleMetricsService.cs @@ -0,0 +1,20 @@ +using DiscordPlayerCountBot.Data; +using DiscordPlayerCountBot.Http; +using System; +using System.Net.Http; +using System.Threading.Tasks; + +namespace DiscordPlayerCountBot.Services +{ + + public class BattleMetricsService : IBattleMetricsService + { + public async Task GetPlayerInformationAsync(string address, string token) + { + using var httpClient = new HttpExecuter(new HttpClient()); + + var response = await httpClient.GET($"https://api.battlemetrics.com/servers/{address}", authToken: new Tuple("Authorization", token)); + return response?.data; + } + } +} diff --git a/DiscordPlayerCountBot/Services/IBattleMetricsService.cs b/DiscordPlayerCountBot/Services/IBattleMetricsService.cs new file mode 100644 index 0000000..5d0b5e3 --- /dev/null +++ b/DiscordPlayerCountBot/Services/IBattleMetricsService.cs @@ -0,0 +1,10 @@ +using DiscordPlayerCountBot.Data; +using System.Threading.Tasks; + +namespace DiscordPlayerCountBot.Services +{ + public interface IBattleMetricsService + { + public Task GetPlayerInformationAsync(string address, string token); + } +} diff --git a/DiscordPlayerCountBot/Services/ISteamService.cs b/DiscordPlayerCountBot/Services/ISteamService.cs index 0746471..68afcb1 100644 --- a/DiscordPlayerCountBot/Services/ISteamService.cs +++ b/DiscordPlayerCountBot/Services/ISteamService.cs @@ -5,6 +5,6 @@ namespace DiscordPlayerCountBot.Services { public interface ISteamService { - public Task GetSteamApiResponse(BotInformation information); + public Task GetSteamApiResponse(string address, int port, string token); } } diff --git a/DiscordPlayerCountBot/Services/SteamService.cs b/DiscordPlayerCountBot/Services/SteamService.cs index 4c9a2c3..2c5cf65 100644 --- a/DiscordPlayerCountBot/Services/SteamService.cs +++ b/DiscordPlayerCountBot/Services/SteamService.cs @@ -11,19 +11,18 @@ public class SteamService : ISteamService { public ILog Logger = LogManager.GetLogger(typeof(SteamService)); - public async Task GetSteamApiResponse(BotInformation information) + public async Task GetSteamApiResponse(string address, int port, string token) { using var httpClient = new HttpExecuter(new HttpClient()); var response = await httpClient.GET("https://api.steampowered.com/IGameServersService/GetServerList/v1/", new SteamGetServerListQueryParams() { - Key = information.SteamAPIToken, - Filter = $"\\addr\\{information.Address}" + Key = token, + Filter = $"\\addr\\{address}:{port}" }); if (response == null) return null; - var serverPortAndAddress = information.GetAddressAndPort(); - var data = response.GetServerDataByPort(serverPortAndAddress.Item2.ToString()); + var data = response.GetServerDataByPort(port); if (data == null) return null; diff --git a/DiscordPlayerCountBot/docker-compose.yml b/DiscordPlayerCountBot/docker-compose.yml index 24cc194..ce4db4c 100644 --- a/DiscordPlayerCountBot/docker-compose.yml +++ b/DiscordPlayerCountBot/docker-compose.yml @@ -16,4 +16,4 @@ services: #Application Variables #These setting apply to the whole application. BOT_UPDATE_TIME: "30" - STEAM_API_KEY: "SteamAPIKeyHere" \ No newline at end of file + BOT_APPLICATION_VARIABLES: "SteamAPIKey,KeyHere;BattleMetricsKey,KeyHere" \ No newline at end of file From f1af4d9b4a3a1a5b8b8c0b28bd722214d02d4f01 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 22:15:58 -0600 Subject: [PATCH 07/30] Update README.MD --- README.MD | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.MD b/README.MD index abbb942..7fcfa6c 100644 --- a/README.MD +++ b/README.MD @@ -69,12 +69,13 @@ The available states that I have are as follows: This bot works with many different providers to display your game server's player counts. The available providers are listed below. -| Name | Config Value | -| :----: | --- | -| Steam | 0 | -| CFX | 1 | -| Scum | 2 | -| Minecraft | 3 | +| Name | Config Value | Note | +| :----: | --- | --- | +| Steam | 0 | Limit 1 Milion requests per 24 hours | +| CFX | 1 | N/A| +| Scum | 2 | Uses game | +| Minecraft | 3 | NA | +| BattleMetrics | 4 | Uses Battle Metrics ID (Check the Battle Metrics URL on their website for your ID)| #### Address Resolution You may use `localhost` or `hostname` as your server address for the application to automatically resolve the hosts IP. From 0903cd12e86d9abea911f68859815cbff8d97382 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 22:16:49 -0600 Subject: [PATCH 08/30] Update README.MD --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 7fcfa6c..5c455ff 100644 --- a/README.MD +++ b/README.MD @@ -75,7 +75,7 @@ This bot works with many different providers to display your game server's playe | CFX | 1 | N/A| | Scum | 2 | Uses game | | Minecraft | 3 | NA | -| BattleMetrics | 4 | Uses Battle Metrics ID (Check the Battle Metrics URL on their website for your ID)| +| BattleMetrics | 4 | Uses Battle Metrics ID (Check the Battle Metrics URL on their website for your ID) [Example](https://www.battlemetrics.com/servers/minecraft/5873087)| #### Address Resolution You may use `localhost` or `hostname` as your server address for the application to automatically resolve the hosts IP. From e9e56a9949eefe954e50add456b360925a933ccf Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:07:37 -0600 Subject: [PATCH 09/30] Update README.MD --- README.MD | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/README.MD b/README.MD index 5c455ff..02e25d7 100644 --- a/README.MD +++ b/README.MD @@ -12,12 +12,17 @@ After installation of .Net Runtime 6, you need to run the application one time. ![image](https://user-images.githubusercontent.com/24533882/188336821-4d368b36-ecfb-44a5-88f1-b05909f20b05.png) -# Getting a Steam API key -In order to get a steam API key, you will need a domain to link it to. Trying looking into [Google's domain site](https://domains.google.com/registrar/). After you have gotten a domain navigate to [Steam'd Web API Key Register](https://steamcommunity.com/dev/apikey), and get your Steam API Key. Copy your `Key` and put it in your config file by replacing `SteamAPIKeyHere` with your Steam API Key. +# Getting a Steam API Key +In order to get a Steam API key, you will need a domain to link it to. Trying looking into [Google's domain site](https://domains.google.com/registrar/). After you have gotten a domain navigate to [Steam'd Web API Key Register](https://steamcommunity.com/dev/apikey), and get your Steam API Key. Copy your `Key` and put it in your config file by replacing `SteamAPIKeyHere` with your Steam API Key. ![image](https://user-images.githubusercontent.com/24533882/103162963-c9304000-47b4-11eb-814e-c6156649b908.png) -![image](https://user-images.githubusercontent.com/24533882/188337476-aa1919f1-4fa5-41e6-869d-9bb8827aa2e1.png) +![image](https://user-images.githubusercontent.com/24533882/188550022-53db7967-ba8d-4100-b258-c81dc67514ca.png) + +# Getting a Battle Metrics Key +In order to get a Battle Metrics API Key, you will need to visit [here](https://www.battlemetrics.com/developers), and generate an api token. After you must replace `Here` with your Battle Metrics API Key. + +![image](https://user-images.githubusercontent.com/24533882/188550180-070db933-0db9-45bd-bd17-caaf03ffc00c.png) # Creating a bot(s) @@ -35,13 +40,15 @@ After you have created your bot and named it, you will need to copy the bots `To ![image](https://user-images.githubusercontent.com/24533882/103163390-9ab56380-47ba-11eb-9c44-ec7f83343078.png) -![image](https://user-images.githubusercontent.com/24533882/188337485-ad4ecd6c-6c77-4ecb-bfe3-e5e107409624.png) +![image](https://user-images.githubusercontent.com/24533882/188548745-78d978f5-652d-4a54-9fde-b490370ebc4f.png) # Configuring Server's -After you have added your Steam API key, and your bot's token you must add the `botAddress`, this address is your query address for the server. This is so we know what game server's player count to display in the status of each bot. In order to configure the bot to display the player count, you must add the IP, and the Port in the format `Address:Port` ex. `23.23.233.233:27015` where `127.0.0.1:2532` is located. This address is **NOT** the connection address. +After you have added your keyS, and your bot's token you must add the `botAddress`, this address is IP and port for the server. **Which port? That depends on your provider. Look [here.](#data-providers)** -![image](https://user-images.githubusercontent.com/24533882/188337510-32d913b8-10a9-451c-9a90-18e26a10a054.png) +If your data provider depends on a port, your address must be formatted as: `address:port`. Example: `127.0.0.1:3450` + +![image](https://user-images.githubusercontent.com/24533882/188548793-322db8f4-10d1-4963-9b88-16f9b7870b64.png) # Invite Your Bot After all configuration steps have been taken, we must start the bot and invite them into our discord. The bot needs no special permissions due to it's responsibility being to update it's status. In order to invite your discord bot, you must replace `{clientID}` with your bots client ID in the URL below, this means you must also remove the curly braces too. If you do not know where to obtain your bot's client ID, navigate to `General Information` tab on the Discord Developer Portal the bot you wish, and copy your Client ID from there. @@ -62,25 +69,25 @@ The available states that I have are as follows: | Streaming | 1 | The user is streaming online | | Listening | 2 | The user is listening to a song. | | Watching | 3 | The user is watching some form of media. | -| CustomStatus | 4 | The user has set a customer status. | +| CustomStatus | 4 | The user has set a customer status. **Do not use.** | | Competing | 5 | The user is competing in a game. | #### Data Providers This bot works with many different providers to display your game server's player counts. The available providers are listed below. -| Name | Config Value | Note | -| :----: | --- | --- | -| Steam | 0 | Limit 1 Milion requests per 24 hours | -| CFX | 1 | N/A| -| Scum | 2 | Uses game | -| Minecraft | 3 | NA | -| BattleMetrics | 4 | Uses Battle Metrics ID (Check the Battle Metrics URL on their website for your ID) [Example](https://www.battlemetrics.com/servers/minecraft/5873087)| +| Name | Config Value | Note | Port Type | +| :----: | --- | --- | ---- | +| Steam | 0 | Limit 1 Milion requests per 24 hours | Steam Query Port | +| CFX | 1 | N/A | Game Port | +| Scum | 2 | Uses game | Game Port | +| Minecraft | 3 | NA | Game Port | +| BattleMetrics | 4 | Uses Battle Metrics ID. [ID is the number in this URL](https://www.battlemetrics.com/servers/minecraft/5873087) | Battle Metrics Server ID | #### Address Resolution You may use `localhost` or `hostname` as your server address for the application to automatically resolve the hosts IP. -![image](https://user-images.githubusercontent.com/24533882/188337540-6b57cd27-b307-476f-8bdf-e190d00ac2f5.png) +![image](https://user-images.githubusercontent.com/24533882/188549477-753fb698-0d34-479b-970e-b2e265e90bd8.png) #### Channel Player Counts You may add the ChannelID variable to any bot to have the bot update the name of a text channel, or voice channel. @@ -90,7 +97,7 @@ ChanelID does not need to be specified in either Docker, or Executable instances This rate limit is enforced by Discord, and not the library used Discord.Net -![image](https://user-images.githubusercontent.com/24533882/188337578-ce80d5b3-1ff3-4cc4-aa38-86320f1a0459.png) +![image](https://user-images.githubusercontent.com/24533882/188549536-35000ab2-5f90-416c-b641-29a534c9511f.png) **Voice Channel Format:** @@ -110,7 +117,7 @@ This rate limit is enforced by Discord, and not the library used Discord.Net | Tag | Description | | :----: | --- | | latest | Latest stable releases | -| Beta | May be unstable and contain unfinished features | +| dev | May be unstable and contain unfinished features | ## Usage @@ -135,7 +142,7 @@ There are two ways to deploy bots with Docker. BOT_STATUSES: "1;2" BOT_USENAMETAGS: "false;false" BOT_PROVIDERTYPES: "0;0" - STEAM_API_KEY: "your steam api key" + BOT_APPLICATION_VARIABLES: "SteamAPIKey,Here;BattleMetricsKey,Here" ``` 3. Edit variables and save the File 4. Open terminal in a location of `docker-compose.yml` file and type `docker-compose up` @@ -156,7 +163,7 @@ There are two ways to deploy bots with Docker. -e BOT_STATUSES='1;2' \ -e BOT_PROVIDERTYPES='0;0' \ -e BOT_USENAMETAGS='false;false' \ - -e STEAM_API_KEY='your steam api key' \ + -e BOT_APPLICATION_VARIABLES='SteamAPIKey,Here;BattleMetricsKey,Here' \ specker/discordplayercountbot ``` 3. Edit values in single quotes and press enter @@ -174,8 +181,8 @@ Container images are configured with help of those variables. | `BOT_STATUSES` | Discord Bots statuses | | `BOT_USENAMETAGS` | "TBD" | | `BOT_PROVIDERTYPES` | Who provides the data for the bot. | -| `STEAM_API_KEY` | Steam Api Key | | `BOT_UPDATE_TIME` | How often bot should refresh | +| `BOT_APPLICATION_VARIABLES` | Application Variables for all bots | To declare Multiple bots in docker separate values in `BOT_NAMES`, `BOT_PUBADDRESSES`, `BOT_PORTS`, `BOT_DISCORD_TOKENS`, `BOT_STATUSES`, `BOT_PROVIDERTYPES`, and `BOT_USENAMETAGS` with `;` @@ -187,6 +194,11 @@ To declare Multiple bots in docker separate values in `BOT_NAMES`, `BOT_PUBADDRE Two bots: `BOT_NAMES='Bot1;Bot2'` +`BOT_APPLICATION_VARIABLES` is a key value pair. The key and value are seperated by commas, and each pair is seperated by a semi-colon. + + Example: + `BOT_APPLICATION_VARIABLES='SteamAPIKey,34124124123rfwer1424124124;BattleMetricsKey,24124124124rwefwrgery5323423412312'` + # Issues Please report any issues to [Issues tab](https://github.com/GravityWolfNotAmused/PlayerCountDiscordBot/issues) or my discord. From 285ffb0be1134b408a22d96af94ac123f7ddd693 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:13:23 -0600 Subject: [PATCH 10/30] Update README.MD --- README.MD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.MD b/README.MD index 02e25d7..5fa294f 100644 --- a/README.MD +++ b/README.MD @@ -80,9 +80,9 @@ This bot works with many different providers to display your game server's playe | :----: | --- | --- | ---- | | Steam | 0 | Limit 1 Milion requests per 24 hours | Steam Query Port | | CFX | 1 | N/A | Game Port | -| Scum | 2 | Uses game | Game Port | -| Minecraft | 3 | NA | Game Port | -| BattleMetrics | 4 | Uses Battle Metrics ID. [ID is the number in this URL](https://www.battlemetrics.com/servers/minecraft/5873087) | Battle Metrics Server ID | +| Scum | 2 | N/A | Game Port | +| Minecraft | 3 | N/A | Game Port | +| BattleMetrics | 4 | Uses Battle Metrics ID. [ID is the number in this URL](https://www.battlemetrics.com/servers/minecraft/5873087) | N/A | #### Address Resolution You may use `localhost` or `hostname` as your server address for the application to automatically resolve the hosts IP. From 1fb42c569fa39fe159f0dde0321775d7eff24be9 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:16:24 -0600 Subject: [PATCH 11/30] Update default values for App tokens, docker comment. --- DiscordPlayerCountBot/Bot/BotConfig.cs | 4 ++-- DiscordPlayerCountBot/docker-compose.yml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DiscordPlayerCountBot/Bot/BotConfig.cs b/DiscordPlayerCountBot/Bot/BotConfig.cs index 85fd43b..9833862 100644 --- a/DiscordPlayerCountBot/Bot/BotConfig.cs +++ b/DiscordPlayerCountBot/Bot/BotConfig.cs @@ -27,8 +27,8 @@ public void CreateDefaults() }); UpdateTime = 30; - ApplicationTokens.Add("SteamAPIKey", ""); - ApplicationTokens.Add("BattleMetricsKey", ""); + ApplicationTokens.Add("SteamAPIKey", "Here"); + ApplicationTokens.Add("BattleMetricsKey", "Here"); } } } diff --git a/DiscordPlayerCountBot/docker-compose.yml b/DiscordPlayerCountBot/docker-compose.yml index ce4db4c..40c8bdf 100644 --- a/DiscordPlayerCountBot/docker-compose.yml +++ b/DiscordPlayerCountBot/docker-compose.yml @@ -16,4 +16,5 @@ services: #Application Variables #These setting apply to the whole application. BOT_UPDATE_TIME: "30" + #Keys and values are seperated by comas and each pair is seperated by a semi-colon. BOT_APPLICATION_VARIABLES: "SteamAPIKey,KeyHere;BattleMetricsKey,KeyHere" \ No newline at end of file From 2134208896a6f01ad2ec058daab5965d94224106 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:33:55 -0600 Subject: [PATCH 12/30] Add Status Code to Steam and CFX responses. --- DiscordPlayerCountBot/Bot/Bot.cs | 1 - DiscordPlayerCountBot/Providers/CFXProvider.cs | 2 +- DiscordPlayerCountBot/Providers/SteamProvider.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/DiscordPlayerCountBot/Bot/Bot.cs b/DiscordPlayerCountBot/Bot/Bot.cs index d2a1efc..44e0a53 100644 --- a/DiscordPlayerCountBot/Bot/Bot.cs +++ b/DiscordPlayerCountBot/Bot/Bot.cs @@ -7,7 +7,6 @@ using log4net; using System; using System.Collections.Generic; -using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; diff --git a/DiscordPlayerCountBot/Providers/CFXProvider.cs b/DiscordPlayerCountBot/Providers/CFXProvider.cs index 951c5a0..c5ad21c 100644 --- a/DiscordPlayerCountBot/Providers/CFXProvider.cs +++ b/DiscordPlayerCountBot/Providers/CFXProvider.cs @@ -57,7 +57,7 @@ public class CFXProvider : ServerInformationProvider if (e is HttpRequestException requestException) { - Logger.Error($"[CFXProvider] - The CFX host has failed to respond."); + Logger.Error($"[CFXProvider] - The CFX host has failed to respond. {requestException.StatusCode}"); return null; } diff --git a/DiscordPlayerCountBot/Providers/SteamProvider.cs b/DiscordPlayerCountBot/Providers/SteamProvider.cs index f2cc09b..00d3276 100644 --- a/DiscordPlayerCountBot/Providers/SteamProvider.cs +++ b/DiscordPlayerCountBot/Providers/SteamProvider.cs @@ -58,7 +58,7 @@ public class SteamProvider : ServerInformationProvider if (e is HttpRequestException requestException) { - Logger.Error($"[SteamProvider] - The Steam has failed to respond."); + Logger.Error($"[SteamProvider] - The Steam has failed to respond. {requestException.StatusCode}"); return null; } From c909b258f4bfd74bf663d874a384133a6a71f2bb Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:38:45 -0600 Subject: [PATCH 13/30] Update DockerConfiguration.cs Debug --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index c1a8803..e3e27fd 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -84,6 +84,9 @@ public async Task, int>> Configure() ProviderType = (int)EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")) }; + var list = providerTypes?.ToList() ?? new(); + list.ForEach(item => Console.WriteLine(item)); + var bot = new Bot(info, applicationTokens); await bot.StartAsync(); bots.Add(bot.Information.Address, bot); From 38ff0c7c3e392013f241285b2b63888cb9b71ded Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:39:17 -0600 Subject: [PATCH 14/30] Update DockerConfiguration.cs --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index e3e27fd..27ad5e6 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -84,13 +84,12 @@ public async Task, int>> Configure() ProviderType = (int)EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")) }; - var list = providerTypes?.ToList() ?? new(); - list.ForEach(item => Console.WriteLine(item)); - var bot = new Bot(info, applicationTokens); await bot.StartAsync(); bots.Add(bot.Information.Address, bot); } + var list = providerTypes?.ToList() ?? new(); + list.ForEach(item => Console.WriteLine(item)); return new Tuple, int>(bots, int.Parse(Environment.GetEnvironmentVariable("BOT_UPDATE_TIME") ?? "30")); } } From 317a8c91752cdfbf895dded3e35a890f47e53aa8 Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:49:46 -0600 Subject: [PATCH 15/30] Additional logging, removal of unneeded cast. --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index 27ad5e6..aea8e77 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -23,7 +23,8 @@ public async Task, int>> Configure() var botTokens = Environment.GetEnvironmentVariable("BOT_DISCORD_TOKENS")?.Split(";"); var botStatuses = Environment.GetEnvironmentVariable("BOT_STATUSES")?.Split(";"); var botTags = Environment.GetEnvironmentVariable("BOT_USENAMETAGS")?.Split(";"); - var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")?.Split(";"); + var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")?.Split(";").ToList() ?? new(); + Logger.Info($"Provider Type Count: {providerTypes.Count}"); var applicationTokens = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")?.Split(";").ToDictionary(data => data.Split(",")[0]) ?? new(); var channelIDs = new List(); @@ -81,7 +82,7 @@ public async Task, int>> Configure() Status = activity, UseNameAsLabel = useNameAsLabel, ChannelID = channelID ?? null, - ProviderType = (int)EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")) + ProviderType = EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")) }; var bot = new Bot(info, applicationTokens); @@ -89,7 +90,7 @@ public async Task, int>> Configure() bots.Add(bot.Information.Address, bot); } var list = providerTypes?.ToList() ?? new(); - list.ForEach(item => Console.WriteLine(item)); + list.ForEach(item => Logger.Info(item)); return new Tuple, int>(bots, int.Parse(Environment.GetEnvironmentVariable("BOT_UPDATE_TIME") ?? "30")); } } From ea6c01f62b67e8a25841cf75522a400297c76d0c Mon Sep 17 00:00:00 2001 From: Larry Date: Mon, 5 Sep 2022 23:53:56 -0600 Subject: [PATCH 16/30] Update DockerConfiguration.cs Change Provider type parse. --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index aea8e77..d73061c 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -23,8 +23,8 @@ public async Task, int>> Configure() var botTokens = Environment.GetEnvironmentVariable("BOT_DISCORD_TOKENS")?.Split(";"); var botStatuses = Environment.GetEnvironmentVariable("BOT_STATUSES")?.Split(";"); var botTags = Environment.GetEnvironmentVariable("BOT_USENAMETAGS")?.Split(";"); - var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")?.Split(";").ToList() ?? new(); - Logger.Info($"Provider Type Count: {providerTypes.Count}"); + var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")!.Split(";"); + Logger.Info($"Provider Type Count: {providerTypes.Length}"); var applicationTokens = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")?.Split(";").ToDictionary(data => data.Split(",")[0]) ?? new(); var channelIDs = new List(); @@ -82,7 +82,7 @@ public async Task, int>> Configure() Status = activity, UseNameAsLabel = useNameAsLabel, ChannelID = channelID ?? null, - ProviderType = EnumHelper.GetDataProvider(int.Parse(providerTypes?[i] ?? "0")) + ProviderType = EnumHelper.GetDataProvider(int.Parse(providerTypes[i])) }; var bot = new Bot(info, applicationTokens); From db5e3f3b8062084981f6a4606b12c51ee57732ac Mon Sep 17 00:00:00 2001 From: Larry Date: Tue, 6 Sep 2022 00:26:49 -0600 Subject: [PATCH 17/30] Simplify exception reset logic to parent, move logging up, remove extra log. --- .../Configuration/DockerConfiguration.cs | 3 +-- .../Base/IServerInformationProvider.cs | 1 + .../Base/ServerInformationProvider.cs | 16 ++++++++++++ .../Providers/BattleMetricsProvider.cs | 25 ++++++------------- .../Providers/CFXProvider.cs | 14 ++--------- .../Providers/MinecraftProvider.cs | 10 ++------ .../Providers/ScumProvider.cs | 11 +------- .../Providers/SteamProvider.cs | 12 ++------- 8 files changed, 33 insertions(+), 59 deletions(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index d73061c..b35c5b1 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -89,8 +89,7 @@ public async Task, int>> Configure() await bot.StartAsync(); bots.Add(bot.Information.Address, bot); } - var list = providerTypes?.ToList() ?? new(); - list.ForEach(item => Logger.Info(item)); + return new Tuple, int>(bots, int.Parse(Environment.GetEnvironmentVariable("BOT_UPDATE_TIME") ?? "30")); } } diff --git a/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs b/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs index a02d638..06075e8 100644 --- a/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs +++ b/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs @@ -10,5 +10,6 @@ public interface IServerInformationProvider bool WasLastExecutionAFailure { get; set; } Exception? LastException { get; set; } Task GetServerInformation(BotInformation information, Dictionary applicationVariables); + void HandleLastException(BotInformation information); } } diff --git a/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs b/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs index 92f39ae..4da5a5f 100644 --- a/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs +++ b/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using log4net; using PlayerCountBot; namespace DiscordPlayerCountBot.Providers.Base @@ -9,7 +10,22 @@ public abstract class ServerInformationProvider : IServerInformationProvider { public bool WasLastExecutionAFailure { get; set; } = false; public Exception? LastException { get; set; } + protected ILog Logger { get; set; } + + public ServerInformationProvider() + { + Logger = LogManager.GetLogger(GetType()); + } public abstract Task GetServerInformation(BotInformation information, Dictionary applicationVariables); + protected void HandleLastException(BotInformation information) + { + if (WasLastExecutionAFailure) + { + Logger.Info($"[{GetType().Name}] - Bot for Address: {information.Address} successfully fetched data after failure."); + LastException = null; + WasLastExecutionAFailure = false; + } + } } } diff --git a/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs b/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs index 0b5dc93..e848bcc 100644 --- a/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs +++ b/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs @@ -5,15 +5,12 @@ using System.Threading.Tasks; using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; -using log4net; using PlayerCountBot; namespace DiscordPlayerCountBot.Providers { public class BattleMetricsProvider : ServerInformationProvider { - private ILog Logger = LogManager.GetLogger(typeof(BattleMetricsProvider)); - public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new BattleMetricsService(); @@ -26,13 +23,7 @@ public class BattleMetricsProvider : ServerInformationProvider if (server == null) throw new ApplicationException("Server cannot be null. Is your server offline?"); - - if (WasLastExecutionAFailure) - { - Logger.Info($"[Battle Metrics Provider] - Bot for Address: {information.Address} successfully fetched data after failure."); - LastException = null; - WasLastExecutionAFailure = false; - } + HandleLastException(information); return new GenericServerInformation() { @@ -53,13 +44,13 @@ public class BattleMetricsProvider : ServerInformationProvider if (e is KeyNotFoundException keyNotFoundException) { - Logger.Error($"[Battle Metrics Provider] - BattleMetricKey is missing from Application variable configuration."); + Logger.Error($"[BattleMetricsProvider] - BattleMetricKey is missing from Application variable configuration."); return null; } if (e is HttpRequestException requestException) { - Logger.Error($"[Battle Metrics Provider] - The BattleMetric host has failed to respond."); + Logger.Error($"[BattleMetricsProvider] - The BattleMetric host has failed to respond."); return null; } @@ -67,28 +58,28 @@ public class BattleMetricsProvider : ServerInformationProvider { if (webException.Status == WebExceptionStatus.Timeout) { - Logger.Error($"[Battle Metrics Provider] - Speaking with BattleMetric has timed out."); + Logger.Error($"[BattleMetricsProvider] - Speaking with BattleMetric has timed out."); return null; } else if (webException.Status == WebExceptionStatus.ConnectFailure) { - Logger.Error($"[Battle Metrics Provider] - Could not connect to BattleMetric."); + Logger.Error($"[BattleMetricsProvider] - Could not connect to BattleMetric."); return null; } else { - Logger.Error($"[Battle Metrics Provider] - There was an error speaking with your BattleMetric server.", e); + Logger.Error($"[BattleMetricsProvider] - There was an error speaking with your BattleMetric server.", e); return null; } } if (e is ApplicationException applicationException) { - Logger.Error($"[Battle Metrics Provider] - {e.Message}"); + Logger.Error($"[BattleMetricsProvider] - {applicationException.Message}"); return null; } - Logger.Error($"[Battle Metrics Provider] - There was an error speaking with BattleMetric.", e); + Logger.Error($"[BattleMetricsProvider] - There was an error speaking with BattleMetric.", e); throw; } } diff --git a/DiscordPlayerCountBot/Providers/CFXProvider.cs b/DiscordPlayerCountBot/Providers/CFXProvider.cs index c5ad21c..76cc788 100644 --- a/DiscordPlayerCountBot/Providers/CFXProvider.cs +++ b/DiscordPlayerCountBot/Providers/CFXProvider.cs @@ -5,17 +5,12 @@ using System.Threading.Tasks; using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; -using log4net; -using log4net.Repository.Hierarchy; using PlayerCountBot; namespace DiscordPlayerCountBot.Providers { - public class CFXProvider : ServerInformationProvider { - private ILog Logger = LogManager.GetLogger(typeof(CFXProvider)); - public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new CFXService(); @@ -32,12 +27,7 @@ public class CFXProvider : ServerInformationProvider if (serverInfo == null) throw new ApplicationException("Server Information cannot be null. Is your server offline?"); - if (WasLastExecutionAFailure) - { - Logger.Info($"[CFXProvider] - Bot for Address: {information.Address} successfully fetched data after failure."); - LastException = null; - WasLastExecutionAFailure = false; - } + HandleLastException(information); return new GenericServerInformation() { @@ -82,7 +72,7 @@ public class CFXProvider : ServerInformationProvider if (e is ApplicationException applicationException) { - Logger.Error($"[CFXProvider] - {e.Message}"); + Logger.Error($"[CFXProvider] - {applicationException.Message}"); return null; } diff --git a/DiscordPlayerCountBot/Providers/MinecraftProvider.cs b/DiscordPlayerCountBot/Providers/MinecraftProvider.cs index cf97713..4b8c051 100644 --- a/DiscordPlayerCountBot/Providers/MinecraftProvider.cs +++ b/DiscordPlayerCountBot/Providers/MinecraftProvider.cs @@ -12,7 +12,6 @@ namespace DiscordPlayerCountBot.Providers { public class MinecraftProvider : ServerInformationProvider { - private ILog Logger = LogManager.GetLogger(typeof(MinecraftProvider)); public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new MinecraftService(); @@ -30,12 +29,7 @@ public class MinecraftProvider : ServerInformationProvider Logger.Warn($"[MinecraftProvider] - The minecraft provider states the server is offline. Server counts may not be correct."); } - if (WasLastExecutionAFailure) - { - Logger.Info($"[MinecraftProvider] - Bot for Address: {information.Address} successfully fetched data after failure."); - LastException = null; - WasLastExecutionAFailure = false; - } + HandleLastException(information); return new() { @@ -81,7 +75,7 @@ public class MinecraftProvider : ServerInformationProvider if (e is ApplicationException applicationException) { - Logger.Error($"[MinecraftProvider] - {e.Message}"); + Logger.Error($"[MinecraftProvider] - {applicationException.Message}"); return null; } diff --git a/DiscordPlayerCountBot/Providers/ScumProvider.cs b/DiscordPlayerCountBot/Providers/ScumProvider.cs index b043ce5..beca125 100644 --- a/DiscordPlayerCountBot/Providers/ScumProvider.cs +++ b/DiscordPlayerCountBot/Providers/ScumProvider.cs @@ -1,10 +1,8 @@ using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; -using log4net; using PlayerCountBot; using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -13,8 +11,6 @@ namespace DiscordPlayerCountBot.Providers { public class ScumProvider : ServerInformationProvider { - private ILog Logger = LogManager.GetLogger(typeof(ScumProvider)); - public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new ScumService(); @@ -34,12 +30,7 @@ public class ScumProvider : ServerInformationProvider if (server == null) throw new ApplicationException("Could not find Server in Scum Provider."); - if (WasLastExecutionAFailure) - { - Logger.Info($"[ScumProvider] - Bot for Address: {information.Address} successfully fetched data after failure."); - LastException = null; - WasLastExecutionAFailure = false; - } + HandleLastException(information); return new() { diff --git a/DiscordPlayerCountBot/Providers/SteamProvider.cs b/DiscordPlayerCountBot/Providers/SteamProvider.cs index 00d3276..3f863e4 100644 --- a/DiscordPlayerCountBot/Providers/SteamProvider.cs +++ b/DiscordPlayerCountBot/Providers/SteamProvider.cs @@ -1,6 +1,5 @@ using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; -using log4net; using PlayerCountBot; using System; using System.Collections.Generic; @@ -12,8 +11,6 @@ namespace DiscordPlayerCountBot.Providers { public class SteamProvider : ServerInformationProvider { - private ILog Logger = LogManager.GetLogger(typeof(SteamProvider)); - public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) { var service = new SteamService(); @@ -26,12 +23,7 @@ public class SteamProvider : ServerInformationProvider if (response == null) throw new ApplicationException($"Server Address: {information.Address} was not found in Steam's directory."); - if (WasLastExecutionAFailure) - { - Logger.Info($"[CFXProvider] - Bot for Address: {information.Address} successfully fetched data after failure."); - LastException = null; - WasLastExecutionAFailure = false; - } + HandleLastException(information); return new() { @@ -83,7 +75,7 @@ public class SteamProvider : ServerInformationProvider if (e is ApplicationException applicationException) { - Logger.Error($"[SteamProvider] - {e.Message}"); + Logger.Error($"[SteamProvider] - {applicationException.Message}"); return null; } From 64d3f6588f0d2d4a0b448f6033e27f7988552ae5 Mon Sep 17 00:00:00 2001 From: Larry Date: Tue, 6 Sep 2022 00:34:19 -0600 Subject: [PATCH 18/30] Fix parse error, and remove handle last exception from interface. --- .../Configuration/DockerConfiguration.cs | 13 ++++++++++++- .../Providers/Base/IServerInformationProvider.cs | 1 - 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index b35c5b1..0e48251 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -26,7 +26,18 @@ public async Task, int>> Configure() var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")!.Split(";"); Logger.Info($"Provider Type Count: {providerTypes.Length}"); - var applicationTokens = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")?.Split(";").ToDictionary(data => data.Split(",")[0]) ?? new(); + var applicationTokensPairs = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")!.Split(";").ToList(); + var applicationTokens = new Dictionary(); + + foreach(var token in applicationTokensPairs) + { + var keyValueSplit = token.Split(','); + var key = keyValueSplit[0]; + var value = keyValueSplit[1]; + + applicationTokens.Add(key, value); + } + var channelIDs = new List(); if (Environment.GetEnvironmentVariables().Contains("BOT_CHANNELIDS")) diff --git a/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs b/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs index 06075e8..a02d638 100644 --- a/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs +++ b/DiscordPlayerCountBot/Providers/Base/IServerInformationProvider.cs @@ -10,6 +10,5 @@ public interface IServerInformationProvider bool WasLastExecutionAFailure { get; set; } Exception? LastException { get; set; } Task GetServerInformation(BotInformation information, Dictionary applicationVariables); - void HandleLastException(BotInformation information); } } From 4d16ae5df5af5c2a34a9ca4eed11dcf03e858c32 Mon Sep 17 00:00:00 2001 From: Larry Date: Tue, 6 Sep 2022 00:51:18 -0600 Subject: [PATCH 19/30] Update DockerConfiguration.cs Remove unneeded log message. --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index 0e48251..ee1d0f7 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -24,7 +24,6 @@ public async Task, int>> Configure() var botStatuses = Environment.GetEnvironmentVariable("BOT_STATUSES")?.Split(";"); var botTags = Environment.GetEnvironmentVariable("BOT_USENAMETAGS")?.Split(";"); var providerTypes = Environment.GetEnvironmentVariable("BOT_PROVIDERTYPES")!.Split(";"); - Logger.Info($"Provider Type Count: {providerTypes.Length}"); var applicationTokensPairs = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")!.Split(";").ToList(); var applicationTokens = new Dictionary(); From e765806ece2b213a21838af76f876d3bb5506e8a Mon Sep 17 00:00:00 2001 From: Larry Date: Tue, 6 Sep 2022 00:52:59 -0600 Subject: [PATCH 20/30] Update DockerConfiguration.cs Linting --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index ee1d0f7..4156923 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -28,7 +28,7 @@ public async Task, int>> Configure() var applicationTokensPairs = Environment.GetEnvironmentVariable("BOT_APPLICATION_VARIABLES")!.Split(";").ToList(); var applicationTokens = new Dictionary(); - foreach(var token in applicationTokensPairs) + foreach (var token in applicationTokensPairs) { var keyValueSplit = token.Split(','); var key = keyValueSplit[0]; From 8e187a9bcd5759871c2defd66ede0438de779eb8 Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:44:41 -0600 Subject: [PATCH 21/30] Create AttributeHelper.cs Makes getting stuff from attributes easier :) --- .../Attributes/AttributeHelper.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 DiscordPlayerCountBot/Attributes/AttributeHelper.cs diff --git a/DiscordPlayerCountBot/Attributes/AttributeHelper.cs b/DiscordPlayerCountBot/Attributes/AttributeHelper.cs new file mode 100644 index 0000000..f3155e2 --- /dev/null +++ b/DiscordPlayerCountBot/Attributes/AttributeHelper.cs @@ -0,0 +1,14 @@ +using System.Linq; + +namespace DiscordPlayerCountBot.Attributes +{ + public static class AttributeHelper + { + public static string GetNameFromAttribute(object obj) + { + var nameAttribute = obj.GetType().GetCustomAttributes(true).Where(attribute => attribute.GetType() == typeof(NameAttribute)).Cast().FirstOrDefault(); + var label = nameAttribute?.Name ?? obj.GetType().Name; + return label; + } + } +} From 849ad75773b18c199a1deccc898dbcf1be52e69a Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:44:59 -0600 Subject: [PATCH 22/30] Update NameAttribute.cs Make name attribute available for classes. --- DiscordPlayerCountBot/Attributes/NameAttribute.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordPlayerCountBot/Attributes/NameAttribute.cs b/DiscordPlayerCountBot/Attributes/NameAttribute.cs index 41e105e..0cc4a6d 100644 --- a/DiscordPlayerCountBot/Attributes/NameAttribute.cs +++ b/DiscordPlayerCountBot/Attributes/NameAttribute.cs @@ -2,7 +2,7 @@ namespace DiscordPlayerCountBot.Attributes { - [AttributeUsage(AttributeTargets.Property)] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)] public class NameAttribute : Attribute { public string Name { get; set; } From 25fbe5758ee2da4e0a82b606253e7007ed13af6d Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:45:59 -0600 Subject: [PATCH 23/30] Update Bot.cs Removed address resolve logic to helper class. Removed discord login to extension method. --- DiscordPlayerCountBot/Bot/Bot.cs | 33 +++----------------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/DiscordPlayerCountBot/Bot/Bot.cs b/DiscordPlayerCountBot/Bot/Bot.cs index 44e0a53..fc4d8b8 100644 --- a/DiscordPlayerCountBot/Bot/Bot.cs +++ b/DiscordPlayerCountBot/Bot/Bot.cs @@ -1,5 +1,6 @@ using Discord; using Discord.WebSocket; +using DiscordPlayerCountBot; using DiscordPlayerCountBot.Enum; using DiscordPlayerCountBot.Http; using DiscordPlayerCountBot.Providers; @@ -51,17 +52,11 @@ public async Task StartAsync() { if (Information.Address.Contains("hostname") || Information.Address.Contains("localhost")) { - string[] splitAddr = Information.Address.Split(":"); - string address = await GetHostAddress(); - string port = splitAddr[1].ToLower(); - Information.Address = address + ":" + port; + Information.Address = await AddressHelper.ResolveAddress(Information.Address); } Logger.Info($"[Bot] - Loaded {Information.Name} at address and port: {Information.Address}, {Information.ProviderType}"); - - await DiscordClient.LoginAsync(TokenType.Bot, Information.Token); - await DiscordClient.SetGameAsync($"Starting: {Information.Address}"); - await DiscordClient.StartAsync(); + await DiscordClient.LoginAndStartAsync(Information.Token, Information.Address); } public async Task StopAsync() @@ -123,27 +118,5 @@ public async Task UpdateAsync() } } } - - public async Task GetHostAddress() - { - string publicIPAddress = string.Empty; - var httpClient = new HttpExecuter(new HttpClient()); - - - try - { - var ipAddress = await httpClient.GET("http://ifconfig.me"); - - if (string.IsNullOrEmpty(ipAddress)) - throw new ApplicationException("IP Address cannot be null. Host failed to resolve address."); - - return ipAddress; - } - catch (WebException ex) - { - Logger.Error($"[Bot] - Error Reaching ifconfig.me: {ex.Status}", ex); - throw ex; - } - } } } From 505bdd577e38351802545d9a26cb59a00d436793 Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:46:20 -0600 Subject: [PATCH 24/30] Update BotInformation.cs Make bot tokens non-nullable --- DiscordPlayerCountBot/Bot/BotInformation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordPlayerCountBot/Bot/BotInformation.cs b/DiscordPlayerCountBot/Bot/BotInformation.cs index 303f1c3..ca98a7a 100644 --- a/DiscordPlayerCountBot/Bot/BotInformation.cs +++ b/DiscordPlayerCountBot/Bot/BotInformation.cs @@ -14,7 +14,7 @@ public class BotInformation public string Address { get; set; } [JsonProperty] - public string? Token { get; set; } + public string Token { get; set; } [JsonProperty] public int Status { get; set; } From 8a62f761fc8b78e4d609e4da35eb2e8db6978ce5 Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:47:10 -0600 Subject: [PATCH 25/30] Remove new call to HttpClient --- DiscordPlayerCountBot/Services/BattleMetricsService.cs | 2 +- DiscordPlayerCountBot/Services/CFXService.cs | 4 ++-- DiscordPlayerCountBot/Services/MinecraftService.cs | 2 +- DiscordPlayerCountBot/Services/ScumService.cs | 2 +- DiscordPlayerCountBot/Services/SteamService.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DiscordPlayerCountBot/Services/BattleMetricsService.cs b/DiscordPlayerCountBot/Services/BattleMetricsService.cs index 8f90020..35980aa 100644 --- a/DiscordPlayerCountBot/Services/BattleMetricsService.cs +++ b/DiscordPlayerCountBot/Services/BattleMetricsService.cs @@ -11,7 +11,7 @@ public class BattleMetricsService : IBattleMetricsService { public async Task GetPlayerInformationAsync(string address, string token) { - using var httpClient = new HttpExecuter(new HttpClient()); + using var httpClient = new HttpExecuter(); var response = await httpClient.GET($"https://api.battlemetrics.com/servers/{address}", authToken: new Tuple("Authorization", token)); return response?.data; diff --git a/DiscordPlayerCountBot/Services/CFXService.cs b/DiscordPlayerCountBot/Services/CFXService.cs index 7c3b4fd..da15709 100644 --- a/DiscordPlayerCountBot/Services/CFXService.cs +++ b/DiscordPlayerCountBot/Services/CFXService.cs @@ -10,13 +10,13 @@ public class CFXService : ICFXService { public async Task?> GetPlayerInformationAsync(string address) { - using var httpClient = new HttpExecuter(new HttpClient()); + using var httpClient = new HttpExecuter(); return await httpClient.GET>($"http://{address}/Players.json"); } public async Task GetServerInformationAsync(string address) { - using var httpClient = new HttpExecuter(new HttpClient()); + using var httpClient = new HttpExecuter(); return await httpClient.GET($"http://{address}/Info.json"); } } diff --git a/DiscordPlayerCountBot/Services/MinecraftService.cs b/DiscordPlayerCountBot/Services/MinecraftService.cs index ff9fadd..79ab7c3 100644 --- a/DiscordPlayerCountBot/Services/MinecraftService.cs +++ b/DiscordPlayerCountBot/Services/MinecraftService.cs @@ -9,7 +9,7 @@ public class MinecraftService : IMinecraftService { public async Task GetMinecraftServerInformationAsync(string address, int port) { - using var httpClient = new HttpExecuter(new HttpClient()); + using var httpClient = new HttpExecuter(); return await httpClient.GET($"https://api.mcsrvstat.us/2/{address}:{port}"); } } diff --git a/DiscordPlayerCountBot/Services/ScumService.cs b/DiscordPlayerCountBot/Services/ScumService.cs index 108e117..a0003d5 100644 --- a/DiscordPlayerCountBot/Services/ScumService.cs +++ b/DiscordPlayerCountBot/Services/ScumService.cs @@ -10,7 +10,7 @@ public class ScumService : IScumService { public async Task GetPlayerInformationAsync(string address, int port) { - using var httpClient = new HttpExecuter(new HttpClient()); + using var httpClient = new HttpExecuter(); var response = await httpClient.GET($"https://api.hellbz.de/scum/api.php", new ScumGetServerInformationQueryParams() { Address = address diff --git a/DiscordPlayerCountBot/Services/SteamService.cs b/DiscordPlayerCountBot/Services/SteamService.cs index 2c5cf65..b172495 100644 --- a/DiscordPlayerCountBot/Services/SteamService.cs +++ b/DiscordPlayerCountBot/Services/SteamService.cs @@ -13,7 +13,7 @@ public class SteamService : ISteamService public async Task GetSteamApiResponse(string address, int port, string token) { - using var httpClient = new HttpExecuter(new HttpClient()); + using var httpClient = new HttpExecuter(); var response = await httpClient.GET("https://api.steampowered.com/IGameServersService/GetServerList/v1/", new SteamGetServerListQueryParams() { Key = token, From cccc112ea48fb063c0a4e678b93e0b2518bbd6da Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:47:18 -0600 Subject: [PATCH 26/30] Create DiscordClient.cs --- DiscordPlayerCountBot/DiscordClient.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 DiscordPlayerCountBot/DiscordClient.cs diff --git a/DiscordPlayerCountBot/DiscordClient.cs b/DiscordPlayerCountBot/DiscordClient.cs new file mode 100644 index 0000000..cf3d4dc --- /dev/null +++ b/DiscordPlayerCountBot/DiscordClient.cs @@ -0,0 +1,16 @@ +using Discord; +using Discord.WebSocket; +using System.Threading.Tasks; + +namespace DiscordPlayerCountBot +{ + public static class DiscordClient + { + public static async Task LoginAndStartAsync(this DiscordSocketClient client, string token, string address) + { + await client.LoginAsync(TokenType.Bot, token); + await client.SetGameAsync($"Starting: {address}"); + await client.StartAsync(); + } + } +} From accd7423e8fb77d9178dec5d28844ea22b78c9b5 Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:47:23 -0600 Subject: [PATCH 27/30] Create AddressHelper.cs --- DiscordPlayerCountBot/Http/AddressHelper.cs | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 DiscordPlayerCountBot/Http/AddressHelper.cs diff --git a/DiscordPlayerCountBot/Http/AddressHelper.cs b/DiscordPlayerCountBot/Http/AddressHelper.cs new file mode 100644 index 0000000..afd51f7 --- /dev/null +++ b/DiscordPlayerCountBot/Http/AddressHelper.cs @@ -0,0 +1,35 @@ +using log4net.Repository.Hierarchy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualBasic; + +namespace DiscordPlayerCountBot.Http +{ + public static class AddressHelper + { + public static async Task GetHostAddress() + { + var publicIPAddress = string.Empty; + var httpClient = new HttpExecuter(); + var ipAddress = await httpClient.GET("http://ifconfig.me"); + + if (string.IsNullOrEmpty(ipAddress)) + throw new ApplicationException("IP Address cannot be null. Host failed to resolve address."); + + return ipAddress; + } + + public static async Task ResolveAddress(string address) + { + var splitAddr = address.Split(":"); + var resolvedAddress = await GetHostAddress(); + var port = splitAddr[1]; + return resolvedAddress + ":" + port; + } + } +} From e5e1031b445dda12f51e83d72a39f13511aae7ae Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:47:47 -0600 Subject: [PATCH 28/30] Update HttpExecuter.cs Move creation of new httpclient to constructor call. --- DiscordPlayerCountBot/Http/HttpExecuter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordPlayerCountBot/Http/HttpExecuter.cs b/DiscordPlayerCountBot/Http/HttpExecuter.cs index 010c5e8..e927863 100644 --- a/DiscordPlayerCountBot/Http/HttpExecuter.cs +++ b/DiscordPlayerCountBot/Http/HttpExecuter.cs @@ -12,9 +12,9 @@ public class HttpExecuter : IHttpExecuter, IDisposable { public readonly HttpClient HttpClient; - public HttpExecuter(HttpClient httpClient) + public HttpExecuter() { - HttpClient = httpClient; + HttpClient = new HttpClient(); } public void Dispose() From 77f9726f4949eb7644410109ead91294e63d9c4c Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 17:49:05 -0600 Subject: [PATCH 29/30] Update Providers Moved label into constructor call. Changed logging messages Create handle exception to have on place for provider exception handling since all services are current http services. --- .../Data/Minecraft/MinecraftServer.cs | 2 +- .../Base/ServerInformationProvider.cs | 63 ++++++++++++++++++- .../Providers/BattleMetricsProvider.cs | 51 ++------------- .../Providers/CFXProvider.cs | 45 ++----------- .../Providers/MinecraftProvider.cs | 55 ++++------------ .../Providers/ScumProvider.cs | 47 ++------------ .../Providers/SteamProvider.cs | 51 ++------------- 7 files changed, 92 insertions(+), 222 deletions(-) diff --git a/DiscordPlayerCountBot/Data/Minecraft/MinecraftServer.cs b/DiscordPlayerCountBot/Data/Minecraft/MinecraftServer.cs index 7ae7346..6cb3e31 100644 --- a/DiscordPlayerCountBot/Data/Minecraft/MinecraftServer.cs +++ b/DiscordPlayerCountBot/Data/Minecraft/MinecraftServer.cs @@ -17,7 +17,7 @@ public class MinecraftServer public MinecraftMotd Motd { get; set; } [JsonProperty("players")] - public MinecraftPlayerInfo Players { get; set; } + public MinecraftPlayerInfo? Players { get; set; } [JsonProperty("version")] public string? Version { get; set; } diff --git a/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs b/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs index 4da5a5f..984659d 100644 --- a/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs +++ b/DiscordPlayerCountBot/Providers/Base/ServerInformationProvider.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.Net.Http; +using System.Net; using System.Threading.Tasks; using log4net; using PlayerCountBot; +using DiscordPlayerCountBot.Attributes; namespace DiscordPlayerCountBot.Providers.Base { @@ -11,10 +14,12 @@ public abstract class ServerInformationProvider : IServerInformationProvider public bool WasLastExecutionAFailure { get; set; } = false; public Exception? LastException { get; set; } protected ILog Logger { get; set; } + public readonly string Label; public ServerInformationProvider() { Logger = LogManager.GetLogger(GetType()); + Label = AttributeHelper.GetNameFromAttribute(this); } public abstract Task GetServerInformation(BotInformation information, Dictionary applicationVariables); @@ -22,10 +27,66 @@ protected void HandleLastException(BotInformation information) { if (WasLastExecutionAFailure) { - Logger.Info($"[{GetType().Name}] - Bot for Address: {information.Address} successfully fetched data after failure."); + + Logger.Info($"[{Label}] - Bot named: {information.Name} at address: {information.Address} successfully fetched data after failure."); LastException = null; WasLastExecutionAFailure = false; } } + + protected void HandleException(Exception e) + { + if (e.Message == LastException?.Message) + return; + + WasLastExecutionAFailure = true; + LastException = e; + + if (e is TaskCanceledException canceledException) + { + Logger.Error($"[{Label}] - Update task was canceled likely because of system timeout."); + return; + } + + if (e is KeyNotFoundException keyNotFoundException) + { + Logger.Error($"[{Label}] - SteamAPIKey is missing from Application variable configuration."); + return; + } + + if (e is HttpRequestException requestException) + { + Logger.Error($"[{Label}] - The {Label} has failed to respond. {requestException.StatusCode}"); + return; + } + + if (e is WebException webException) + { + if (webException.Status == WebExceptionStatus.Timeout) + { + Logger.Error($"[{Label}] - Speaking with {Label} has timed out."); + return; + } + else if (webException.Status == WebExceptionStatus.ConnectFailure) + { + Logger.Error($"[{Label}] - Could not connect to {Label}."); + return; + } + else + { + Logger.Error($"[{Label}] - There was an error speaking with your {Label} server.", e); + return; + } + } + + if (e is ApplicationException applicationException) + { + Logger.Error($"[{Label}] - {applicationException.Message}"); + return; + } + + Logger.Error($"[{Label}] - There was an error speaking with {Label}.", e); + throw e; + } } } diff --git a/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs b/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs index e848bcc..3a74811 100644 --- a/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs +++ b/DiscordPlayerCountBot/Providers/BattleMetricsProvider.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -using System.Net; -using System.Net.Http; using System.Threading.Tasks; +using DiscordPlayerCountBot.Attributes; using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; using PlayerCountBot; namespace DiscordPlayerCountBot.Providers { + [Name("BattleMetrics")] public class BattleMetricsProvider : ServerInformationProvider { public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) @@ -36,51 +36,8 @@ public class BattleMetricsProvider : ServerInformationProvider } catch (Exception e) { - if (e.Message == LastException?.Message) - return null; - - WasLastExecutionAFailure = true; - LastException = e; - - if (e is KeyNotFoundException keyNotFoundException) - { - Logger.Error($"[BattleMetricsProvider] - BattleMetricKey is missing from Application variable configuration."); - return null; - } - - if (e is HttpRequestException requestException) - { - Logger.Error($"[BattleMetricsProvider] - The BattleMetric host has failed to respond."); - return null; - } - - if (e is WebException webException) - { - if (webException.Status == WebExceptionStatus.Timeout) - { - Logger.Error($"[BattleMetricsProvider] - Speaking with BattleMetric has timed out."); - return null; - } - else if (webException.Status == WebExceptionStatus.ConnectFailure) - { - Logger.Error($"[BattleMetricsProvider] - Could not connect to BattleMetric."); - return null; - } - else - { - Logger.Error($"[BattleMetricsProvider] - There was an error speaking with your BattleMetric server.", e); - return null; - } - } - - if (e is ApplicationException applicationException) - { - Logger.Error($"[BattleMetricsProvider] - {applicationException.Message}"); - return null; - } - - Logger.Error($"[BattleMetricsProvider] - There was an error speaking with BattleMetric.", e); - throw; + HandleException(e); + return null; } } } diff --git a/DiscordPlayerCountBot/Providers/CFXProvider.cs b/DiscordPlayerCountBot/Providers/CFXProvider.cs index 76cc788..b9f772b 100644 --- a/DiscordPlayerCountBot/Providers/CFXProvider.cs +++ b/DiscordPlayerCountBot/Providers/CFXProvider.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -using System.Net; -using System.Net.Http; using System.Threading.Tasks; +using DiscordPlayerCountBot.Attributes; using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; using PlayerCountBot; namespace DiscordPlayerCountBot.Providers { + [Name("CFX")] public class CFXProvider : ServerInformationProvider { public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) @@ -39,45 +39,8 @@ public class CFXProvider : ServerInformationProvider } catch (Exception e) { - if (e.Message == LastException?.Message) - return null; - - WasLastExecutionAFailure = true; - LastException = e; - - if (e is HttpRequestException requestException) - { - Logger.Error($"[CFXProvider] - The CFX host has failed to respond. {requestException.StatusCode}"); - return null; - } - - if (e is WebException webException) - { - if (webException.Status == WebExceptionStatus.Timeout) - { - Logger.Error($"[CFXProvider] - Speaking with CFX has timed out."); - return null; - } - else if (webException.Status == WebExceptionStatus.ConnectFailure) - { - Logger.Error($"[CFXProvider] - Could not connect to CFX."); - return null; - } - else - { - Logger.Error($"[CFXProvider] - There was an error speaking with your CFX server.", e); - return null; - } - } - - if (e is ApplicationException applicationException) - { - Logger.Error($"[CFXProvider] - {applicationException.Message}"); - return null; - } - - Logger.Error($"[CFXProvider] - There was an error speaking with CFX.", e); - throw; + HandleException(e); + return null; } } } diff --git a/DiscordPlayerCountBot/Providers/MinecraftProvider.cs b/DiscordPlayerCountBot/Providers/MinecraftProvider.cs index 4b8c051..441ac19 100644 --- a/DiscordPlayerCountBot/Providers/MinecraftProvider.cs +++ b/DiscordPlayerCountBot/Providers/MinecraftProvider.cs @@ -1,15 +1,14 @@ using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; -using log4net; using PlayerCountBot; using System; -using System.Net.Http; -using System.Net; using System.Threading.Tasks; using System.Collections.Generic; +using DiscordPlayerCountBot.Attributes; namespace DiscordPlayerCountBot.Providers { + [Name("Minecraft")] public class MinecraftProvider : ServerInformationProvider { public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) @@ -31,56 +30,24 @@ public class MinecraftProvider : ServerInformationProvider HandleLastException(information); + var playerInformation = response.Players; + + if (playerInformation == null) + throw new ApplicationException("Failed to fetch player information from provider."); + return new() { Address = addressAndPort.Item1, Port = addressAndPort.Item2, - CurrentPlayers = response.Players.Online, - MaxPlayers = response.Players.Max, + CurrentPlayers = response?.Players?.Online ?? 0, + MaxPlayers = response?.Players?.Max ?? 0, PlayersInQueue = 0 }; } catch (Exception e) { - if (e.Message == LastException?.Message) - return null; - - WasLastExecutionAFailure = true; - LastException = e; - - if (e is HttpRequestException requestException) - { - Logger.Error($"[MinecraftProvider] - The Minecraft provider has failed to respond."); - return null; - } - - if (e is WebException webException) - { - if (webException.Status == WebExceptionStatus.Timeout) - { - Logger.Error($"[MinecraftProvider] - Speaking with Minecraft has timed out."); - return null; - } - else if (webException.Status == WebExceptionStatus.ConnectFailure) - { - Logger.Error($"[MinecraftProvider] - Could not connect to Minecraft."); - return null; - } - else - { - Logger.Error($"[MinecraftProvider] - There was an error speaking with your Minecraft server.", e); - return null; - } - } - - if (e is ApplicationException applicationException) - { - Logger.Error($"[MinecraftProvider] - {applicationException.Message}"); - return null; - } - - Logger.Error($"[MinecraftProvider] - There was an error speaking with Minecraft.", e); - throw; + HandleException(e); + return null; } } } diff --git a/DiscordPlayerCountBot/Providers/ScumProvider.cs b/DiscordPlayerCountBot/Providers/ScumProvider.cs index beca125..9d19e66 100644 --- a/DiscordPlayerCountBot/Providers/ScumProvider.cs +++ b/DiscordPlayerCountBot/Providers/ScumProvider.cs @@ -1,14 +1,14 @@ -using DiscordPlayerCountBot.Providers.Base; +using DiscordPlayerCountBot.Attributes; +using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; using PlayerCountBot; using System; using System.Collections.Generic; -using System.Net; -using System.Net.Http; using System.Threading.Tasks; namespace DiscordPlayerCountBot.Providers { + [Name("Scum")] public class ScumProvider : ServerInformationProvider { public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) @@ -43,45 +43,8 @@ public class ScumProvider : ServerInformationProvider } catch (Exception e) { - if (e.Message == LastException?.Message) - return null; - - WasLastExecutionAFailure = true; - LastException = e; - - if (e is HttpRequestException requestException) - { - Logger.Error($"[ScumProvider] - The Scum provider has failed to respond."); - return null; - } - - if (e is WebException webException) - { - if (webException.Status == WebExceptionStatus.Timeout) - { - Logger.Error($"[ScumProvider] - Speaking with the Scum provider has timed out."); - return null; - } - else if (webException.Status == WebExceptionStatus.ConnectFailure) - { - Logger.Error($"[ScumProvider] - Could not connect to Scum provider."); - return null; - } - else - { - Logger.Error($"[ScumProvider] - There was an error speaking with the Scum data provider.", e); - return null; - } - } - - if (e is ApplicationException applicationException) - { - Logger.Error($"[ScumProvider] - {applicationException.Message}"); - return null; - } - - Logger.Error($"[ScumProvider] - There was an error speaking with Scum.", e); - throw; + HandleException(e); + return null; } } } diff --git a/DiscordPlayerCountBot/Providers/SteamProvider.cs b/DiscordPlayerCountBot/Providers/SteamProvider.cs index 3f863e4..64d906b 100644 --- a/DiscordPlayerCountBot/Providers/SteamProvider.cs +++ b/DiscordPlayerCountBot/Providers/SteamProvider.cs @@ -1,4 +1,5 @@ -using DiscordPlayerCountBot.Providers.Base; +using DiscordPlayerCountBot.Attributes; +using DiscordPlayerCountBot.Providers.Base; using DiscordPlayerCountBot.Services; using PlayerCountBot; using System; @@ -9,6 +10,7 @@ namespace DiscordPlayerCountBot.Providers { + [Name("Steam")] public class SteamProvider : ServerInformationProvider { public async override Task GetServerInformation(BotInformation information, Dictionary applicationVariables) @@ -36,51 +38,8 @@ public class SteamProvider : ServerInformationProvider } catch (Exception e) { - if (e.Message == LastException?.Message) - return null; - - WasLastExecutionAFailure = true; - LastException = e; - - if (e is KeyNotFoundException keyNotFoundException) - { - Logger.Error($"[SteamProvider] - SteamAPIKey is missing from Application variable configuration."); - return null; - } - - if (e is HttpRequestException requestException) - { - Logger.Error($"[SteamProvider] - The Steam has failed to respond. {requestException.StatusCode}"); - return null; - } - - if (e is WebException webException) - { - if (webException.Status == WebExceptionStatus.Timeout) - { - Logger.Error($"[SteamProvider] - Speaking with Steam has timed out."); - return null; - } - else if (webException.Status == WebExceptionStatus.ConnectFailure) - { - Logger.Error($"[SteamProvider] - Could not connect to Steam."); - return null; - } - else - { - Logger.Error($"[SteamProvider] - There was an error speaking with your CFX server.", e); - return null; - } - } - - if (e is ApplicationException applicationException) - { - Logger.Error($"[SteamProvider] - {applicationException.Message}"); - return null; - } - - Logger.Error($"[SteamProvider] - There was an error speaking with Steam.", e); - throw; + HandleException(e); + return null; } } } From 5cf8cfac7864ddc0bd3317957d5331f476ee3ffa Mon Sep 17 00:00:00 2001 From: Larry Date: Fri, 9 Sep 2022 18:10:10 -0600 Subject: [PATCH 30/30] Update DockerConfiguration.cs Fix null reference warning. --- DiscordPlayerCountBot/Configuration/DockerConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs index 4156923..eb04598 100644 --- a/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs +++ b/DiscordPlayerCountBot/Configuration/DockerConfiguration.cs @@ -88,7 +88,7 @@ public async Task, int>> Configure() { Name = botNames[i], Address = botAddresses?[i] + ":" + botPorts?[i], - Token = botTokens?[i], + Token = botTokens?[i] ?? throw new ApplicationException("Missing bot token."), Status = activity, UseNameAsLabel = useNameAsLabel, ChannelID = channelID ?? null,