mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-30 17:24:35 +00:00
Rewrite BGR to new OrderedDictionary<T,V> type
This commit is contained in:
@@ -24,7 +24,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -227,7 +226,7 @@ public sealed class BotController : ArchiController {
|
|||||||
|
|
||||||
[EndpointSummary("Adds keys to redeem using BGR to given bot")]
|
[EndpointSummary("Adds keys to redeem using BGR to given bot")]
|
||||||
[HttpPost("{botNames:required}/GamesToRedeemInBackground")]
|
[HttpPost("{botNames:required}/GamesToRedeemInBackground")]
|
||||||
[ProducesResponseType<GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>>((int) HttpStatusCode.OK)]
|
[ProducesResponseType<GenericResponse<IReadOnlyDictionary<string, OrderedDictionary<string, string>>>>((int) HttpStatusCode.OK)]
|
||||||
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.BadRequest)]
|
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.BadRequest)]
|
||||||
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundPost(string botNames, [FromBody] BotGamesToRedeemInBackgroundRequest request) {
|
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundPost(string botNames, [FromBody] BotGamesToRedeemInBackgroundRequest request) {
|
||||||
ArgumentException.ThrowIfNullOrEmpty(botNames);
|
ArgumentException.ThrowIfNullOrEmpty(botNames);
|
||||||
@@ -243,7 +242,7 @@ public sealed class BotController : ArchiController {
|
|||||||
return BadRequest(new GenericResponse(false, Strings.FormatBotNotFound(botNames)));
|
return BadRequest(new GenericResponse(false, Strings.FormatBotNotFound(botNames)));
|
||||||
}
|
}
|
||||||
|
|
||||||
IOrderedDictionary validGamesToRedeemInBackground = Bot.ValidateGamesToRedeemInBackground(request.GamesToRedeemInBackground);
|
OrderedDictionary<string, string> validGamesToRedeemInBackground = Bot.ValidateGamesToRedeemInBackground(request.GamesToRedeemInBackground);
|
||||||
|
|
||||||
if (validGamesToRedeemInBackground.Count == 0) {
|
if (validGamesToRedeemInBackground.Count == 0) {
|
||||||
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsEmpty(nameof(validGamesToRedeemInBackground))));
|
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsEmpty(nameof(validGamesToRedeemInBackground))));
|
||||||
@@ -251,13 +250,13 @@ public sealed class BotController : ArchiController {
|
|||||||
|
|
||||||
await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.AddGamesToRedeemInBackground(validGamesToRedeemInBackground)))).ConfigureAwait(false);
|
await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.AddGamesToRedeemInBackground(validGamesToRedeemInBackground)))).ConfigureAwait(false);
|
||||||
|
|
||||||
Dictionary<string, IOrderedDictionary> result = new(bots.Count, Bot.BotsComparer);
|
Dictionary<string, OrderedDictionary<string, string>> result = new(bots.Count, Bot.BotsComparer);
|
||||||
|
|
||||||
foreach (Bot bot in bots) {
|
foreach (Bot bot in bots) {
|
||||||
result[bot.BotName] = validGamesToRedeemInBackground;
|
result[bot.BotName] = validGamesToRedeemInBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(result));
|
return Ok(new GenericResponse<IReadOnlyDictionary<string, OrderedDictionary<string, string>>>(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
[EndpointSummary("Provides input value to given bot for next usage")]
|
[EndpointSummary("Provides input value to given bot for next usage")]
|
||||||
|
|||||||
@@ -21,7 +21,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System.Collections.Specialized;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
@@ -35,7 +36,7 @@ public sealed class BotGamesToRedeemInBackgroundRequest {
|
|||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
[JsonRequired]
|
[JsonRequired]
|
||||||
[Required]
|
[Required]
|
||||||
public OrderedDictionary GamesToRedeemInBackground { get; private init; } = new();
|
public OrderedDictionary<string, string> GamesToRedeemInBackground { get; private init; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
private BotGamesToRedeemInBackgroundRequest() { }
|
private BotGamesToRedeemInBackgroundRequest() { }
|
||||||
|
|||||||
@@ -22,12 +22,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Frozen;
|
using System.Collections.Frozen;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
@@ -1020,7 +1018,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddGamesToRedeemInBackground(IOrderedDictionary gamesToRedeemInBackground) {
|
internal void AddGamesToRedeemInBackground(IReadOnlyDictionary<string, string> gamesToRedeemInBackground) {
|
||||||
if ((gamesToRedeemInBackground == null) || (gamesToRedeemInBackground.Count == 0)) {
|
if ((gamesToRedeemInBackground == null) || (gamesToRedeemInBackground.Count == 0)) {
|
||||||
throw new ArgumentNullException(nameof(gamesToRedeemInBackground));
|
throw new ArgumentNullException(nameof(gamesToRedeemInBackground));
|
||||||
}
|
}
|
||||||
@@ -1461,7 +1459,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OrderedDictionary gamesToRedeemInBackground = new();
|
OrderedDictionary<string, string> gamesToRedeemInBackground = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
using (StreamReader reader = new(filePath)) {
|
using (StreamReader reader = new(filePath)) {
|
||||||
while (await reader.ReadLineAsync().ConfigureAwait(false) is { } line) {
|
while (await reader.ReadLineAsync().ConfigureAwait(false) is { } line) {
|
||||||
@@ -1489,7 +1487,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gamesToRedeemInBackground.Count > 0) {
|
if (gamesToRedeemInBackground.Count > 0) {
|
||||||
IOrderedDictionary validGamesToRedeemInBackground = ValidateGamesToRedeemInBackground(gamesToRedeemInBackground);
|
OrderedDictionary<string, string> validGamesToRedeemInBackground = ValidateGamesToRedeemInBackground(gamesToRedeemInBackground);
|
||||||
|
|
||||||
if (validGamesToRedeemInBackground.Count > 0) {
|
if (validGamesToRedeemInBackground.Count > 0) {
|
||||||
AddGamesToRedeemInBackground(validGamesToRedeemInBackground);
|
AddGamesToRedeemInBackground(validGamesToRedeemInBackground);
|
||||||
@@ -2009,18 +2007,22 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IOrderedDictionary ValidateGamesToRedeemInBackground(IOrderedDictionary gamesToRedeemInBackground) {
|
internal static OrderedDictionary<string, string> ValidateGamesToRedeemInBackground(IReadOnlyDictionary<string, string> gamesToRedeemInBackground) {
|
||||||
if ((gamesToRedeemInBackground == null) || (gamesToRedeemInBackground.Count == 0)) {
|
if ((gamesToRedeemInBackground == null) || (gamesToRedeemInBackground.Count == 0)) {
|
||||||
throw new ArgumentNullException(nameof(gamesToRedeemInBackground));
|
throw new ArgumentNullException(nameof(gamesToRedeemInBackground));
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<object> invalidKeys = gamesToRedeemInBackground.Cast<DictionaryEntry>().Where(static game => !BotDatabase.IsValidGameToRedeemInBackground(game)).Select(static game => game.Key).ToHashSet();
|
OrderedDictionary<string, string> result = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
foreach (object invalidKey in invalidKeys) {
|
foreach ((string key, string name) in gamesToRedeemInBackground) {
|
||||||
gamesToRedeemInBackground.Remove(invalidKey);
|
if (!BotDatabase.IsValidGameToRedeemInBackground(key, name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[key] = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return gamesToRedeemInBackground;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Connect() {
|
private async Task Connect() {
|
||||||
|
|||||||
@@ -22,8 +22,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -192,7 +191,7 @@ public sealed class BotDatabase : GenericDatabase {
|
|||||||
|
|
||||||
[JsonDisallowNull]
|
[JsonDisallowNull]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
private OrderedDictionary GamesToRedeemInBackground { get; init; } = new();
|
private OrderedDictionary<string, string> GamesToRedeemInBackground { get; init; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
private BotDatabase(string filePath) : this() {
|
private BotDatabase(string filePath) : this() {
|
||||||
ArgumentException.ThrowIfNullOrEmpty(filePath);
|
ArgumentException.ThrowIfNullOrEmpty(filePath);
|
||||||
@@ -303,18 +302,18 @@ public sealed class BotDatabase : GenericDatabase {
|
|||||||
|
|
||||||
protected override Task Save() => Save(this);
|
protected override Task Save() => Save(this);
|
||||||
|
|
||||||
internal void AddGamesToRedeemInBackground(IOrderedDictionary games) {
|
internal void AddGamesToRedeemInBackground(IReadOnlyDictionary<string, string> games) {
|
||||||
if ((games == null) || (games.Count == 0)) {
|
if ((games == null) || (games.Count == 0)) {
|
||||||
throw new ArgumentNullException(nameof(games));
|
throw new ArgumentNullException(nameof(games));
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (GamesToRedeemInBackground) {
|
lock (GamesToRedeemInBackground) {
|
||||||
foreach (DictionaryEntry game in games) {
|
foreach ((string key, string name) in games) {
|
||||||
if (!IsValidGameToRedeemInBackground(game)) {
|
if (!IsValidGameToRedeemInBackground(key, name)) {
|
||||||
throw new InvalidOperationException(nameof(game));
|
throw new InvalidOperationException(nameof(IsValidGameToRedeemInBackground));
|
||||||
}
|
}
|
||||||
|
|
||||||
GamesToRedeemInBackground[game.Key] = game.Value;
|
GamesToRedeemInBackground[key] = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,33 +380,15 @@ public sealed class BotDatabase : GenericDatabase {
|
|||||||
|
|
||||||
internal (string? Key, string? Name) GetGameToRedeemInBackground() {
|
internal (string? Key, string? Name) GetGameToRedeemInBackground() {
|
||||||
lock (GamesToRedeemInBackground) {
|
lock (GamesToRedeemInBackground) {
|
||||||
foreach (DictionaryEntry game in GamesToRedeemInBackground) {
|
foreach ((string key, string name) in GamesToRedeemInBackground) {
|
||||||
return game.Value switch {
|
return (key, name);
|
||||||
string name => (game.Key as string, name),
|
|
||||||
JsonElement { ValueKind: JsonValueKind.String } jsonElement => (game.Key as string, jsonElement.GetString()),
|
|
||||||
_ => throw new InvalidOperationException(nameof(game.Value))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (null, null);
|
return (null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsValidGameToRedeemInBackground(DictionaryEntry game) {
|
internal static bool IsValidGameToRedeemInBackground(string key, string name) => !string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(name) && Utilities.IsValidCdKey(key);
|
||||||
string? key = game.Key as string;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(key) || !Utilities.IsValidCdKey(key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (game.Value) {
|
|
||||||
case string name when !string.IsNullOrEmpty(name):
|
|
||||||
case JsonElement { ValueKind: JsonValueKind.String } jsonElement when !string.IsNullOrEmpty(jsonElement.GetString()):
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PerformMaintenance() {
|
internal void PerformMaintenance() {
|
||||||
DateTime now = DateTime.UtcNow;
|
DateTime now = DateTime.UtcNow;
|
||||||
@@ -421,17 +402,15 @@ public sealed class BotDatabase : GenericDatabase {
|
|||||||
ArgumentException.ThrowIfNullOrEmpty(key);
|
ArgumentException.ThrowIfNullOrEmpty(key);
|
||||||
|
|
||||||
lock (GamesToRedeemInBackground) {
|
lock (GamesToRedeemInBackground) {
|
||||||
if (!GamesToRedeemInBackground.Contains(key)) {
|
if (!GamesToRedeemInBackground.Remove(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GamesToRedeemInBackground.Remove(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Utilities.InBackground(Save);
|
Utilities.InBackground(Save);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (bool Valid, string? ErrorMessage) CheckValidation() => GamesToRedeemInBackground.Cast<DictionaryEntry>().Any(static game => !IsValidGameToRedeemInBackground(game)) ? (false, Strings.FormatErrorConfigPropertyInvalid(nameof(GamesToRedeemInBackground), string.Join("", GamesToRedeemInBackground))) : (true, null);
|
private (bool Valid, string? ErrorMessage) CheckValidation() => GamesToRedeemInBackground.Any(static entry => !IsValidGameToRedeemInBackground(entry.Key, entry.Value)) ? (false, Strings.FormatErrorConfigPropertyInvalid(nameof(GamesToRedeemInBackground), string.Join("", GamesToRedeemInBackground))) : (true, null);
|
||||||
|
|
||||||
private async void OnObjectModified(object? sender, EventArgs e) {
|
private async void OnObjectModified(object? sender, EventArgs e) {
|
||||||
if (string.IsNullOrEmpty(FilePath)) {
|
if (string.IsNullOrEmpty(FilePath)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user