mirror of
https://github.com/JustArchiNET/ArchiSteamFarm
synced 2024-11-10 07:04:27 +00:00
* Good start * Misc * Make ApiAuthenticationMiddleware use new json * Remove first newtonsoft dependency * Pull latest ASFB json enhancements * Start reimplementing newtonsoft! * One thing at a time * Keep doing all kind of breaking changes which need to be tested later * Add back ShouldSerialize() support * Misc * Eradicate remaining parts of newtonsoft * WIP * Workaround STJ stupidity in regards to derived types STJ can't serialize derived type properties by default, so we'll use another approach in our serializable file function * Make CI happy * Bunch of further fixes * Fix AddFreeLicense() after rewrite * Add full support for JsonDisallowNullAttribute * Optimize our json utilities even further * Misc * Add support for fields in disallow null * Misc optimization * Fix deserialization of GlobalCache in STD * Fix non-public [JsonExtensionData] * Fix IM missing method exception, correct db storage helpers * Fix saving into generic databases Thanks STJ * Make Save() function abstract to force inheritors to implement it properly * Correct ShouldSerializeAdditionalProperties to be a method * Misc cleanup * Code review * Allow JSON comments in configs, among other * Allow trailing commas in configs Users very often add them accidentally, no reason to throw on them * Fix confirmation ID Probably needs further fixes, will need to check later * Correct confirmations deserialization * Use JsonNumberHandling * Misc * Misc * [JsonDisallowNull] corrections * Forbid [JsonDisallowNull] on non-nullable structs * Not really but okay * Add and use ToJson() helpers * Misc * Misc
This commit is contained in:
parent
3968130e15
commit
6b0bf0f9c1
114 changed files with 1714 additions and 1212 deletions
|
@ -6,7 +6,6 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -21,16 +21,17 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
||||
|
@ -45,31 +46,35 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
|||
internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection, IBotFriendRequest, IBotMessage, IBotModules, IBotTradeOffer {
|
||||
// This is used for identification purposes, typically you want to use a friendly name of your plugin here, such as the name of your main class
|
||||
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public string Name => nameof(ExamplePlugin);
|
||||
|
||||
// This will be displayed to the user and written in the log file, typically you should point it to the version of your library, but alternatively you can do some more advanced logic if you'd like to
|
||||
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public Version Version => typeof(ExamplePlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
// Plugins can expose custom properties for our GET /Api/Plugins API call, simply annotate them with [JsonProperty] (or keep public)
|
||||
[JsonProperty]
|
||||
public bool CustomIsEnabledField { get; private set; } = true;
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public bool CustomIsEnabledField { get; private init; } = true;
|
||||
|
||||
// This method, apart from being called before any bot initialization takes place, allows you to read custom global config properties that are not recognized by ASF
|
||||
// Thanks to that, you can extend default ASF config with your own stuff, then parse it here in order to customize your plugin during runtime
|
||||
// Keep in mind that, as noted in the interface, additionalConfigProperties can be null if no custom, unrecognized properties are found by ASF, you should handle that case appropriately
|
||||
// In addition to that, this method also guarantees that all plugins were already OnLoaded(), which allows cross-plugins-communication to be possible
|
||||
public Task OnASFInit(IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null) {
|
||||
public Task OnASFInit(IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null) {
|
||||
if (additionalConfigProperties == null) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
foreach ((string configProperty, JToken configValue) in additionalConfigProperties) {
|
||||
foreach ((string configProperty, JsonElement configValue) in additionalConfigProperties) {
|
||||
// It's a good idea to prefix your custom properties with the name of your plugin, so there will be no possible conflict of ASF or other plugins using the same name, neither now or in the future
|
||||
switch (configProperty) {
|
||||
case $"{nameof(ExamplePlugin)}TestProperty" when configValue.Type == JTokenType.Boolean:
|
||||
bool exampleBooleanValue = configValue.Value<bool>();
|
||||
ASF.ArchiLogger.LogGenericInfo($"{nameof(ExamplePlugin)}TestProperty boolean property has been found with a value of: {exampleBooleanValue}");
|
||||
case $"{nameof(ExamplePlugin)}TestProperty" when configValue.ValueKind == JsonValueKind.True:
|
||||
ASF.ArchiLogger.LogGenericInfo($"{nameof(ExamplePlugin)}TestProperty boolean property has been found with a value of true");
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -135,7 +140,7 @@ internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection,
|
|||
// Keep in mind that, as noted in the interface, additionalConfigProperties can be null if no custom, unrecognized properties are found by ASF, you should handle that case appropriately
|
||||
// Also keep in mind that this function can be called multiple times, e.g. when user edits their bot configs during runtime
|
||||
// Take a look at OnASFInit() for example parsing code
|
||||
public async Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null) {
|
||||
public async Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null) {
|
||||
// For example, we'll ensure that every bot starts paused regardless of Paused property, in order to do this, we'll just call Pause here in InitModules()
|
||||
// Thanks to the fact that this method is called with each bot config reload, we'll ensure that our bot stays paused even if it'd get unpaused otherwise
|
||||
bot.ArchiLogger.LogGenericInfo("Pausing this bot as asked from the plugin");
|
||||
|
|
|
@ -21,15 +21,17 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during json deserialization
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class MeowResponse {
|
||||
[JsonProperty("url", Required = Required.Always)]
|
||||
internal readonly Uri URL = null!;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("url")]
|
||||
[JsonRequired]
|
||||
internal Uri URL { get; private init; } = null!;
|
||||
|
||||
[JsonConstructor]
|
||||
private MeowResponse() { }
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
using System.Runtime;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
|
@ -38,8 +40,12 @@ internal sealed class PeriodicGCPlugin : IPlugin {
|
|||
private static readonly object LockObject = new();
|
||||
private static readonly Timer PeriodicGCTimer = new(PerformGC);
|
||||
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public string Name => nameof(PeriodicGCPlugin);
|
||||
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public Version Version => typeof(PeriodicGCPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
public Task OnLoaded() {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
<PackageReference Include="AngleSharp.XPath" IncludeAssets="compile" />
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam.Data;
|
||||
|
||||
public sealed class SignInWithSteamRequest {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public Uri RedirectURL { get; private set; } = null!;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
public Uri RedirectURL { get; private init; } = null!;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,14 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam.Data;
|
||||
|
||||
public sealed class SignInWithSteamResponse {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public Uri ReturnURL { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
public Uri ReturnURL { get; private init; }
|
||||
|
||||
internal SignInWithSteamResponse(Uri returnURL) {
|
||||
ArgumentNullException.ThrowIfNull(returnURL);
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
|
@ -31,8 +33,12 @@ namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam;
|
|||
[Export(typeof(IPlugin))]
|
||||
[UsedImplicitly]
|
||||
internal sealed class SignInWithSteamPlugin : IPlugin {
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public string Name => nameof(SignInWithSteamPlugin);
|
||||
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public Version Version => typeof(SignInWithSteamPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
public Task OnLoaded() {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
|
|
|
@ -22,20 +22,22 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Collections;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
||||
|
||||
internal sealed class BotCache : SerializableFile {
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly ConcurrentList<AssetForListing> LastAnnouncedAssetsForListing = [];
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
internal ConcurrentList<AssetForListing> LastAnnouncedAssetsForListing { get; private init; } = [];
|
||||
|
||||
internal string? LastAnnouncedTradeToken {
|
||||
get => BackingLastAnnouncedTradeToken;
|
||||
|
@ -76,14 +78,14 @@ internal sealed class BotCache : SerializableFile {
|
|||
}
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
private string? BackingLastAnnouncedTradeToken;
|
||||
[JsonInclude]
|
||||
private string? BackingLastAnnouncedTradeToken { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
private string? BackingLastInventoryChecksumBeforeDeduplication;
|
||||
[JsonInclude]
|
||||
private string? BackingLastInventoryChecksumBeforeDeduplication { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
private DateTime? BackingLastRequestAt;
|
||||
[JsonInclude]
|
||||
private DateTime? BackingLastRequestAt { get; set; }
|
||||
|
||||
private BotCache(string filePath) : this() {
|
||||
ArgumentException.ThrowIfNullOrEmpty(filePath);
|
||||
|
@ -116,6 +118,8 @@ internal sealed class BotCache : SerializableFile {
|
|||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override Task Save() => Save(this);
|
||||
|
||||
internal static async Task<BotCache> CreateOrLoad(string filePath) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(filePath);
|
||||
|
||||
|
@ -134,7 +138,7 @@ internal sealed class BotCache : SerializableFile {
|
|||
return new BotCache(filePath);
|
||||
}
|
||||
|
||||
botCache = JsonConvert.DeserializeObject<BotCache>(json);
|
||||
botCache = json.ToJsonObject<BotCache>();
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
|
||||
|
|
|
@ -22,19 +22,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal sealed class AnnouncementDiffRequest : AnnouncementRequest {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly ImmutableHashSet<AssetForListing> InventoryRemoved;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private ImmutableHashSet<AssetForListing> InventoryRemoved { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly string PreviousInventoryChecksum;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private string PreviousInventoryChecksum { get; init; }
|
||||
|
||||
internal AnnouncementDiffRequest(Guid guid, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<Asset.EType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string tradeToken, IReadOnlyCollection<AssetForListing> inventoryRemoved, string previousInventoryChecksum, string? nickname = null, string? avatarHash = null) : base(guid, steamID, inventory, inventoryChecksum, matchableTypes, totalInventoryCount, matchEverything, maxTradeHoldDuration, tradeToken, nickname, avatarHash) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
|
|
@ -22,47 +22,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal class AnnouncementRequest {
|
||||
[JsonProperty]
|
||||
private readonly string? AvatarHash;
|
||||
[JsonInclude]
|
||||
private string? AvatarHash { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly Guid Guid;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private Guid Guid { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly ImmutableHashSet<AssetForListing> Inventory;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private ImmutableHashSet<AssetForListing> Inventory { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly string InventoryChecksum;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private string InventoryChecksum { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly ImmutableHashSet<Asset.EType> MatchableTypes;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private ImmutableHashSet<Asset.EType> MatchableTypes { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly bool MatchEverything;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private bool MatchEverything { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly byte MaxTradeHoldDuration;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private byte MaxTradeHoldDuration { get; init; }
|
||||
|
||||
[JsonProperty]
|
||||
private readonly string? Nickname;
|
||||
[JsonInclude]
|
||||
private string? Nickname { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly ulong SteamID;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private ulong SteamID { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly uint TotalInventoryCount;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private uint TotalInventoryCount { get; init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
private readonly string TradeToken;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private string TradeToken { get; init; }
|
||||
|
||||
internal AnnouncementRequest(Guid guid, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<Asset.EType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string tradeToken, string? nickname = null, string? avatarHash = null) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
|
|
@ -20,19 +20,23 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal sealed class AssetForListing : AssetInInventory {
|
||||
[JsonProperty("i", Required = Required.Always)]
|
||||
internal readonly uint Index;
|
||||
internal string BackendHashCode => $"{Index}-{PreviousAssetID}-{AssetID}-{ClassID}-{Rarity}-{RealAppID}-{Tradable}-{Type}-{Amount}";
|
||||
|
||||
[JsonProperty("l", Required = Required.Always)]
|
||||
internal readonly ulong PreviousAssetID;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("i")]
|
||||
[JsonRequired]
|
||||
internal uint Index { get; private init; }
|
||||
|
||||
internal string BackendHashCode => Index + "-" + PreviousAssetID + "-" + AssetID + "-" + ClassID + "-" + Rarity + "-" + RealAppID + "-" + Tradable + "-" + Type + "-" + Amount;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("l")]
|
||||
[JsonRequired]
|
||||
internal ulong PreviousAssetID { get; private init; }
|
||||
|
||||
internal AssetForListing(Asset asset, uint index, ulong previousAssetID) : base(asset) {
|
||||
ArgumentNullException.ThrowIfNull(asset);
|
||||
|
|
|
@ -20,30 +20,42 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal class AssetForMatching {
|
||||
[JsonProperty("c", Required = Required.Always)]
|
||||
internal readonly ulong ClassID;
|
||||
|
||||
[JsonProperty("r", Required = Required.Always)]
|
||||
internal readonly Asset.ERarity Rarity;
|
||||
|
||||
[JsonProperty("e", Required = Required.Always)]
|
||||
internal readonly uint RealAppID;
|
||||
|
||||
[JsonProperty("t", Required = Required.Always)]
|
||||
internal readonly bool Tradable;
|
||||
|
||||
[JsonProperty("p", Required = Required.Always)]
|
||||
internal readonly Asset.EType Type;
|
||||
|
||||
[JsonProperty("a", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("a")]
|
||||
[JsonRequired]
|
||||
internal uint Amount { get; set; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("c")]
|
||||
[JsonRequired]
|
||||
internal ulong ClassID { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("r")]
|
||||
[JsonRequired]
|
||||
internal Asset.ERarity Rarity { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("e")]
|
||||
[JsonRequired]
|
||||
internal uint RealAppID { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("t")]
|
||||
[JsonRequired]
|
||||
internal bool Tradable { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("p")]
|
||||
[JsonRequired]
|
||||
internal Asset.EType Type { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
protected AssetForMatching() { }
|
||||
|
||||
|
|
|
@ -20,14 +20,16 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal class AssetInInventory : AssetForMatching {
|
||||
[JsonProperty("d", Required = Required.Always)]
|
||||
internal readonly ulong AssetID;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("d")]
|
||||
[JsonRequired]
|
||||
internal ulong AssetID { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
protected AssetInInventory() { }
|
||||
|
|
|
@ -21,22 +21,20 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during json deserialization
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class BackgroundTaskResponse {
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly bool Finished;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal bool Finished { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly Guid RequestID;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal Guid RequestID { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private BackgroundTaskResponse() { }
|
||||
|
|
|
@ -20,17 +20,19 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal sealed class HeartBeatRequest {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly Guid Guid;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal Guid Guid { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ulong SteamID;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
internal HeartBeatRequest(Guid guid, ulong steamID) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
|
|
@ -23,24 +23,28 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal sealed class InventoriesRequest {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly Guid Guid;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal Guid Guid { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<AssetForMatching> Inventory;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<AssetForMatching> Inventory { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<Asset.EType> MatchableTypes;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Asset.EType> MatchableTypes { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ulong SteamID;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
internal InventoriesRequest(Guid guid, ulong steamID, IReadOnlyCollection<Asset> inventory, IReadOnlyCollection<Asset.EType> matchableTypes) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
|
|
@ -21,52 +21,48 @@
|
|||
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during json deserialization
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class ListedUser {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<AssetInInventory> Assets = ImmutableHashSet<AssetInInventory>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<AssetInInventory> Assets { get; private init; } = ImmutableHashSet<AssetInInventory>.Empty;
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<Asset.EType> MatchableTypes = ImmutableHashSet<Asset.EType>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Asset.EType> MatchableTypes { get; private init; } = ImmutableHashSet<Asset.EType>.Empty;
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly bool MatchEverything;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal bool MatchEverything { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly byte MaxTradeHoldDuration;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal byte MaxTradeHoldDuration { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.AllowNull)]
|
||||
internal readonly string? Nickname;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
internal string? Nickname { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ulong SteamID;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly uint TotalGamesCount;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal uint TotalGamesCount { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly uint TotalInventoryCount;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal uint TotalInventoryCount { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly string TradeToken = "";
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal string TradeToken { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private ListedUser() { }
|
||||
|
|
|
@ -20,33 +20,33 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during json deserialization
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class SetPart {
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty("c", Required = Required.Always)]
|
||||
internal readonly ulong ClassID;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("c")]
|
||||
[JsonRequired]
|
||||
internal ulong ClassID { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty("r", Required = Required.Always)]
|
||||
internal readonly Asset.ERarity Rarity;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("r")]
|
||||
[JsonRequired]
|
||||
internal Asset.ERarity Rarity { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty("e", Required = Required.Always)]
|
||||
internal readonly uint RealAppID;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("e")]
|
||||
[JsonRequired]
|
||||
internal uint RealAppID { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty("p", Required = Required.Always)]
|
||||
internal readonly Asset.EType Type;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("p")]
|
||||
[JsonRequired]
|
||||
internal Asset.EType Type { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private SetPart() { }
|
||||
|
|
|
@ -22,24 +22,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
|
||||
internal sealed class SetPartsRequest {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly Guid Guid;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal Guid Guid { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<Asset.EType> MatchableTypes;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Asset.EType> MatchableTypes { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> RealAppIDs;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> RealAppIDs { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ulong SteamID;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
internal SetPartsRequest(Guid guid, ulong steamID, IReadOnlyCollection<Asset.EType> matchableTypes, IReadOnlyCollection<uint> realAppIDs) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
|
|
@ -23,8 +23,11 @@ using System;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization;
|
||||
|
@ -33,8 +36,6 @@ using ArchiSteamFarm.Plugins.Interfaces;
|
|||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
using ArchiSteamFarm.Steam.Integration.Callbacks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
||||
|
@ -43,10 +44,12 @@ namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
|||
internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, IBotIdentity, IBotModules, IBotTradeOfferResults, IBotUserNotifications {
|
||||
internal static readonly ConcurrentDictionary<Bot, RemoteCommunication> RemoteCommunications = new();
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override string Name => nameof(ItemsMatcherPlugin);
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override Version Version => typeof(ItemsMatcherPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
public async Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
|
||||
|
@ -83,7 +86,7 @@ internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, I
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null) {
|
||||
public async Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
|
||||
if (RemoteCommunications.TryRemove(bot, out RemoteCommunication? remoteCommunication)) {
|
||||
|
|
|
@ -28,6 +28,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
|
@ -43,7 +44,6 @@ using ArchiSteamFarm.Steam.Storage;
|
|||
using ArchiSteamFarm.Storage;
|
||||
using ArchiSteamFarm.Web;
|
||||
using ArchiSteamFarm.Web.Responses;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
|
||||
|
@ -1190,11 +1190,19 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
|||
// Cancel previous trade offers sent and deprioritize SteamIDs that didn't answer us in this round
|
||||
HashSet<ulong>? matchActivelyTradeOfferIDs = null;
|
||||
|
||||
JToken? matchActivelyTradeOfferIDsToken = Bot.BotDatabase.LoadFromJsonStorage(MatchActivelyTradeOfferIDsStorageKey);
|
||||
JsonElement matchActivelyTradeOfferIDsToken = Bot.BotDatabase.LoadFromJsonStorage(MatchActivelyTradeOfferIDsStorageKey);
|
||||
|
||||
if (matchActivelyTradeOfferIDsToken != null) {
|
||||
if (matchActivelyTradeOfferIDsToken.ValueKind == JsonValueKind.Array) {
|
||||
try {
|
||||
matchActivelyTradeOfferIDs = matchActivelyTradeOfferIDsToken.ToObject<HashSet<ulong>>();
|
||||
matchActivelyTradeOfferIDs = new HashSet<ulong>(matchActivelyTradeOfferIDsToken.GetArrayLength());
|
||||
|
||||
foreach (JsonElement tradeIDElement in matchActivelyTradeOfferIDsToken.EnumerateArray()) {
|
||||
if (!tradeIDElement.TryGetUInt64(out ulong tradeID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
matchActivelyTradeOfferIDs.Add(tradeID);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
}
|
||||
|
@ -1223,7 +1231,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
|||
matchActivelyTradeOfferIDs = activeTradeOfferIDs;
|
||||
|
||||
if (matchActivelyTradeOfferIDs.Count > 0) {
|
||||
Bot.BotDatabase.SaveToJsonStorage(MatchActivelyTradeOfferIDsStorageKey, JToken.FromObject(matchActivelyTradeOfferIDs));
|
||||
Bot.BotDatabase.SaveToJsonStorage(MatchActivelyTradeOfferIDsStorageKey, matchActivelyTradeOfferIDs);
|
||||
} else {
|
||||
Bot.BotDatabase.DeleteFromJsonStorage(MatchActivelyTradeOfferIDsStorageKey);
|
||||
}
|
||||
|
@ -1427,7 +1435,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
|||
if (tradeOfferIDs?.Count > 0) {
|
||||
matchActivelyTradeOfferIDs.UnionWith(tradeOfferIDs);
|
||||
|
||||
Bot.BotDatabase.SaveToJsonStorage(MatchActivelyTradeOfferIDsStorageKey, JToken.FromObject(matchActivelyTradeOfferIDs));
|
||||
Bot.BotDatabase.SaveToJsonStorage(MatchActivelyTradeOfferIDsStorageKey, matchActivelyTradeOfferIDs);
|
||||
}
|
||||
|
||||
if (mobileTradeOfferIDs?.Count > 0) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -27,9 +27,9 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
|
||||
|
@ -128,7 +128,7 @@ internal static class Commands {
|
|||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
}
|
||||
|
||||
Steam.Security.MobileAuthenticator? mobileAuthenticator = JsonConvert.DeserializeObject<Steam.Security.MobileAuthenticator>(json);
|
||||
Steam.Security.MobileAuthenticator? mobileAuthenticator = json.ToJsonObject<Steam.Security.MobileAuthenticator>();
|
||||
|
||||
if (mobileAuthenticator == null) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
|
@ -261,7 +261,7 @@ internal static class Commands {
|
|||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
}
|
||||
|
||||
Steam.Security.MobileAuthenticator? mobileAuthenticator = JsonConvert.DeserializeObject<Steam.Security.MobileAuthenticator>(json);
|
||||
Steam.Security.MobileAuthenticator? mobileAuthenticator = json.ToJsonObject<Steam.Security.MobileAuthenticator>();
|
||||
|
||||
if (mobileAuthenticator == null) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
|
@ -360,7 +360,7 @@ internal static class Commands {
|
|||
MaFileData maFileData = new(response, bot.SteamID, deviceID);
|
||||
|
||||
string maFilePendingPath = $"{bot.GetFilePath(Bot.EFileType.MobileAuthenticator)}.PENDING";
|
||||
string json = JsonConvert.SerializeObject(maFileData, Formatting.Indented);
|
||||
string json = maFileData.ToJsonText(true);
|
||||
|
||||
try {
|
||||
await File.WriteAllTextAsync(maFilePendingPath, json).ConfigureAwait(false);
|
||||
|
|
|
@ -20,48 +20,71 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
|
||||
|
||||
internal sealed class MaFileData {
|
||||
[JsonProperty("account_name", Required = Required.Always)]
|
||||
internal readonly string AccountName;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("account_name")]
|
||||
[JsonRequired]
|
||||
internal string AccountName { get; private init; }
|
||||
|
||||
[JsonProperty("device_id", Required = Required.Always)]
|
||||
internal readonly string DeviceID;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("device_id")]
|
||||
[JsonRequired]
|
||||
internal string DeviceID { get; private init; }
|
||||
|
||||
[JsonProperty("identity_secret", Required = Required.Always)]
|
||||
internal readonly string IdentitySecret;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("identity_secret")]
|
||||
[JsonRequired]
|
||||
internal string IdentitySecret { get; private init; }
|
||||
|
||||
[JsonProperty("revocation_code", Required = Required.Always)]
|
||||
internal readonly string RevocationCode;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("revocation_code")]
|
||||
[JsonRequired]
|
||||
internal string RevocationCode { get; private init; }
|
||||
|
||||
[JsonProperty("secret_1", Required = Required.Always)]
|
||||
internal readonly string Secret1;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("secret_1")]
|
||||
[JsonRequired]
|
||||
internal string Secret1 { get; private init; }
|
||||
|
||||
[JsonProperty("serial_number", Required = Required.Always)]
|
||||
internal readonly ulong SerialNumber;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("serial_number")]
|
||||
[JsonRequired]
|
||||
internal ulong SerialNumber { get; private init; }
|
||||
|
||||
[JsonProperty("server_time", Required = Required.Always)]
|
||||
internal readonly ulong ServerTime;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("server_time")]
|
||||
[JsonRequired]
|
||||
internal ulong ServerTime { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly MaFileSessionData Session;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal MaFileSessionData Session { get; private init; }
|
||||
|
||||
[JsonProperty("shared_secret", Required = Required.Always)]
|
||||
internal readonly string SharedSecret;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("shared_secret")]
|
||||
[JsonRequired]
|
||||
internal string SharedSecret { get; private init; }
|
||||
|
||||
[JsonProperty("status", Required = Required.Always)]
|
||||
internal readonly int Status;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("status")]
|
||||
[JsonRequired]
|
||||
internal int Status { get; private init; }
|
||||
|
||||
[JsonProperty("token_gid", Required = Required.Always)]
|
||||
internal readonly string TokenGid;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("token_gid")]
|
||||
[JsonRequired]
|
||||
internal string TokenGid { get; private init; }
|
||||
|
||||
[JsonProperty("uri", Required = Required.Always)]
|
||||
internal readonly string Uri;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("uri")]
|
||||
[JsonRequired]
|
||||
internal string Uri { get; private init; }
|
||||
|
||||
internal MaFileData(CTwoFactor_AddAuthenticator_Response data, ulong steamID, string deviceID) {
|
||||
ArgumentNullException.ThrowIfNull(data);
|
||||
|
|
|
@ -20,14 +20,15 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
|
||||
|
||||
internal sealed class MaFileSessionData {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly ulong SteamID;
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
internal MaFileSessionData(ulong steamID) {
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
|
|
|
@ -22,15 +22,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.OfficialPlugins.MobileAuthenticator.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
|
||||
|
@ -38,10 +39,12 @@ namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
|
|||
[Export(typeof(IPlugin))]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeFileLocal")]
|
||||
internal sealed class MobileAuthenticatorPlugin : OfficialPlugin, IBotCommand2, IBotSteamClient {
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override string Name => nameof(MobileAuthenticatorPlugin);
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override Version Version => typeof(MobileAuthenticatorPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
public async Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
|
|
|
@ -23,34 +23,44 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Core;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.Data;
|
||||
|
||||
internal sealed class SubmitRequest {
|
||||
[JsonProperty("guid", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("guid")]
|
||||
private static string Guid => ASF.GlobalDatabase?.Identifier.ToString("N") ?? throw new InvalidOperationException(nameof(ASF.GlobalDatabase.Identifier));
|
||||
|
||||
[JsonProperty("token", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("token")]
|
||||
private static string Token => SharedInfo.Token;
|
||||
|
||||
[JsonProperty("v", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("v")]
|
||||
private static byte Version => SharedInfo.ApiVersion;
|
||||
|
||||
[JsonProperty("apps", Required = Required.Always)]
|
||||
private readonly ImmutableDictionary<string, string> Apps;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("apps")]
|
||||
[JsonRequired]
|
||||
private ImmutableDictionary<string, string> Apps { get; init; }
|
||||
|
||||
[JsonProperty("depots", Required = Required.Always)]
|
||||
private readonly ImmutableDictionary<string, string> Depots;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("depots")]
|
||||
[JsonRequired]
|
||||
private ImmutableDictionary<string, string> Depots { get; init; }
|
||||
|
||||
private readonly ulong SteamID;
|
||||
|
||||
[JsonProperty("subs", Required = Required.Always)]
|
||||
private readonly ImmutableDictionary<string, string> Subs;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("subs")]
|
||||
[JsonRequired]
|
||||
private ImmutableDictionary<string, string> Subs { get; init; }
|
||||
|
||||
[JsonProperty("steamid", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("steamid")]
|
||||
private string SteamIDText => new SteamID(SteamID).Render();
|
||||
|
||||
internal SubmitRequest(ulong steamID, IReadOnlyCollection<KeyValuePair<uint, ulong>> apps, IReadOnlyCollection<KeyValuePair<uint, ulong>> accessTokens, IReadOnlyCollection<KeyValuePair<uint, string>> depots) {
|
||||
|
|
|
@ -20,22 +20,21 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.Data;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during json deserialization
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class SubmitResponse {
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty("data", Required = Required.DisallowNull)]
|
||||
internal readonly SubmitResponseData? Data;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("data")]
|
||||
internal SubmitResponseData? Data { get; private init; }
|
||||
|
||||
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonProperty("success", Required = Required.Always)]
|
||||
internal readonly bool Success;
|
||||
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("success")]
|
||||
[JsonRequired]
|
||||
internal bool Success { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private SubmitResponse() { }
|
||||
|
|
|
@ -20,28 +20,40 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.Data;
|
||||
|
||||
#pragma warning disable CA1812 // False positive, the class is used during json deserialization
|
||||
internal sealed class SubmitResponseData {
|
||||
[JsonProperty("new_apps", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> NewApps = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("new_apps")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> NewApps { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty("new_depots", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> NewDepots = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("new_depots")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> NewDepots { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty("new_subs", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> NewPackages = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("new_subs")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> NewPackages { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty("verified_apps", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> VerifiedApps = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("verified_apps")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> VerifiedApps { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty("verified_depots", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> VerifiedDepots = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("verified_depots")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> VerifiedDepots { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty("verified_subs", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> VerifiedPackages = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("verified_subs")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> VerifiedPackages { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
}
|
||||
#pragma warning restore CA1812 // False positive, the class is used during json deserialization
|
||||
|
|
|
@ -26,14 +26,15 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.Localization;
|
||||
using ArchiSteamFarm.Web.Responses;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
|
||||
|
@ -43,27 +44,34 @@ internal sealed class GlobalCache : SerializableFile {
|
|||
|
||||
private static string SharedFilePath => Path.Combine(ArchiSteamFarm.SharedInfo.ConfigDirectory, $"{nameof(SteamTokenDumper)}.cache");
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, uint> AppChangeNumbers = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, ulong> AppTokens = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, string> DepotKeys = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, ulong> SubmittedApps = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, string> SubmittedDepots = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, ulong> SubmittedPackages = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
[JsonInclude]
|
||||
internal uint LastChangeNumber { get; private set; }
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
private ConcurrentDictionary<uint, uint> AppChangeNumbers { get; init; } = new();
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
private ConcurrentDictionary<uint, ulong> AppTokens { get; init; } = new();
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
private ConcurrentDictionary<uint, string> DepotKeys { get; init; } = new();
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
private ConcurrentDictionary<uint, ulong> SubmittedApps { get; init; } = new();
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
private ConcurrentDictionary<uint, string> SubmittedDepots { get; init; } = new();
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
private ConcurrentDictionary<uint, ulong> SubmittedPackages { get; init; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
internal GlobalCache() => FilePath = SharedFilePath;
|
||||
|
||||
[UsedImplicitly]
|
||||
|
@ -87,6 +95,8 @@ internal sealed class GlobalCache : SerializableFile {
|
|||
[UsedImplicitly]
|
||||
public bool ShouldSerializeSubmittedPackages() => !SubmittedPackages.IsEmpty;
|
||||
|
||||
protected override Task Save() => Save(this);
|
||||
|
||||
internal ulong GetAppToken(uint appID) => AppTokens[appID];
|
||||
|
||||
internal Dictionary<uint, ulong> GetAppTokensForSubmission() => AppTokens.Where(appToken => (SteamTokenDumperPlugin.Config?.SecretAppIDs.Contains(appToken.Key) != true) && (appToken.Value > 0) && (!SubmittedApps.TryGetValue(appToken.Key, out ulong token) || (appToken.Value != token))).ToDictionary(static appToken => appToken.Key, static appToken => appToken.Value);
|
||||
|
@ -118,7 +128,7 @@ internal sealed class GlobalCache : SerializableFile {
|
|||
return null;
|
||||
}
|
||||
|
||||
globalCache = JsonConvert.DeserializeObject<GlobalCache>(json);
|
||||
globalCache = json.ToJsonObject<GlobalCache>();
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
|
||||
|
||||
public sealed class GlobalConfigExtension {
|
||||
[JsonProperty]
|
||||
public SteamTokenDumperConfig? SteamTokenDumperPlugin { get; private set; }
|
||||
[JsonInclude]
|
||||
public SteamTokenDumperConfig? SteamTokenDumperPlugin { get; private init; }
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool SteamTokenDumperPluginEnabled { get; private set; }
|
||||
[JsonInclude]
|
||||
public bool SteamTokenDumperPluginEnabled { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
internal GlobalConfigExtension() { }
|
||||
|
|
|
@ -20,29 +20,33 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.IPC.Integration;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
|
||||
|
||||
public sealed class SteamTokenDumperConfig {
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
[JsonInclude]
|
||||
public bool Enabled { get; internal set; }
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[SwaggerItemsMinMax(MinimumUint = 1, MaximumUint = uint.MaxValue)]
|
||||
public ImmutableHashSet<uint> SecretAppIDs { get; private set; } = ImmutableHashSet<uint>.Empty;
|
||||
public ImmutableHashSet<uint> SecretAppIDs { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[SwaggerItemsMinMax(MinimumUint = 1, MaximumUint = uint.MaxValue)]
|
||||
public ImmutableHashSet<uint> SecretDepotIDs { get; private set; } = ImmutableHashSet<uint>.Empty;
|
||||
public ImmutableHashSet<uint> SecretDepotIDs { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[SwaggerItemsMinMax(MinimumUint = 1, MaximumUint = uint.MaxValue)]
|
||||
public ImmutableHashSet<uint> SecretPackageIDs { get; private set; } = ImmutableHashSet<uint>.Empty;
|
||||
public ImmutableHashSet<uint> SecretPackageIDs { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool SkipAutoGrantPackages { get; private set; } = true;
|
||||
[JsonInclude]
|
||||
public bool SkipAutoGrantPackages { get; private init; } = true;
|
||||
|
||||
[JsonConstructor]
|
||||
internal SteamTokenDumperConfig() { }
|
||||
|
|
|
@ -24,14 +24,18 @@ using System.Collections.Concurrent;
|
|||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Composition;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.Data;
|
||||
using ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
|
@ -41,8 +45,6 @@ using ArchiSteamFarm.Steam.Interaction;
|
|||
using ArchiSteamFarm.Storage;
|
||||
using ArchiSteamFarm.Web;
|
||||
using ArchiSteamFarm.Web.Responses;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
|
||||
|
@ -51,7 +53,7 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;
|
|||
internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotCommand2, IBotSteamClient, ISteamPICSChanges {
|
||||
private const ushort DepotsRateLimitingDelay = 500;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
internal static SteamTokenDumperConfig? Config { get; private set; }
|
||||
|
||||
private static readonly ConcurrentDictionary<Bot, IDisposable> BotSubscriptions = new();
|
||||
|
@ -62,15 +64,17 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
|
|||
private static GlobalCache? GlobalCache;
|
||||
private static DateTimeOffset LastUploadAt = DateTimeOffset.MinValue;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override string Name => nameof(SteamTokenDumperPlugin);
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public override Version Version => typeof(SteamTokenDumperPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
|
||||
|
||||
public Task<uint> GetPreferredChangeNumberToStartFrom() => Task.FromResult(GlobalCache?.LastChangeNumber ?? 0);
|
||||
|
||||
public async Task OnASFInit(IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null) {
|
||||
public async Task OnASFInit(IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null) {
|
||||
if (!SharedInfo.HasValidToken) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.PluginDisabledMissingBuildToken, nameof(SteamTokenDumperPlugin)));
|
||||
|
||||
|
@ -81,15 +85,19 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
|
|||
SteamTokenDumperConfig? config = null;
|
||||
|
||||
if (additionalConfigProperties != null) {
|
||||
foreach ((string configProperty, JToken configValue) in additionalConfigProperties) {
|
||||
foreach ((string configProperty, JsonElement configValue) in additionalConfigProperties) {
|
||||
try {
|
||||
switch (configProperty) {
|
||||
case nameof(GlobalConfigExtension.SteamTokenDumperPlugin):
|
||||
config = configValue.ToObject<SteamTokenDumperConfig>();
|
||||
config = configValue.ToJsonObject<SteamTokenDumperConfig>();
|
||||
|
||||
break;
|
||||
case nameof(GlobalConfigExtension.SteamTokenDumperPluginEnabled):
|
||||
isEnabled = configValue.Value<bool>();
|
||||
case nameof(GlobalConfigExtension.SteamTokenDumperPluginEnabled) when configValue.ValueKind == JsonValueKind.False:
|
||||
isEnabled = false;
|
||||
|
||||
break;
|
||||
case nameof(GlobalConfigExtension.SteamTokenDumperPluginEnabled) when configValue.ValueKind == JsonValueKind.True:
|
||||
isEnabled = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -17,13 +17,11 @@
|
|||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Markdig.Signed" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
<PackageReference Include="Nito.AsyncEx.Coordination" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" />
|
||||
<PackageReference Include="SteamKit2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" />
|
||||
<PackageReference Include="System.Composition" />
|
||||
<PackageReference Include="System.Linq.Async" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
|
||||
|
|
|
@ -28,7 +28,7 @@ using JetBrains.Annotations;
|
|||
|
||||
namespace ArchiSteamFarm.Collections;
|
||||
|
||||
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ISet<T> where T : notnull {
|
||||
public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : notnull {
|
||||
[PublicAPI]
|
||||
public event EventHandler? OnModified;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ using Nito.AsyncEx;
|
|||
|
||||
namespace ArchiSteamFarm.Collections;
|
||||
|
||||
internal sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
|
||||
public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
|
||||
[PublicAPI]
|
||||
public event EventHandler? OnModified;
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ using System.Collections;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Collections;
|
||||
|
||||
|
@ -42,7 +41,6 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
|
|||
[PublicAPI]
|
||||
public ICollection<TKey> Keys => BackingDictionary.Keys;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<TKey, TValue> BackingDictionary = new();
|
||||
|
||||
int ICollection<KeyValuePair<TKey, TValue>>.Count => BackingDictionary.Count;
|
||||
|
@ -54,6 +52,7 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
|
|||
|
||||
public TValue this[TKey key] {
|
||||
get => BackingDictionary[key];
|
||||
|
||||
set {
|
||||
if (BackingDictionary.TryGetValue(key, out TValue? savedValue) && EqualityComparer<TValue>.Default.Equals(savedValue, value)) {
|
||||
return;
|
||||
|
|
30
ArchiSteamFarm/Helpers/Json/JsonDisallowNullAttribute.cs
Normal file
30
ArchiSteamFarm/Helpers/Json/JsonDisallowNullAttribute.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm.Helpers.Json;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
[PublicAPI]
|
||||
public sealed class JsonDisallowNullAttribute : JsonAttribute;
|
186
ArchiSteamFarm/Helpers/Json/JsonUtilities.cs
Normal file
186
ArchiSteamFarm/Helpers/Json/JsonUtilities.cs
Normal file
|
@ -0,0 +1,186 @@
|
|||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm.Helpers.Json;
|
||||
|
||||
public static class JsonUtilities {
|
||||
[PublicAPI]
|
||||
public static readonly JsonSerializerOptions DefaultJsonSerialierOptions = CreateDefaultJsonSerializerOptions();
|
||||
|
||||
[PublicAPI]
|
||||
public static readonly JsonSerializerOptions IndentedJsonSerialierOptions = CreateDefaultJsonSerializerOptions(true);
|
||||
|
||||
[PublicAPI]
|
||||
public static JsonElement ToJsonElement<T>(this T obj, bool writeIndented = false) where T : notnull {
|
||||
ArgumentNullException.ThrowIfNull(obj);
|
||||
|
||||
return JsonSerializer.SerializeToElement(obj, writeIndented ? IndentedJsonSerialierOptions : DefaultJsonSerialierOptions);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static T? ToJsonObject<T>(this JsonElement jsonElement, CancellationToken cancellationToken = default) => jsonElement.Deserialize<T>(DefaultJsonSerialierOptions);
|
||||
|
||||
[PublicAPI]
|
||||
public static async ValueTask<T?> ToJsonObject<T>(this Stream stream, CancellationToken cancellationToken = default) {
|
||||
ArgumentNullException.ThrowIfNull(stream);
|
||||
|
||||
return await JsonSerializer.DeserializeAsync<T>(stream, DefaultJsonSerialierOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static T? ToJsonObject<T>([StringSyntax(StringSyntaxAttribute.Json)] this string json) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(json);
|
||||
|
||||
return JsonSerializer.Deserialize<T>(json, DefaultJsonSerialierOptions);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static string ToJsonText<T>(this T obj, bool writeIndented = false) => JsonSerializer.Serialize(obj, writeIndented ? IndentedJsonSerialierOptions : DefaultJsonSerialierOptions);
|
||||
|
||||
private static void ApplyCustomModifiers(JsonTypeInfo jsonTypeInfo) {
|
||||
ArgumentNullException.ThrowIfNull(jsonTypeInfo);
|
||||
|
||||
bool potentialDisallowedNullsPossible = false;
|
||||
|
||||
foreach (JsonPropertyInfo property in jsonTypeInfo.Properties) {
|
||||
// All our modifications require a valid Get method on a property
|
||||
if (property.Get == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The object should be validated against potential nulls if at least one property has [JsonDisallowNull] declared, avoid performance penalty otherwise
|
||||
if (property.AttributeProvider?.IsDefined(typeof(JsonDisallowNullAttribute), false) == true) {
|
||||
if (property.PropertyType.IsValueType && (Nullable.GetUnderlyingType(property.PropertyType) == null)) {
|
||||
// We should have no [JsonDisallowNull] declared on non-nullable types, this requires developer correction
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(JsonDisallowNullAttribute), $"{property.Name} ({jsonTypeInfo.Type})"));
|
||||
}
|
||||
|
||||
potentialDisallowedNullsPossible = true;
|
||||
}
|
||||
|
||||
// The property should be checked against ShouldSerialize if there is a valid method to invoke, avoid performance penalty otherwise
|
||||
MethodInfo? shouldSerializeMethod = GetShouldSerializeMethod(jsonTypeInfo.Type, property);
|
||||
|
||||
if (shouldSerializeMethod != null) {
|
||||
property.ShouldSerialize = (parent, _) => ShouldSerialize(shouldSerializeMethod, parent);
|
||||
}
|
||||
}
|
||||
|
||||
if (potentialDisallowedNullsPossible) {
|
||||
jsonTypeInfo.OnDeserialized = OnPotentialDisallowedNullsDeserialized;
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonSerializerOptions CreateDefaultJsonSerializerOptions(bool writeIndented = false) =>
|
||||
new() {
|
||||
AllowTrailingCommas = true,
|
||||
PropertyNamingPolicy = null,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ApplyCustomModifiers } },
|
||||
WriteIndented = writeIndented
|
||||
};
|
||||
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2070", Justification = "We don't care about trimmed methods, it's not like we can make it work differently anyway")]
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2075", Justification = "We don't care about trimmed properties, it's not like we can make it work differently anyway")]
|
||||
private static MethodInfo? GetShouldSerializeMethod([SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")] Type parent, JsonPropertyInfo property) {
|
||||
ArgumentNullException.ThrowIfNull(parent);
|
||||
ArgumentNullException.ThrowIfNull(property);
|
||||
|
||||
// Handle most common case where ShouldSerializeXYZ() matches property name
|
||||
MethodInfo? result = parent.GetMethod($"ShouldSerialize{property.Name}", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, Type.EmptyTypes, null);
|
||||
|
||||
if (result?.ReturnType == typeof(bool)) {
|
||||
// Method exists and returns a boolean, that's what we'd like to hear
|
||||
return result;
|
||||
}
|
||||
|
||||
// Handle less common case where ShouldSerializeXYZ() matches original member name
|
||||
PropertyInfo? memberNameProperty = property.GetType().GetProperty("MemberName", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (memberNameProperty == null) {
|
||||
// Should never happen, investigate if it does
|
||||
throw new InvalidOperationException(nameof(memberNameProperty));
|
||||
}
|
||||
|
||||
object? memberNameResult = memberNameProperty.GetValue(property);
|
||||
|
||||
if (memberNameResult is not string memberName) {
|
||||
// Should never happen, investigate if it does
|
||||
throw new InvalidOperationException(nameof(memberName));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(memberName) || (memberName == property.Name)) {
|
||||
// We don't have anything to work with further, there is no ShouldSerialize() method
|
||||
return null;
|
||||
}
|
||||
|
||||
result = parent.GetMethod($"ShouldSerialize{memberName}", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, Type.EmptyTypes, null);
|
||||
|
||||
// Use alternative method if it exists and returns a boolean
|
||||
return result?.ReturnType == typeof(bool) ? result : null;
|
||||
}
|
||||
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2075", Justification = "We don't care about trimmed properties, it's not like we can make it work differently anyway")]
|
||||
private static void OnPotentialDisallowedNullsDeserialized(object obj) {
|
||||
ArgumentNullException.ThrowIfNull(obj);
|
||||
|
||||
Type type = obj.GetType();
|
||||
|
||||
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(field => field.IsDefined(typeof(JsonDisallowNullAttribute), false) && (field.GetValue(obj) == null))) {
|
||||
throw new JsonException($"Required field {field.Name} expects a non-null value.");
|
||||
}
|
||||
|
||||
foreach (PropertyInfo property in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(property => (property.GetMethod != null) && property.IsDefined(typeof(JsonDisallowNullAttribute), false) && (property.GetValue(obj) == null))) {
|
||||
throw new JsonException($"Required property {property.Name} expects a non-null value.");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldSerialize(MethodInfo shouldSerializeMethod, object parent) {
|
||||
ArgumentNullException.ThrowIfNull(shouldSerializeMethod);
|
||||
ArgumentNullException.ThrowIfNull(parent);
|
||||
|
||||
if (shouldSerializeMethod.ReturnType != typeof(bool)) {
|
||||
throw new InvalidOperationException(nameof(shouldSerializeMethod));
|
||||
}
|
||||
|
||||
object? shouldSerialize = shouldSerializeMethod.Invoke(parent, null);
|
||||
|
||||
if (shouldSerialize is not bool result) {
|
||||
// Should not happen, we've already determined we have a method that returns a boolean
|
||||
throw new InvalidOperationException(nameof(shouldSerialize));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -24,7 +24,8 @@ using System.IO;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using Newtonsoft.Json;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm.Helpers;
|
||||
|
||||
|
@ -49,47 +50,60 @@ public abstract class SerializableFile : IDisposable {
|
|||
}
|
||||
}
|
||||
|
||||
protected async Task Save() {
|
||||
if (string.IsNullOrEmpty(FilePath)) {
|
||||
/// <summary>
|
||||
/// Implementing this method in your target class is crucial for providing supported functionality.
|
||||
/// In order to do so, it's enough to call static <see cref="Save" /> function from the parent class, providing <code>this</code> as input parameter.
|
||||
/// Afterwards, simply call your <see cref="Save" /> function whenever you need to save changes.
|
||||
/// This approach will allow JSON serializer used in the <see cref="SerializableFile" /> to properly discover all of the properties used in your class.
|
||||
/// Unfortunately, due to STJ's limitations, called by some "security", it's not possible for base class to resolve your properties automatically otherwise.
|
||||
/// </summary>
|
||||
/// <example>protected override Task Save() => Save(this);</example>
|
||||
[UsedImplicitly]
|
||||
protected abstract Task Save();
|
||||
|
||||
protected static async Task Save<T>(T serializableFile) where T : SerializableFile {
|
||||
ArgumentNullException.ThrowIfNull(serializableFile);
|
||||
|
||||
if (string.IsNullOrEmpty(serializableFile.FilePath)) {
|
||||
throw new InvalidOperationException(nameof(FilePath));
|
||||
}
|
||||
|
||||
if (ReadOnly) {
|
||||
if (serializableFile.ReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
|
||||
lock (FileSemaphore) {
|
||||
if (SavingScheduled) {
|
||||
lock (serializableFile.FileSemaphore) {
|
||||
if (serializableFile.SavingScheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
SavingScheduled = true;
|
||||
serializableFile.SavingScheduled = true;
|
||||
}
|
||||
|
||||
await FileSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
await serializableFile.FileSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
|
||||
lock (FileSemaphore) {
|
||||
SavingScheduled = false;
|
||||
lock (serializableFile.FileSemaphore) {
|
||||
serializableFile.SavingScheduled = false;
|
||||
}
|
||||
|
||||
if (ReadOnly) {
|
||||
if (serializableFile.ReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
string json = JsonConvert.SerializeObject(this, Debugging.IsUserDebugging ? Formatting.Indented : Formatting.None);
|
||||
string json = serializableFile.ToJsonText(Debugging.IsUserDebugging);
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
throw new InvalidOperationException(nameof(json));
|
||||
}
|
||||
|
||||
// We always want to write entire content to temporary file first, in order to never load corrupted data, also when target file doesn't exist
|
||||
string newFilePath = $"{FilePath}.new";
|
||||
string newFilePath = $"{serializableFile.FilePath}.new";
|
||||
|
||||
if (File.Exists(FilePath)) {
|
||||
string currentJson = await File.ReadAllTextAsync(FilePath).ConfigureAwait(false);
|
||||
if (File.Exists(serializableFile.FilePath)) {
|
||||
string currentJson = await File.ReadAllTextAsync(serializableFile.FilePath).ConfigureAwait(false);
|
||||
|
||||
if (json == currentJson) {
|
||||
return;
|
||||
|
@ -97,16 +111,16 @@ public abstract class SerializableFile : IDisposable {
|
|||
|
||||
await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false);
|
||||
|
||||
File.Replace(newFilePath, FilePath, null);
|
||||
File.Replace(newFilePath, serializableFile.FilePath, null);
|
||||
} else {
|
||||
await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false);
|
||||
|
||||
File.Move(newFilePath, FilePath);
|
||||
File.Move(newFilePath, serializableFile.FilePath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
} finally {
|
||||
FileSemaphore.Release();
|
||||
serializableFile.FileSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.IPC.Controllers.Api;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
|
@ -31,8 +33,6 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog.Web;
|
||||
|
||||
namespace ArchiSteamFarm.IPC;
|
||||
|
@ -83,9 +83,9 @@ internal static class ArchiKestrel {
|
|||
string json = await File.ReadAllTextAsync(customConfigPath).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(json)) {
|
||||
JObject jObject = JObject.Parse(json);
|
||||
JsonNode? jsonNode = JsonNode.Parse(json);
|
||||
|
||||
ASF.ArchiLogger.LogGenericDebug($"{SharedInfo.IPCConfigFile}: {jObject.ToString(Formatting.Indented)}");
|
||||
ASF.ArchiLogger.LogGenericDebug($"{SharedInfo.IPCConfigFile}: {jsonNode?.ToJsonText(true) ?? "null"}");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.IPC.Requests;
|
||||
|
@ -32,7 +33,6 @@ using ArchiSteamFarm.Localization;
|
|||
using ArchiSteamFarm.Steam.Interaction;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
||||
|
@ -124,9 +124,9 @@ public sealed class ASFController : ArchiController {
|
|||
}
|
||||
|
||||
if (ASF.GlobalConfig.AdditionalProperties is { Count: > 0 }) {
|
||||
request.GlobalConfig.AdditionalProperties ??= new Dictionary<string, JToken>(ASF.GlobalConfig.AdditionalProperties.Count, ASF.GlobalConfig.AdditionalProperties.Comparer);
|
||||
request.GlobalConfig.AdditionalProperties ??= new Dictionary<string, JsonElement>(ASF.GlobalConfig.AdditionalProperties.Count, ASF.GlobalConfig.AdditionalProperties.Comparer);
|
||||
|
||||
foreach ((string key, JToken value) in ASF.GlobalConfig.AdditionalProperties.Where(property => !request.GlobalConfig.AdditionalProperties.ContainsKey(property.Key))) {
|
||||
foreach ((string key, JsonElement value) in ASF.GlobalConfig.AdditionalProperties.Where(property => !request.GlobalConfig.AdditionalProperties.ContainsKey(property.Key))) {
|
||||
request.GlobalConfig.AdditionalProperties.Add(key, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ using System.Collections.Specialized;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.IPC.Requests;
|
||||
|
@ -33,7 +34,6 @@ using ArchiSteamFarm.Localization;
|
|||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2.Internal;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
@ -127,9 +127,9 @@ public sealed class BotController : ArchiController {
|
|||
}
|
||||
|
||||
if (bot.BotConfig.AdditionalProperties?.Count > 0) {
|
||||
request.BotConfig.AdditionalProperties ??= new Dictionary<string, JToken>(bot.BotConfig.AdditionalProperties.Count, bot.BotConfig.AdditionalProperties.Comparer);
|
||||
request.BotConfig.AdditionalProperties ??= new Dictionary<string, JsonElement>(bot.BotConfig.AdditionalProperties.Count, bot.BotConfig.AdditionalProperties.Comparer);
|
||||
|
||||
foreach ((string key, JToken value) in bot.BotConfig.AdditionalProperties.Where(property => !request.BotConfig.AdditionalProperties.ContainsKey(property.Key))) {
|
||||
foreach ((string key, JsonElement value) in bot.BotConfig.AdditionalProperties.Where(property => !request.BotConfig.AdditionalProperties.ContainsKey(property.Key))) {
|
||||
request.BotConfig.AdditionalProperties.Add(key, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.IPC.Responses;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
using ArchiSteamFarm.NLog.Targets;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
||||
|
@ -156,7 +156,7 @@ public sealed class NLogController : ArchiController {
|
|||
return;
|
||||
}
|
||||
|
||||
string json = JsonConvert.SerializeObject(new GenericResponse<string>(newHistoryEntryArgs.Message));
|
||||
string json = new GenericResponse<string>(newHistoryEntryArgs.Message).ToJsonText();
|
||||
|
||||
await Task.WhenAll(ActiveLogWebSockets.Where(static kv => kv.Key.State == WebSocketState.Open).Select(kv => PostLoggedJsonUpdate(kv.Key, json, kv.Value.Semaphore, kv.Value.CancellationToken))).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ public sealed class NLogController : ArchiController {
|
|||
return;
|
||||
}
|
||||
|
||||
string response = JsonConvert.SerializeObject(new GenericResponse<string>(loggedMessage));
|
||||
string response = new GenericResponse<string>(loggedMessage).ToJsonText();
|
||||
|
||||
await PostLoggedJsonUpdate(webSocket, response, sendSemaphore, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.IPC.Responses;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
||||
|
@ -51,7 +51,7 @@ public sealed class StorageController : ArchiController {
|
|||
/// Loads entry under specified key from ASF's persistent KeyValue JSON storage.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[ProducesResponseType<GenericResponse<JToken>>((int) HttpStatusCode.OK)]
|
||||
[ProducesResponseType<GenericResponse<JsonElement?>>((int) HttpStatusCode.OK)]
|
||||
public ActionResult<GenericResponse> StorageGet(string key) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(key);
|
||||
|
||||
|
@ -59,9 +59,9 @@ public sealed class StorageController : ArchiController {
|
|||
throw new InvalidOperationException(nameof(ASF.GlobalDatabase));
|
||||
}
|
||||
|
||||
JToken? value = ASF.GlobalDatabase.LoadFromJsonStorage(key);
|
||||
JsonElement value = ASF.GlobalDatabase.LoadFromJsonStorage(key);
|
||||
|
||||
return Ok(new GenericResponse<JToken>(true, value));
|
||||
return Ok(new GenericResponse<JsonElement?>(true, value.ValueKind != JsonValueKind.Undefined ? value : null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -70,15 +70,18 @@ public sealed class StorageController : ArchiController {
|
|||
[Consumes("application/json")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.OK)]
|
||||
public ActionResult<GenericResponse> StoragePost(string key, [FromBody] JToken value) {
|
||||
public ActionResult<GenericResponse> StoragePost(string key, [FromBody] JsonElement value) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(key);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
if (value.ValueKind == JsonValueKind.Undefined) {
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
|
||||
if (ASF.GlobalDatabase == null) {
|
||||
throw new InvalidOperationException(nameof(ASF.GlobalDatabase));
|
||||
}
|
||||
|
||||
if (value.Type == JTokenType.Null) {
|
||||
if (value.ValueKind == JsonValueKind.Null) {
|
||||
ASF.GlobalDatabase.DeleteFromJsonStorage(key);
|
||||
} else {
|
||||
ASF.GlobalDatabase.SaveToJsonStorage(key, value);
|
||||
|
|
|
@ -26,11 +26,11 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.IPC.Responses;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api;
|
||||
|
||||
|
@ -63,27 +63,35 @@ public sealed class TypeController : ArchiController {
|
|||
|
||||
if (targetType.IsClass) {
|
||||
foreach (FieldInfo field in targetType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(static field => !field.IsPrivate)) {
|
||||
JsonPropertyAttribute? jsonProperty = field.GetCustomAttribute<JsonPropertyAttribute>();
|
||||
|
||||
if (jsonProperty != null) {
|
||||
string? unifiedName = field.FieldType.GetUnifiedName();
|
||||
|
||||
if (!string.IsNullOrEmpty(unifiedName)) {
|
||||
body[jsonProperty.PropertyName ?? field.Name] = unifiedName;
|
||||
}
|
||||
if (!field.IsDefined(typeof(JsonIncludeAttribute), false) || field.IsDefined(typeof(JsonExtensionDataAttribute), false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string? unifiedName = field.FieldType.GetUnifiedName();
|
||||
|
||||
if (string.IsNullOrEmpty(unifiedName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonPropertyNameAttribute? jsonPropertyName = field.GetCustomAttribute<JsonPropertyNameAttribute>();
|
||||
|
||||
body[jsonPropertyName?.Name ?? field.Name] = unifiedName;
|
||||
}
|
||||
|
||||
foreach (PropertyInfo property in targetType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(static property => property is { CanRead: true, GetMethod.IsPrivate: false })) {
|
||||
JsonPropertyAttribute? jsonProperty = property.GetCustomAttribute<JsonPropertyAttribute>();
|
||||
|
||||
if (jsonProperty != null) {
|
||||
string? unifiedName = property.PropertyType.GetUnifiedName();
|
||||
|
||||
if (!string.IsNullOrEmpty(unifiedName)) {
|
||||
body[jsonProperty.PropertyName ?? property.Name] = unifiedName;
|
||||
}
|
||||
if (!property.IsDefined(typeof(JsonIncludeAttribute), false) || property.IsDefined(typeof(JsonExtensionDataAttribute), false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string? unifiedName = property.PropertyType.GetUnifiedName();
|
||||
|
||||
if (string.IsNullOrEmpty(unifiedName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonPropertyNameAttribute? jsonPropertyName = property.GetCustomAttribute<JsonPropertyNameAttribute>();
|
||||
|
||||
body[jsonPropertyName?.Name ?? property.Name] = unifiedName;
|
||||
}
|
||||
} else if (targetType.IsEnum) {
|
||||
Type enumType = Enum.GetUnderlyingType(targetType);
|
||||
|
|
|
@ -68,7 +68,7 @@ internal sealed class ApiAuthenticationMiddleware {
|
|||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public async Task InvokeAsync(HttpContext context, IOptions<MvcNewtonsoftJsonOptions> jsonOptions) {
|
||||
public async Task InvokeAsync(HttpContext context, IOptions<JsonOptions> jsonOptions) {
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
ArgumentNullException.ThrowIfNull(jsonOptions);
|
||||
|
||||
|
@ -84,7 +84,7 @@ internal sealed class ApiAuthenticationMiddleware {
|
|||
|
||||
StatusCodeResponse statusCodeResponse = new(statusCode, permanent);
|
||||
|
||||
await context.Response.WriteJsonAsync(new GenericResponse<StatusCodeResponse>(false, statusCodeResponse), jsonOptions.Value.SerializerSettings).ConfigureAwait(false);
|
||||
await context.Response.WriteAsJsonAsync(new GenericResponse<StatusCodeResponse>(false, statusCodeResponse), jsonOptions.Value.JsonSerializerOptions).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static void ClearFailedAuthorizations(object? state = null) => FailedAuthorizations.Clear();
|
||||
|
|
40
ArchiSteamFarm/IPC/Integration/ReadOnlyFixesSchemaFilter.cs
Normal file
40
ArchiSteamFarm/IPC/Integration/ReadOnlyFixesSchemaFilter.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Integration;
|
||||
|
||||
[UsedImplicitly]
|
||||
internal sealed class ReadOnlyFixesSchemaFilter : ISchemaFilter {
|
||||
public void Apply(OpenApiSchema schema, SchemaFilterContext context) {
|
||||
ArgumentNullException.ThrowIfNull(schema);
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
|
||||
if (schema.ReadOnly && context.MemberInfo is PropertyInfo { CanWrite: true }) {
|
||||
schema.ReadOnly = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,10 +28,10 @@ namespace ArchiSteamFarm.IPC.Integration;
|
|||
|
||||
[PublicAPI]
|
||||
public sealed class SwaggerSteamIdentifierAttribute : CustomSwaggerAttribute {
|
||||
public EAccountType AccountType { get; set; } = EAccountType.Individual;
|
||||
public uint MaximumAccountID { get; set; } = uint.MaxValue;
|
||||
public uint MinimumAccountID { get; set; } = 1;
|
||||
public EUniverse Universe { get; set; } = EUniverse.Public;
|
||||
public EAccountType AccountType { get; init; } = EAccountType.Individual;
|
||||
public uint MaximumAccountID { get; init; } = uint.MaxValue;
|
||||
public uint MinimumAccountID { get; init; } = 1;
|
||||
public EUniverse Universe { get; init; } = EUniverse.Public;
|
||||
|
||||
public override void Apply(OpenApiSchema schema) {
|
||||
ArgumentNullException.ThrowIfNull(schema);
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace ArchiSteamFarm.IPC.Integration;
|
|||
|
||||
[PublicAPI]
|
||||
public sealed class SwaggerValidValuesAttribute : CustomSwaggerAttribute {
|
||||
public int[]? ValidIntValues { get; set; }
|
||||
public string[]? ValidStringValues { get; set; }
|
||||
public int[]? ValidIntValues { get; init; }
|
||||
public string[]? ValidStringValues { get; init; }
|
||||
|
||||
public override void Apply(OpenApiSchema schema) {
|
||||
ArgumentNullException.ThrowIfNull(schema);
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -31,16 +31,18 @@ public sealed class ASFEncryptRequest {
|
|||
/// <summary>
|
||||
/// Encryption method used for encrypting this string.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public ArchiCryptoHelper.ECryptoMethod CryptoMethod { get; private set; }
|
||||
public ArchiCryptoHelper.ECryptoMethod CryptoMethod { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// String to encrypt with provided <see cref="CryptoMethod" />.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string StringToEncrypt { get; private set; } = "";
|
||||
public string StringToEncrypt { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private ASFEncryptRequest() { }
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -31,16 +31,18 @@ public sealed class ASFHashRequest {
|
|||
/// <summary>
|
||||
/// Hashing method used for hashing this string.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public ArchiCryptoHelper.EHashingMethod HashingMethod { get; private set; }
|
||||
public ArchiCryptoHelper.EHashingMethod HashingMethod { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// String to hash with provided <see cref="HashingMethod" />.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string StringToHash { get; private set; } = "";
|
||||
public string StringToHash { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private ASFHashRequest() { }
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -31,9 +31,10 @@ public sealed class ASFRequest {
|
|||
/// <summary>
|
||||
/// ASF's global config structure.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public GlobalConfig GlobalConfig { get; private set; } = new();
|
||||
public GlobalConfig GlobalConfig { get; private init; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
private ASFRequest() { }
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
using System.Collections.Specialized;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -35,9 +35,10 @@ public sealed class BotGamesToRedeemInBackgroundRequest {
|
|||
/// Key in the map must be a valid and unique Steam cd-key.
|
||||
/// Value in the map must be a non-null and non-empty name of the key (e.g. game's name, but can be anything).
|
||||
/// </remarks>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public OrderedDictionary GamesToRedeemInBackground { get; private set; } = new();
|
||||
public OrderedDictionary GamesToRedeemInBackground { get; private init; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
private BotGamesToRedeemInBackgroundRequest() { }
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Core;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -30,14 +31,18 @@ public sealed class BotInputRequest {
|
|||
/// <summary>
|
||||
/// Specifies the type of the input.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public ASF.EUserInputType Type { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public ASF.EUserInputType Type { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the value for given input type (declared in <see cref="Type" />)
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public string Value { get; private set; } = "";
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string Value { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private BotInputRequest() { }
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -29,14 +29,14 @@ public sealed class BotPauseRequest {
|
|||
/// <summary>
|
||||
/// Specifies if pause is permanent or temporary (default).
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool Permanent { get; private set; }
|
||||
[JsonInclude]
|
||||
public bool Permanent { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies automatic resume action in given seconds. Default value of 0 disables automatic resume.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ushort ResumeInSeconds { get; private set; }
|
||||
[JsonInclude]
|
||||
public ushort ResumeInSeconds { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private BotPauseRequest() { }
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -31,9 +31,10 @@ public sealed class BotRedeemRequest {
|
|||
/// <summary>
|
||||
/// A collection (set) of keys to redeem.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public ImmutableHashSet<string> KeysToRedeem { get; private set; } = ImmutableHashSet<string>.Empty;
|
||||
public ImmutableHashSet<string> KeysToRedeem { get; private init; } = ImmutableHashSet<string>.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
private BotRedeemRequest() { }
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -30,9 +30,10 @@ public sealed class BotRenameRequest {
|
|||
/// <summary>
|
||||
/// Specifies the new name for the bot. The new name can't be "ASF", neither the one used by any existing bot.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string NewName { get; private set; } = "";
|
||||
public string NewName { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private BotRenameRequest() { }
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -31,9 +31,10 @@ public sealed class BotRequest {
|
|||
/// <summary>
|
||||
/// ASF's bot config structure.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public BotConfig BotConfig { get; private set; } = new();
|
||||
public BotConfig BotConfig { get; private init; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
private BotRequest() { }
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -30,9 +30,10 @@ public sealed class CommandRequest {
|
|||
/// <summary>
|
||||
/// Specifies the command that will be executed by ASF.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string Command { get; private set; } = "";
|
||||
public string Command { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private CommandRequest() { }
|
||||
|
|
|
@ -22,13 +22,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -37,29 +39,34 @@ public sealed class TwoFactorAuthenticationConfirmationsRequest {
|
|||
/// <summary>
|
||||
/// Specifies the target action, whether we should accept the confirmations (true), or decline them (false).
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public bool Accept { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public bool Accept { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies IDs of the confirmations that we're supposed to handle. CreatorID of the confirmation is equal to ID of the object that triggered it - e.g. ID of the trade offer, or ID of the market listing. If not provided, or empty array, all confirmation IDs are considered for an action.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ImmutableHashSet<ulong> AcceptedCreatorIDs { get; private set; } = ImmutableHashSet<ulong>.Empty;
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
public ImmutableHashSet<ulong> AcceptedCreatorIDs { get; private init; } = ImmutableHashSet<ulong>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the type of confirmations to handle. If not provided, all confirmation types are considered for an action.
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public Confirmation.EConfirmationType? AcceptedType { get; private set; }
|
||||
[JsonInclude]
|
||||
public Confirmation.EConfirmationType? AcceptedType { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// A helper property which works the same as <see cref="AcceptedCreatorIDs" /> but with values written as strings - for javascript compatibility purposes. Use either this one, or <see cref="AcceptedCreatorIDs" />, not both.
|
||||
/// </summary>
|
||||
[JsonProperty($"{SharedInfo.UlongCompatibilityStringPrefix}{nameof(AcceptedCreatorIDs)}", Required = Required.DisallowNull)]
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName($"{SharedInfo.UlongCompatibilityStringPrefix}{nameof(AcceptedCreatorIDs)}")]
|
||||
public ImmutableHashSet<string> SAcceptedCreatorIDs {
|
||||
get => AcceptedCreatorIDs.Select(static creatorID => creatorID.ToString(CultureInfo.InvariantCulture)).ToImmutableHashSet(StringComparer.Ordinal);
|
||||
|
||||
private set {
|
||||
private init {
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
HashSet<ulong> acceptedCreatorIDs = [];
|
||||
|
@ -81,8 +88,8 @@ public sealed class TwoFactorAuthenticationConfirmationsRequest {
|
|||
/// <summary>
|
||||
/// Specifies whether we should wait for the confirmations to arrive, in case they're not available immediately. This option makes sense only if <see cref="AcceptedCreatorIDs" /> is specified as well, and in this case ASF will add a few more tries if needed to ensure that all specified IDs are handled. Useful if confirmations are generated with a delay on Steam network side, which happens fairly often.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool WaitIfNeeded { get; private set; }
|
||||
[JsonInclude]
|
||||
public bool WaitIfNeeded { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private TwoFactorAuthenticationConfirmationsRequest() { }
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
|
@ -30,8 +30,8 @@ public sealed class UpdateRequest {
|
|||
/// <summary>
|
||||
/// Target update channel. Not required, will default to UpdateChannel in GlobalConfig if not provided.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public GlobalConfig.EUpdateChannel? Channel { get; private set; }
|
||||
[JsonInclude]
|
||||
public GlobalConfig.EUpdateChannel? Channel { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private UpdateRequest() { }
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -30,51 +30,58 @@ public sealed class ASFResponse {
|
|||
/// <summary>
|
||||
/// ASF's build variant.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string BuildVariant { get; private set; }
|
||||
public string BuildVariant { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// A value specifying whether this variant of ASF is capable of auto-update.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public bool CanUpdate { get; private set; }
|
||||
public bool CanUpdate { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently loaded ASF's global config.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public GlobalConfig GlobalConfig { get; private set; }
|
||||
public GlobalConfig GlobalConfig { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Current amount of managed memory being used by the process, in kilobytes.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public uint MemoryUsage { get; private set; }
|
||||
public uint MemoryUsage { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Start date of the process.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public DateTime ProcessStartTime { get; private set; }
|
||||
public DateTime ProcessStartTime { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean value specifying whether ASF has been started with a --service parameter.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public bool Service { get; private set; }
|
||||
public bool Service { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// ASF version of currently running binary.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public Version Version { get; private set; }
|
||||
public Version Version { get; private init; }
|
||||
|
||||
internal ASFResponse(string buildVariant, bool canUpdate, GlobalConfig globalConfig, uint memoryUsage, DateTime processStartTime, Version version) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(buildVariant);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -28,14 +28,14 @@ public sealed class GamesToRedeemInBackgroundResponse {
|
|||
/// <summary>
|
||||
/// Keys that were redeemed and not used during the process, if available.
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public Dictionary<string, string>? UnusedKeys { get; private set; }
|
||||
[JsonInclude]
|
||||
public Dictionary<string, string>? UnusedKeys { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Keys that were redeemed and used during the process, if available.
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public Dictionary<string, string>? UsedKeys { get; private set; }
|
||||
[JsonInclude]
|
||||
public Dictionary<string, string>? UsedKeys { get; private init; }
|
||||
|
||||
internal GamesToRedeemInBackgroundResponse(Dictionary<string, string>? unusedKeys = null, Dictionary<string, string>? usedKeys = null) {
|
||||
UnusedKeys = unusedKeys;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -32,8 +32,8 @@ public sealed class GenericResponse<T> : GenericResponse {
|
|||
/// <remarks>
|
||||
/// The type of the result depends on the API endpoint that you've called.
|
||||
/// </remarks>
|
||||
[JsonProperty]
|
||||
public T? Result { get; private set; }
|
||||
[JsonInclude]
|
||||
public T? Result { get; private init; }
|
||||
|
||||
public GenericResponse(T? result) : base(result is not null) => Result = result;
|
||||
public GenericResponse(bool success, string? message) : base(success, message) { }
|
||||
|
@ -51,15 +51,16 @@ public class GenericResponse {
|
|||
/// <remarks>
|
||||
/// This property will provide exact reason for majority of expected failures.
|
||||
/// </remarks>
|
||||
[JsonProperty]
|
||||
public string? Message { get; private set; }
|
||||
[JsonInclude]
|
||||
public string? Message { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean type that specifies if the request has succeeded.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public bool Success { get; private set; }
|
||||
public bool Success { get; private init; }
|
||||
|
||||
public GenericResponse(bool success, string? message = null) {
|
||||
Success = success;
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Web;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -30,30 +30,34 @@ public sealed class GitHubReleaseResponse {
|
|||
/// <summary>
|
||||
/// Changelog of the release rendered in HTML.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string ChangelogHTML { get; private set; }
|
||||
public string ChangelogHTML { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Date of the release.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public DateTime ReleasedAt { get; private set; }
|
||||
public DateTime ReleasedAt { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean value that specifies whether the build is stable or not (pre-release).
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public bool Stable { get; private set; }
|
||||
public bool Stable { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Version of the release.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public string Version { get; private set; }
|
||||
public string Version { get; private init; }
|
||||
|
||||
internal GitHubReleaseResponse(GitHub.ReleaseResponse releaseResponse) {
|
||||
ArgumentNullException.ThrowIfNull(releaseResponse);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -30,16 +30,18 @@ public sealed class LogResponse {
|
|||
/// <summary>
|
||||
/// Content of the log file which consists of lines read from it - in chronological order.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public IReadOnlyList<string> Content { get; private set; }
|
||||
public IReadOnlyList<string> Content { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of lines of the log file returned, can be used as an index for future requests.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public int TotalLines { get; private set; }
|
||||
public int TotalLines { get; private init; }
|
||||
|
||||
internal LogResponse(int totalLines, IReadOnlyList<string> content) {
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(totalLines);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -29,16 +29,18 @@ public sealed class StatusCodeResponse {
|
|||
/// <summary>
|
||||
/// Value indicating whether the status is permanent. If yes, retrying the request with exactly the same payload doesn't make sense due to a permanent problem (e.g. ASF misconfiguration).
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public bool Permanent { get; private set; }
|
||||
public bool Permanent { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Status code transmitted in addition to the one in HTTP spec.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public HttpStatusCode StatusCode { get; private set; }
|
||||
public HttpStatusCode StatusCode { get; private init; }
|
||||
|
||||
internal StatusCodeResponse(HttpStatusCode statusCode, bool permanent) {
|
||||
StatusCode = statusCode;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -32,8 +32,8 @@ public sealed class TypeProperties {
|
|||
/// <remarks>
|
||||
/// This can be used for determining how the body of the response should be interpreted.
|
||||
/// </remarks>
|
||||
[JsonProperty]
|
||||
public string? BaseType { get; private set; }
|
||||
[JsonInclude]
|
||||
public string? BaseType { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom attributes of given type, if available.
|
||||
|
@ -41,8 +41,8 @@ public sealed class TypeProperties {
|
|||
/// <remarks>
|
||||
/// This can be used for determining main enum type if <see cref="BaseType" /> is <see cref="Enum" />.
|
||||
/// </remarks>
|
||||
[JsonProperty]
|
||||
public HashSet<string>? CustomAttributes { get; private set; }
|
||||
[JsonInclude]
|
||||
public HashSet<string>? CustomAttributes { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Underlying type of given type, if available.
|
||||
|
@ -50,8 +50,8 @@ public sealed class TypeProperties {
|
|||
/// <remarks>
|
||||
/// This can be used for determining underlying enum type if <see cref="BaseType" /> is <see cref="Enum" />.
|
||||
/// </remarks>
|
||||
[JsonProperty]
|
||||
public string? UnderlyingType { get; private set; }
|
||||
[JsonInclude]
|
||||
public string? UnderlyingType { get; private init; }
|
||||
|
||||
internal TypeProperties(string? baseType = null, HashSet<string>? customAttributes = null, string? underlyingType = null) {
|
||||
BaseType = baseType;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Responses;
|
||||
|
||||
|
@ -35,16 +35,18 @@ public sealed class TypeResponse {
|
|||
/// For enums, keys are friendly names while values are underlying values of those names.
|
||||
/// For objects, keys are non-private fields and properties, while values are underlying types of those.
|
||||
/// </remarks>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public Dictionary<string, string> Body { get; private set; }
|
||||
public Dictionary<string, string> Body { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of given type.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[Required]
|
||||
public TypeProperties Properties { get; private set; }
|
||||
public TypeProperties Properties { get; private init; }
|
||||
|
||||
internal TypeResponse(Dictionary<string, string> body, TypeProperties properties) {
|
||||
ArgumentNullException.ThrowIfNull(body);
|
||||
|
|
|
@ -28,6 +28,7 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Reflection;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.IPC.Integration;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
|
@ -45,8 +46,6 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||
|
||||
namespace ArchiSteamFarm.IPC;
|
||||
|
@ -284,6 +283,7 @@ internal sealed class Startup {
|
|||
|
||||
options.SchemaFilter<CustomAttributesSchemaFilter>();
|
||||
options.SchemaFilter<EnumSchemaFilter>();
|
||||
options.SchemaFilter<ReadOnlyFixesSchemaFilter>();
|
||||
|
||||
options.SwaggerDoc(
|
||||
SharedInfo.ASF, new OpenApiInfo {
|
||||
|
@ -310,9 +310,6 @@ internal sealed class Startup {
|
|||
}
|
||||
);
|
||||
|
||||
// Add support for Newtonsoft.Json in swagger, this one must be executed after AddSwaggerGen()
|
||||
services.AddSwaggerGenNewtonsoftSupport();
|
||||
|
||||
// We need MVC for /Api, but we're going to use only a small subset of all available features
|
||||
IMvcBuilder mvc = services.AddControllers();
|
||||
|
||||
|
@ -329,14 +326,10 @@ internal sealed class Startup {
|
|||
|
||||
mvc.AddControllersAsServices();
|
||||
|
||||
mvc.AddNewtonsoftJson(
|
||||
mvc.AddJsonOptions(
|
||||
static options => {
|
||||
// Fix default contract resolver to use original names and not a camel case
|
||||
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
|
||||
|
||||
if (Debugging.IsUserDebugging) {
|
||||
options.SerializerSettings.Formatting = Formatting.Indented;
|
||||
}
|
||||
options.JsonSerializerOptions.PropertyNamingPolicy = JsonUtilities.DefaultJsonSerialierOptions.PropertyNamingPolicy;
|
||||
options.JsonSerializerOptions.TypeInfoResolver = JsonUtilities.DefaultJsonSerialierOptions.TypeInfoResolver;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -21,12 +21,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC;
|
||||
|
||||
|
@ -56,26 +51,4 @@ internal static class WebUtilities {
|
|||
|
||||
return Type.GetType($"{typeText},{typeText[..index]}");
|
||||
}
|
||||
|
||||
internal static async Task WriteJsonAsync<TValue>(this HttpResponse response, TValue? value, JsonSerializerSettings? jsonSerializerSettings = null) {
|
||||
ArgumentNullException.ThrowIfNull(response);
|
||||
|
||||
JsonSerializer serializer = JsonSerializer.CreateDefault(jsonSerializerSettings);
|
||||
|
||||
response.ContentType = "application/json; charset=utf-8";
|
||||
|
||||
StreamWriter streamWriter = new(response.Body, Encoding.UTF8);
|
||||
|
||||
await using (streamWriter.ConfigureAwait(false)) {
|
||||
#pragma warning disable CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
|
||||
JsonTextWriter jsonWriter = new(streamWriter) {
|
||||
CloseOutput = false
|
||||
};
|
||||
#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
|
||||
|
||||
await using (jsonWriter.ConfigureAwait(false)) {
|
||||
serializer.Serialize(jsonWriter, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ArchiSteamFarm.Plugins.Interfaces;
|
||||
|
||||
|
@ -33,5 +33,5 @@ public interface IASF : IPlugin {
|
|||
/// ASF will call this method right after global config initialization.
|
||||
/// </summary>
|
||||
/// <param name="additionalConfigProperties">Extra config properties made out of <see cref="JsonExtensionDataAttribute" />. Can be null if no extra properties are found.</param>
|
||||
Task OnASFInit(IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null);
|
||||
Task OnASFInit(IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null);
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ArchiSteamFarm.Plugins.Interfaces;
|
||||
|
||||
|
@ -35,5 +35,5 @@ public interface IBotModules : IPlugin {
|
|||
/// </summary>
|
||||
/// <param name="bot">Bot object related to this callback.</param>
|
||||
/// <param name="additionalConfigProperties">Extra config properties made out of <see cref="JsonExtensionDataAttribute" />. Can be null if no extra properties are found.</param>
|
||||
Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null);
|
||||
Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Plugins.Interfaces;
|
||||
|
||||
|
@ -32,7 +33,8 @@ public interface IPlugin {
|
|||
/// ASF will use this property as general plugin identifier for the user.
|
||||
/// </summary>
|
||||
/// <returns>String that will be used as the name of this plugin.</returns>
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -40,7 +42,8 @@ public interface IPlugin {
|
|||
/// You have a freedom in deciding what versioning you want to use, this is for identification purposes only.
|
||||
/// </summary>
|
||||
/// <returns>Version that will be shown to the user when plugin is loaded.</returns>
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
Version Version { get; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Plugins.Interfaces;
|
||||
|
||||
|
@ -35,6 +35,6 @@ public interface IWebInterface : IPlugin {
|
|||
/// <summary>
|
||||
/// Specifies web path (address) under which ASF should host your static WWW files in <see cref="PhysicalPath" /> directory. Default value of "/" allows you to override default ASF files and gives you full flexibility in your <see cref="PhysicalPath" /> directory. However, you can instead host your files under some other fixed location specified here, such as "/MyPlugin".
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
string WebPath => "/";
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
|
@ -43,7 +44,6 @@ using ArchiSteamFarm.Steam.Data;
|
|||
using ArchiSteamFarm.Steam.Exchange;
|
||||
using ArchiSteamFarm.Steam.Integration.Callbacks;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Plugins;
|
||||
|
@ -286,7 +286,7 @@ public static class PluginsCore {
|
|||
return assemblies;
|
||||
}
|
||||
|
||||
internal static async Task OnASFInitModules(IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null) {
|
||||
internal static async Task OnASFInitModules(IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null) {
|
||||
if (ActivePlugins.Count == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -436,7 +436,7 @@ public static class PluginsCore {
|
|||
}
|
||||
}
|
||||
|
||||
internal static async Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JToken>? additionalConfigProperties = null) {
|
||||
internal static async Task OnBotInitModules(Bot bot, IReadOnlyDictionary<string, JsonElement>? additionalConfigProperties = null) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
|
||||
if (ActivePlugins.Count == 0) {
|
||||
|
|
|
@ -33,6 +33,7 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.IPC;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
|
@ -40,7 +41,6 @@ using ArchiSteamFarm.NLog.Targets;
|
|||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using ArchiSteamFarm.Web;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using SteamKit2;
|
||||
|
||||
|
@ -353,7 +353,7 @@ internal static class Program {
|
|||
}
|
||||
|
||||
if (globalConfig.Debug) {
|
||||
ASF.ArchiLogger.LogGenericDebug($"{globalConfigFile}: {JsonConvert.SerializeObject(globalConfig, Formatting.Indented)}");
|
||||
ASF.ArchiLogger.LogGenericDebug($"{globalConfigFile}: {globalConfig.ToJsonText(true)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(globalConfig.CurrentCulture)) {
|
||||
|
@ -414,7 +414,7 @@ internal static class Program {
|
|||
// If debugging is on, we prepare debug directory prior to running
|
||||
if (Debugging.IsUserDebugging) {
|
||||
if (Debugging.IsDebugConfigured) {
|
||||
ASF.ArchiLogger.LogGenericDebug($"{globalDatabaseFile}: {JsonConvert.SerializeObject(ASF.GlobalDatabase, Formatting.Indented)}");
|
||||
ASF.ArchiLogger.LogGenericDebug($"{globalDatabaseFile}: {globalDatabase.ToJsonText(true)}");
|
||||
}
|
||||
|
||||
Logging.EnableTraceLogging();
|
||||
|
|
|
@ -27,10 +27,12 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -38,6 +40,7 @@ using AngleSharp.Dom;
|
|||
using ArchiSteamFarm.Collections;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
|
@ -53,7 +56,6 @@ using ArchiSteamFarm.Storage;
|
|||
using ArchiSteamFarm.Web;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
using SteamKit2.Authentication;
|
||||
using SteamKit2.Internal;
|
||||
|
@ -101,24 +103,28 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
[PublicAPI]
|
||||
public BotDatabase BotDatabase { get; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public string BotName { get; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public CardsFarmer CardsFarmer { get; }
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public Commands Commands { get; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public uint GamesToRedeemInBackgroundCount => BotDatabase.GamesToRedeemInBackgroundCount;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public bool HasMobileAuthenticator => BotDatabase.MobileAuthenticator != null;
|
||||
|
||||
[JsonIgnore]
|
||||
|
@ -129,18 +135,26 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
[PublicAPI]
|
||||
public bool IsAccountLocked => AccountFlags.HasFlag(EAccountFlags.Lockdown);
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public bool IsConnectedAndLoggedOn => SteamClient.SteamID != null;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public bool IsPlayingPossible => !PlayingBlocked && !LibraryLocked;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
public string? PublicIP => SteamClient.PublicIP?.ToString();
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName($"{SharedInfo.UlongCompatibilityStringPrefix}{nameof(SteamID)}")]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public string SSteamID => SteamID.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public SteamApps SteamApps { get; }
|
||||
|
@ -186,9 +200,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
}
|
||||
}
|
||||
|
||||
[JsonProperty($"{SharedInfo.UlongCompatibilityStringPrefix}{nameof(SteamID)}")]
|
||||
private string SSteamID => SteamID.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public string? AccessToken {
|
||||
|
@ -217,19 +228,29 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
}
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public EAccountFlags AccountFlags { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
public string? AvatarHash { get; private set; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public BotConfig BotConfig { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public bool KeepRunning { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
public string? Nickname { get; private set; }
|
||||
|
||||
|
@ -237,24 +258,34 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
[PublicAPI]
|
||||
public FrozenDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> OwnedPackageIDs { get; private set; } = FrozenDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)>.Empty;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public ASF.EUserInputType RequiredInput { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public ulong SteamID { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public long WalletBalance { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public long WalletBalanceDelayed { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public ECurrencyCode WalletCurrency { get; private set; }
|
||||
|
||||
internal byte HeartBeatFailures { get; private set; }
|
||||
|
@ -264,9 +295,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
private DateTime? AccessTokenValidUntil;
|
||||
private string? AuthCode;
|
||||
|
||||
[JsonProperty]
|
||||
private string? AvatarHash;
|
||||
|
||||
private string? BackingAccessToken;
|
||||
private Timer? ConnectionFailureTimer;
|
||||
private bool FirstTradeSent;
|
||||
|
@ -1660,7 +1688,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
}
|
||||
|
||||
if (Debugging.IsDebugConfigured) {
|
||||
ASF.ArchiLogger.LogGenericDebug($"{configFilePath}: {JsonConvert.SerializeObject(botConfig, Formatting.Indented)}");
|
||||
ASF.ArchiLogger.LogGenericDebug($"{configFilePath}: {botConfig.ToJsonText(true)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(latestJson)) {
|
||||
|
@ -1688,7 +1716,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
}
|
||||
|
||||
if (Debugging.IsDebugConfigured) {
|
||||
ASF.ArchiLogger.LogGenericDebug($"{databaseFilePath}: {JsonConvert.SerializeObject(botDatabase, Formatting.Indented)}");
|
||||
ASF.ArchiLogger.LogGenericDebug($"{databaseFilePath}: {botDatabase.ToJsonText(true)}");
|
||||
}
|
||||
|
||||
botDatabase.PerformMaintenance();
|
||||
|
@ -2280,7 +2308,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
|
|||
return;
|
||||
}
|
||||
|
||||
MobileAuthenticator? authenticator = JsonConvert.DeserializeObject<MobileAuthenticator>(json);
|
||||
MobileAuthenticator? authenticator = json.ToJsonObject<MobileAuthenticator>();
|
||||
|
||||
if (authenticator == null) {
|
||||
ArchiLogger.LogNullError(authenticator);
|
||||
|
|
|
@ -24,8 +24,10 @@ using System.Collections.Concurrent;
|
|||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -42,7 +44,6 @@ using ArchiSteamFarm.Steam.Storage;
|
|||
using ArchiSteamFarm.Storage;
|
||||
using ArchiSteamFarm.Web;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Cards;
|
||||
|
@ -63,16 +64,21 @@ public sealed class CardsFarmer : IAsyncDisposable, IDisposable {
|
|||
// Games that were confirmed to show false status on general badges page
|
||||
private static readonly FrozenSet<uint> UntrustedAppIDs = new HashSet<uint>(3) { 440, 570, 730 }.ToFrozenSet();
|
||||
|
||||
[JsonProperty(nameof(CurrentGamesFarming))]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName(nameof(CurrentGamesFarming))]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public IReadOnlyCollection<Game> CurrentGamesFarmingReadOnly => CurrentGamesFarming;
|
||||
|
||||
[JsonProperty(nameof(GamesToFarm))]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName(nameof(GamesToFarm))]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public IReadOnlyCollection<Game> GamesToFarmReadOnly => GamesToFarm;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public TimeSpan TimeRemaining {
|
||||
get {
|
||||
if (GamesToFarm.Count == 0) {
|
||||
|
@ -136,8 +142,10 @@ public sealed class CardsFarmer : IAsyncDisposable, IDisposable {
|
|||
}
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
[Required]
|
||||
public bool Paused { get; private set; }
|
||||
|
||||
internal bool NowFarming { get; private set; }
|
||||
|
|
|
@ -20,23 +20,28 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Cards;
|
||||
|
||||
public sealed class Game : IEquatable<Game> {
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public uint AppID { get; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public string GameName { get; }
|
||||
|
||||
internal readonly byte BadgeLevel;
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public ushort CardsRemaining { get; internal set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonInclude]
|
||||
[Required]
|
||||
public float HoursPlayed { get; internal set; }
|
||||
|
||||
internal uint PlayableAppID { get; set; }
|
||||
|
|
|
@ -22,11 +22,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using ArchiSteamFarm.Core;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
|
@ -43,34 +41,46 @@ public sealed class Asset {
|
|||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public IReadOnlyDictionary<string, JToken>? AdditionalPropertiesReadOnly => AdditionalProperties;
|
||||
public IReadOnlyDictionary<string, JsonElement>? AdditionalPropertiesReadOnly => AdditionalProperties;
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public bool IsSteamPointsShopItem => !Tradable && (InstanceID == SteamPointsShopInstanceID);
|
||||
|
||||
[JsonIgnore]
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("amount")]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
public uint Amount { get; internal set; }
|
||||
|
||||
[JsonProperty("appid", Required = Required.DisallowNull)]
|
||||
public uint AppID { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("appid")]
|
||||
public uint AppID { get; private init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("assetid")]
|
||||
[PublicAPI]
|
||||
public ulong AssetID { get; private set; }
|
||||
public ulong AssetID { get; private init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("classid")]
|
||||
[PublicAPI]
|
||||
public ulong ClassID { get; private set; }
|
||||
public ulong ClassID { get; private init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("contextid")]
|
||||
[PublicAPI]
|
||||
public ulong ContextID { get; private set; }
|
||||
public ulong ContextID { get; private init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("instanceid")]
|
||||
[PublicAPI]
|
||||
public ulong InstanceID { get; private set; }
|
||||
public ulong InstanceID { get; private init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
|
@ -96,109 +106,16 @@ public sealed class Asset {
|
|||
[PublicAPI]
|
||||
public EType Type { get; internal set; }
|
||||
|
||||
[JsonExtensionData(WriteData = false)]
|
||||
internal Dictionary<string, JToken>? AdditionalProperties { private get; set; }
|
||||
[JsonExtensionData]
|
||||
[JsonInclude]
|
||||
internal Dictionary<string, JsonElement>? AdditionalProperties { get; set; }
|
||||
|
||||
[JsonProperty("amount", Required = Required.Always)]
|
||||
private string AmountText {
|
||||
get => Amount.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uint.TryParse(value, out uint amount) || (amount == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(amount);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Amount = amount;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("assetid", Required = Required.DisallowNull)]
|
||||
private string AssetIDText {
|
||||
get => AssetID.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong assetID) || (assetID == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(assetID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
AssetID = assetID;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("classid", Required = Required.DisallowNull)]
|
||||
private string ClassIDText {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong classID) || (classID == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassID = classID;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("contextid", Required = Required.DisallowNull)]
|
||||
private string ContextIDText {
|
||||
get => ContextID.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong contextID) || (contextID == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(contextID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ContextID = contextID;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("id", Required = Required.DisallowNull)]
|
||||
private string IDText {
|
||||
set => AssetIDText = value;
|
||||
}
|
||||
|
||||
[JsonProperty("instanceid", Required = Required.DisallowNull)]
|
||||
private string InstanceIDText {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong instanceID)) {
|
||||
ASF.ArchiLogger.LogNullError(instanceID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InstanceID = instanceID;
|
||||
}
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("id")]
|
||||
private ulong ID {
|
||||
get => AssetID;
|
||||
init => AssetID = value;
|
||||
}
|
||||
|
||||
// Constructed from trades being received or plugins
|
||||
|
@ -228,6 +145,9 @@ public sealed class Asset {
|
|||
[JsonConstructor]
|
||||
private Asset() { }
|
||||
|
||||
[UsedImplicitly]
|
||||
public static bool ShouldSerializeAdditionalProperties() => false;
|
||||
|
||||
internal Asset CreateShallowCopy() => (Asset) MemberwiseClone();
|
||||
|
||||
public enum ERarity : byte {
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
|
@ -30,8 +30,10 @@ namespace ArchiSteamFarm.Steam.Data;
|
|||
public class BooleanResponse {
|
||||
// You say it works in a RESTFUL way
|
||||
// Then your errors come back as 200 OK
|
||||
[JsonProperty("success", Required = Required.Always)]
|
||||
public bool Success { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("success")]
|
||||
[JsonRequired]
|
||||
public bool Success { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
protected BooleanResponse() { }
|
||||
|
|
|
@ -20,17 +20,21 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BoosterCreatorEntry {
|
||||
[JsonProperty("appid", Required = Required.Always)]
|
||||
public uint AppID { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("appid")]
|
||||
[JsonRequired]
|
||||
public uint AppID { get; private init; }
|
||||
|
||||
[JsonProperty("name", Required = Required.Always)]
|
||||
public string Name { get; private set; } = "";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("name")]
|
||||
[JsonRequired]
|
||||
public string Name { get; private init; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
private BoosterCreatorEntry() { }
|
||||
|
|
|
@ -20,25 +20,36 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[PublicAPI]
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class Confirmation {
|
||||
[JsonProperty(PropertyName = "nonce", Required = Required.Always)]
|
||||
internal readonly ulong Nonce;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("type")]
|
||||
[JsonRequired]
|
||||
public EConfirmationType ConfirmationType { get; private init; }
|
||||
|
||||
[JsonProperty(PropertyName = "type", Required = Required.Always)]
|
||||
public EConfirmationType ConfirmationType { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("creator_id")]
|
||||
[JsonRequired]
|
||||
public ulong CreatorID { get; private init; }
|
||||
|
||||
[JsonProperty(PropertyName = "creator_id", Required = Required.Always)]
|
||||
public ulong CreatorID { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("id")]
|
||||
[JsonRequired]
|
||||
public ulong ID { get; private init; }
|
||||
|
||||
[JsonProperty(PropertyName = "id", Required = Required.Always)]
|
||||
public ulong ID { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("nonce")]
|
||||
[JsonRequired]
|
||||
internal ulong Nonce { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private Confirmation() { }
|
||||
|
|
|
@ -20,13 +20,15 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
internal sealed class ConfirmationsResponse : BooleanResponse {
|
||||
[JsonProperty("conf", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<Confirmation> Confirmations = ImmutableHashSet<Confirmation>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("conf")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Confirmation> Confirmations { get; private init; } = ImmutableHashSet<Confirmation>.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
private ConfirmationsResponse() { }
|
||||
|
|
|
@ -24,80 +24,68 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Steam.Integration;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class InventoryResponse : OptionalResultResponse {
|
||||
[JsonProperty("assets", Required = Required.DisallowNull)]
|
||||
internal readonly ImmutableList<Asset> Assets = ImmutableList<Asset>.Empty;
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("assets")]
|
||||
internal ImmutableList<Asset> Assets { get; private init; } = ImmutableList<Asset>.Empty;
|
||||
|
||||
[JsonProperty("descriptions", Required = Required.DisallowNull)]
|
||||
internal readonly ImmutableHashSet<Description> Descriptions = ImmutableHashSet<Description>.Empty;
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("descriptions")]
|
||||
internal ImmutableHashSet<Description> Descriptions { get; private init; } = ImmutableHashSet<Description>.Empty;
|
||||
|
||||
[JsonProperty("total_inventory_count", Required = Required.DisallowNull)]
|
||||
internal readonly uint TotalInventoryCount;
|
||||
internal EResult? ErrorCode { get; private init; }
|
||||
internal string? ErrorText { get; private init; }
|
||||
|
||||
internal EResult? ErrorCode { get; private set; }
|
||||
internal string? ErrorText { get; private set; }
|
||||
internal ulong LastAssetID { get; private set; }
|
||||
internal bool MoreItems { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("last_assetid")]
|
||||
internal ulong LastAssetID { get; private init; }
|
||||
|
||||
[JsonProperty("error", Required = Required.DisallowNull)]
|
||||
internal bool MoreItems { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("total_inventory_count")]
|
||||
internal uint TotalInventoryCount { get; private init; }
|
||||
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("error")]
|
||||
private string Error {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
get => ErrorText ?? "";
|
||||
|
||||
return;
|
||||
}
|
||||
init {
|
||||
ArgumentException.ThrowIfNullOrEmpty(value);
|
||||
|
||||
ErrorCode = SteamUtilities.InterpretError(value);
|
||||
ErrorText = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("last_assetid", Required = Required.DisallowNull)]
|
||||
private string LastAssetIDText {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong lastAssetID) || (lastAssetID == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(lastAssetID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LastAssetID = lastAssetID;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("more_items", Required = Required.DisallowNull)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("more_items")]
|
||||
private byte MoreItemsNumber {
|
||||
set => MoreItems = value > 0;
|
||||
get => MoreItems ? (byte) 1 : (byte) 0;
|
||||
init => MoreItems = value > 0;
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private InventoryResponse() { }
|
||||
|
||||
internal sealed class Description {
|
||||
[JsonProperty("appid", Required = Required.Always)]
|
||||
internal readonly uint AppID;
|
||||
|
||||
[JsonProperty("tags", Required = Required.DisallowNull)]
|
||||
internal readonly ImmutableHashSet<Tag> Tags = ImmutableHashSet<Tag>.Empty;
|
||||
|
||||
internal Asset.ERarity Rarity {
|
||||
get {
|
||||
foreach (Tag tag in Tags) {
|
||||
|
@ -217,62 +205,49 @@ internal sealed class InventoryResponse : OptionalResultResponse {
|
|||
}
|
||||
}
|
||||
|
||||
[JsonExtensionData(WriteData = false)]
|
||||
internal Dictionary<string, JToken>? AdditionalProperties {
|
||||
get;
|
||||
[UsedImplicitly]
|
||||
set;
|
||||
}
|
||||
[JsonExtensionData]
|
||||
[JsonInclude]
|
||||
internal Dictionary<string, JsonElement>? AdditionalProperties { get; private init; }
|
||||
|
||||
internal ulong ClassID { get; private set; }
|
||||
internal ulong InstanceID { get; private set; }
|
||||
internal bool Marketable { get; private set; }
|
||||
internal bool Tradable { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("appid")]
|
||||
[JsonRequired]
|
||||
internal uint AppID { get; private init; }
|
||||
|
||||
[JsonProperty("classid", Required = Required.Always)]
|
||||
private string ClassIDText {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("classid")]
|
||||
[JsonRequired]
|
||||
internal ulong ClassID { get; private init; }
|
||||
|
||||
return;
|
||||
}
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("instanceid")]
|
||||
internal ulong InstanceID { get; private init; }
|
||||
|
||||
if (!ulong.TryParse(value, out ulong classID) || (classID == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(classID);
|
||||
internal bool Marketable { get; private init; }
|
||||
|
||||
return;
|
||||
}
|
||||
[JsonDisallowNull]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("tags")]
|
||||
internal ImmutableHashSet<Tag> Tags { get; private init; } = ImmutableHashSet<Tag>.Empty;
|
||||
|
||||
ClassID = classID;
|
||||
}
|
||||
}
|
||||
internal bool Tradable { get; private init; }
|
||||
|
||||
[JsonProperty("instanceid", Required = Required.DisallowNull)]
|
||||
private string InstanceIDText {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong instanceID)) {
|
||||
ASF.ArchiLogger.LogNullError(instanceID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InstanceID = instanceID;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("marketable", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("marketable")]
|
||||
[JsonRequired]
|
||||
private byte MarketableNumber {
|
||||
set => Marketable = value > 0;
|
||||
get => Marketable ? (byte) 1 : (byte) 0;
|
||||
init => Marketable = value > 0;
|
||||
}
|
||||
|
||||
[JsonProperty("tradable", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("tradable")]
|
||||
[JsonRequired]
|
||||
private byte TradableNumber {
|
||||
set => Tradable = value > 0;
|
||||
get => Tradable ? (byte) 1 : (byte) 0;
|
||||
init => Tradable = value > 0;
|
||||
}
|
||||
|
||||
// Constructed from trades being received/sent
|
||||
|
@ -293,5 +268,8 @@ internal sealed class InventoryResponse : OptionalResultResponse {
|
|||
|
||||
[JsonConstructor]
|
||||
private Description() { }
|
||||
|
||||
[UsedImplicitly]
|
||||
public static bool ShouldSerializeAdditionalProperties() => false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,16 @@
|
|||
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class NewDiscoveryQueueResponse {
|
||||
[JsonProperty("queue", Required = Required.Always)]
|
||||
internal readonly ImmutableHashSet<uint> Queue = ImmutableHashSet<uint>.Empty;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("queue")]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<uint> Queue { get; private init; } = ImmutableHashSet<uint>.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
private NewDiscoveryQueueResponse() { }
|
||||
|
|
|
@ -19,16 +19,17 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[PublicAPI]
|
||||
public class OptionalResultResponse {
|
||||
[JsonProperty("success", Required = Required.DisallowNull)]
|
||||
public EResult? Result { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("success")]
|
||||
public EResult? Result { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
protected OptionalResultResponse() { }
|
||||
|
|
|
@ -20,18 +20,20 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class RedeemWalletResponse : ResultResponse {
|
||||
[JsonProperty("formattednewwalletbalance", Required = Required.DisallowNull)]
|
||||
internal readonly string? BalanceText;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("formattednewwalletbalance")]
|
||||
internal string? BalanceText { get; private init; }
|
||||
|
||||
[JsonProperty("detail", Required = Required.DisallowNull)]
|
||||
internal readonly EPurchaseResultDetail PurchaseResultDetail;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("detail")]
|
||||
internal EPurchaseResultDetail PurchaseResultDetail { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private RedeemWalletResponse() { }
|
||||
|
|
|
@ -19,16 +19,18 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[PublicAPI]
|
||||
public class ResultResponse {
|
||||
[JsonProperty("success", Required = Required.Always)]
|
||||
public EResult Result { get; private set; }
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("success")]
|
||||
[JsonRequired]
|
||||
public EResult Result { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
protected ResultResponse() { }
|
||||
|
|
|
@ -20,19 +20,23 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
public sealed class Tag {
|
||||
[JsonProperty("category", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("category")]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
public string Identifier { get; private set; } = "";
|
||||
public string Identifier { get; private init; } = "";
|
||||
|
||||
[JsonProperty("internal_name", Required = Required.Always)]
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("internal_name")]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
public string Value { get; private set; } = "";
|
||||
public string Value { get; private init; } = "";
|
||||
|
||||
internal Tag(string identifier, string value) {
|
||||
ArgumentException.ThrowIfNullOrEmpty(identifier);
|
||||
|
|
|
@ -20,17 +20,19 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class TradeOfferAcceptResponse {
|
||||
[JsonProperty("strError", Required = Required.DisallowNull)]
|
||||
internal readonly string ErrorText = "";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("strError")]
|
||||
internal string? ErrorText { get; private init; }
|
||||
|
||||
[JsonProperty("needs_mobile_confirmation", Required = Required.DisallowNull)]
|
||||
internal readonly bool RequiresMobileConfirmation;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("needs_mobile_confirmation")]
|
||||
internal bool RequiresMobileConfirmation { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private TradeOfferAcceptResponse() { }
|
||||
|
|
|
@ -20,19 +20,25 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
internal sealed class TradeOfferSendRequest {
|
||||
[JsonProperty("me", Required = Required.Always)]
|
||||
internal readonly ItemList ItemsToGive = new();
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("me")]
|
||||
[JsonRequired]
|
||||
internal ItemList ItemsToGive { get; private init; } = new();
|
||||
|
||||
[JsonProperty("them", Required = Required.Always)]
|
||||
internal readonly ItemList ItemsToReceive = new();
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("them")]
|
||||
[JsonRequired]
|
||||
internal ItemList ItemsToReceive { get; private init; } = new();
|
||||
|
||||
internal sealed class ItemList {
|
||||
[JsonProperty("assets", Required = Required.Always)]
|
||||
internal readonly HashSet<Asset> Assets = [];
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("assets")]
|
||||
[JsonRequired]
|
||||
internal HashSet<Asset> Assets { get; private init; } = [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,39 +20,24 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ArchiSteamFarm.Core;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class TradeOfferSendResponse {
|
||||
[JsonProperty("strError", Required = Required.DisallowNull)]
|
||||
internal readonly string ErrorText = "";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("strError")]
|
||||
internal string? ErrorText { get; private init; }
|
||||
|
||||
[JsonProperty("needs_mobile_confirmation", Required = Required.DisallowNull)]
|
||||
internal readonly bool RequiresMobileConfirmation;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("needs_mobile_confirmation")]
|
||||
internal bool RequiresMobileConfirmation { get; private init; }
|
||||
|
||||
internal ulong TradeOfferID { get; private set; }
|
||||
|
||||
[JsonProperty("tradeofferid", Required = Required.DisallowNull)]
|
||||
private string TradeOfferIDText {
|
||||
set {
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
ASF.ArchiLogger.LogNullError(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ulong.TryParse(value, out ulong tradeOfferID) || (tradeOfferID == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(tradeOfferID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TradeOfferID = tradeOfferID;
|
||||
}
|
||||
}
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("tradeofferid")]
|
||||
internal ulong TradeOfferID { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private TradeOfferSendResponse() { }
|
||||
|
|
|
@ -22,18 +22,22 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using ArchiSteamFarm.Steam.Integration;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class UserPrivacy {
|
||||
[JsonProperty("eCommentPermission", Required = Required.Always)]
|
||||
internal readonly ECommentPermission CommentPermission;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("eCommentPermission")]
|
||||
[JsonRequired]
|
||||
internal ECommentPermission CommentPermission { get; private init; }
|
||||
|
||||
[JsonProperty("PrivacySettings", Required = Required.Always)]
|
||||
internal readonly PrivacySettings Settings = new();
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacySettings")]
|
||||
[JsonRequired]
|
||||
internal PrivacySettings Settings { get; private init; } = new();
|
||||
|
||||
// Constructed from privacy change request
|
||||
internal UserPrivacy(PrivacySettings settings, ECommentPermission commentPermission) {
|
||||
|
@ -51,23 +55,35 @@ internal sealed class UserPrivacy {
|
|||
private UserPrivacy() { }
|
||||
|
||||
internal sealed class PrivacySettings {
|
||||
[JsonProperty("PrivacyFriendsList", Required = Required.Always)]
|
||||
internal readonly ArchiHandler.EPrivacySetting FriendsList;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacyFriendsList")]
|
||||
[JsonRequired]
|
||||
internal ArchiHandler.EPrivacySetting FriendsList { get; private init; }
|
||||
|
||||
[JsonProperty("PrivacyInventory", Required = Required.Always)]
|
||||
internal readonly ArchiHandler.EPrivacySetting Inventory;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacyInventory")]
|
||||
[JsonRequired]
|
||||
internal ArchiHandler.EPrivacySetting Inventory { get; private init; }
|
||||
|
||||
[JsonProperty("PrivacyInventoryGifts", Required = Required.Always)]
|
||||
internal readonly ArchiHandler.EPrivacySetting InventoryGifts;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacyInventoryGifts")]
|
||||
[JsonRequired]
|
||||
internal ArchiHandler.EPrivacySetting InventoryGifts { get; private init; }
|
||||
|
||||
[JsonProperty("PrivacyOwnedGames", Required = Required.Always)]
|
||||
internal readonly ArchiHandler.EPrivacySetting OwnedGames;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacyOwnedGames")]
|
||||
[JsonRequired]
|
||||
internal ArchiHandler.EPrivacySetting OwnedGames { get; private init; }
|
||||
|
||||
[JsonProperty("PrivacyPlaytime", Required = Required.Always)]
|
||||
internal readonly ArchiHandler.EPrivacySetting Playtime;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacyPlaytime")]
|
||||
[JsonRequired]
|
||||
internal ArchiHandler.EPrivacySetting Playtime { get; private init; }
|
||||
|
||||
[JsonProperty("PrivacyProfile", Required = Required.Always)]
|
||||
internal readonly ArchiHandler.EPrivacySetting Profile;
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("PrivacyProfile")]
|
||||
[JsonRequired]
|
||||
internal ArchiHandler.EPrivacySetting Profile { get; private init; }
|
||||
|
||||
// Constructed from privacy change request
|
||||
internal PrivacySettings(ArchiHandler.EPrivacySetting profile, ArchiHandler.EPrivacySetting ownedGames, ArchiHandler.EPrivacySetting playtime, ArchiHandler.EPrivacySetting friendsList, ArchiHandler.EPrivacySetting inventory, ArchiHandler.EPrivacySetting inventoryGifts) {
|
||||
|
|
|
@ -30,11 +30,13 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Helpers.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
|
@ -42,8 +44,6 @@ using ArchiSteamFarm.Storage;
|
|||
using ArchiSteamFarm.Web;
|
||||
using ArchiSteamFarm.Web.Responses;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Integration;
|
||||
|
@ -167,7 +167,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
|||
string json = scriptNode.TextContent[startIndex..(endIndex + 1)];
|
||||
|
||||
try {
|
||||
result = JsonConvert.DeserializeObject<ImmutableHashSet<BoosterCreatorEntry>>(json);
|
||||
result = json.ToJsonObject<ImmutableHashSet<BoosterCreatorEntry>>();
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
|
@ -713,7 +713,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
|||
Dictionary<string, string> data = new(6, StringComparer.Ordinal) {
|
||||
{ "partner", steamID.ToString(CultureInfo.InvariantCulture) },
|
||||
{ "serverid", "1" },
|
||||
{ "trade_offer_create_params", !string.IsNullOrEmpty(token) ? new JObject { { "trade_offer_access_token", token } }.ToString(Formatting.None) : "" },
|
||||
{ "trade_offer_create_params", !string.IsNullOrEmpty(token) ? new JsonObject { { "trade_offer_access_token", token } }.ToJsonText() : "" },
|
||||
{ "tradeoffermessage", $"Sent by {SharedInfo.PublicIdentifier}/{SharedInfo.Version}" }
|
||||
};
|
||||
|
||||
|
@ -721,7 +721,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
|||
HashSet<ulong> mobileTradeOfferIDs = new(trades.Count);
|
||||
|
||||
foreach (TradeOfferSendRequest trade in trades) {
|
||||
data["json_tradeoffer"] = JsonConvert.SerializeObject(trade);
|
||||
data["json_tradeoffer"] = trade.ToJsonText();
|
||||
|
||||
ObjectResponse<TradeOfferSendResponse>? response = null;
|
||||
|
||||
|
@ -1578,7 +1578,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
|||
{ "ajax", "true" }
|
||||
};
|
||||
|
||||
ObjectResponse<JToken>? response = await UrlPostToJsonObjectWithSession<JToken>(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.ReturnServerErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors).ConfigureAwait(false);
|
||||
ObjectResponse<JsonNode>? response = await UrlPostToJsonObjectWithSession<JsonNode>(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.ReturnServerErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
return (EResult.Fail, EPurchaseResultDetail.Timeout);
|
||||
|
@ -1594,31 +1594,37 @@ public sealed class ArchiWebHandler : IDisposable {
|
|||
// There is not much we can do apart from trying to extract the result and returning it along with the OK and non-OK response, it's also why it doesn't make any sense to strong-type it
|
||||
EResult result = response.StatusCode.IsSuccessCode() ? EResult.OK : EResult.Fail;
|
||||
|
||||
if (response.Content is not JObject jObject) {
|
||||
if (response.Content is not JsonObject jsonObject) {
|
||||
// Who knows what piece of crap that is?
|
||||
return (result, EPurchaseResultDetail.NoDetail);
|
||||
}
|
||||
|
||||
byte? numberResult = jObject["purchaseresultdetail"]?.Value<byte>();
|
||||
try {
|
||||
byte? numberResult = jsonObject["purchaseresultdetail"]?.GetValue<byte>();
|
||||
|
||||
if (numberResult.HasValue) {
|
||||
return (result, (EPurchaseResultDetail) numberResult.Value);
|
||||
}
|
||||
if (numberResult.HasValue) {
|
||||
return (result, (EPurchaseResultDetail) numberResult.Value);
|
||||
}
|
||||
|
||||
// Attempt to do limited parsing from error message, if it exists that is
|
||||
string? errorMessage = jObject["error"]?.Value<string>();
|
||||
// Attempt to do limited parsing from error message, if it exists that is
|
||||
string? errorMessage = jsonObject["error"]?.GetValue<string>();
|
||||
|
||||
switch (errorMessage) {
|
||||
case null:
|
||||
case "":
|
||||
// Thanks Steam, very useful
|
||||
return (result, EPurchaseResultDetail.NoDetail);
|
||||
case "You got rate limited, try again in an hour.":
|
||||
return (result, EPurchaseResultDetail.RateLimited);
|
||||
default:
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(errorMessage), errorMessage));
|
||||
switch (errorMessage) {
|
||||
case null:
|
||||
case "":
|
||||
// Thanks Steam, very useful
|
||||
return (result, EPurchaseResultDetail.NoDetail);
|
||||
case "You got rate limited, try again in an hour.":
|
||||
return (result, EPurchaseResultDetail.RateLimited);
|
||||
default:
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(errorMessage), errorMessage));
|
||||
|
||||
return (result, EPurchaseResultDetail.ContactSupport);
|
||||
return (result, EPurchaseResultDetail.ContactSupport);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return (result, EPurchaseResultDetail.ContactSupport);
|
||||
}
|
||||
case HttpStatusCode.Unauthorized:
|
||||
// Let's convert this into something reasonable
|
||||
|
@ -1647,7 +1653,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
|||
// Extra entry for sessionID
|
||||
Dictionary<string, string> data = new(3, StringComparer.Ordinal) {
|
||||
{ "eCommentPermission", ((byte) userPrivacy.CommentPermission).ToString(CultureInfo.InvariantCulture) },
|
||||
{ "Privacy", JsonConvert.SerializeObject(userPrivacy.Settings) }
|
||||
{ "Privacy", userPrivacy.Settings.ToJsonText() }
|
||||
};
|
||||
|
||||
ObjectResponse<ResultResponse>? response = await UrlPostToJsonObjectWithSession<ResultResponse>(request, data: data).ConfigureAwait(false);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue