Compare commits

..

16 Commits

Author SHA1 Message Date
Archi
e6e82e19bd Cut excessive data from announcement
Now that we don't need to transmit whole inventory to the backend anymore, we can cut it to matchable types only
2023-01-14 15:08:28 +01:00
renovate[bot]
289e539c38 Update docker/build-push-action action to v3.3.0 2023-01-14 09:28:45 +00:00
ArchiBot
91f4e47ff6 Automatic translations update 2023-01-14 02:16:04 +00:00
Archi
18cd12040f Bump 2023-01-13 17:17:06 +01:00
Archi
55f7235a32 Misc 2023-01-13 17:16:15 +01:00
Archi
45d434e64e Misc 2023-01-13 10:43:45 +01:00
Łukasz Domeradzki
0261076021 Ignore QUIC exceptions (#2800)
* Ignore QUIC exceptions

See https://github.com/dotnet/runtime/issues/80111

* Update madness

* No i jaki jest twój problem ja się pytam
2023-01-13 10:40:37 +01:00
renovate[bot]
39650c6a4d Update ASF-ui digest to 80b91db 2023-01-13 05:07:57 +00:00
ArchiBot
a29c73e38f Automatic translations update 2023-01-13 02:40:35 +00:00
renovate[bot]
adfaf1e2f4 Update dependency JustArchiNET.Madness to v3.10.0 2023-01-12 17:52:10 +00:00
renovate[bot]
656e98944c Update ASF-ui digest to bdd72e1 2023-01-12 13:33:00 +00:00
Archi
84be0f8077 Misc
We can save some excessive memory I guess
2023-01-12 11:47:45 +01:00
Archi
8cc705feff Skip pointless announcements if possible 2023-01-12 11:42:04 +01:00
renovate[bot]
e248948002 Update swashbuckle-aspnetcore monorepo to v6.5.0 2023-01-12 02:36:40 +00:00
ArchiBot
a3ba0b680d Automatic translations update 2023-01-12 02:35:26 +00:00
Archi
ac5cd5c08b Bump 2023-01-11 20:22:37 +01:00
12 changed files with 77 additions and 36 deletions

View File

@@ -25,7 +25,7 @@ jobs:
uses: docker/setup-buildx-action@v2.2.1
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v3.3.0
with:
context: .
file: ${{ matrix.file }}

View File

@@ -55,7 +55,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile.Service
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v3.3.0
with:
context: .
file: Dockerfile.Service

View File

@@ -55,7 +55,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v3.3.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

View File

@@ -56,7 +56,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v3.3.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

2
ASF-ui

Submodule ASF-ui updated: d4efcd325e...80b91db274

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,7 +37,7 @@ using ArchiSteamFarm.Web.Responses;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
internal static class Backend {
internal static async Task<BasicResponse?> AnnounceForListing(Bot bot, WebBrowser webBrowser, IReadOnlyList<Asset> inventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes, string tradeToken, string? nickname = null, string? avatarHash = null) {
internal static async Task<BasicResponse?> AnnounceForListing(Bot bot, WebBrowser webBrowser, IReadOnlyCollection<AssetForListing> inventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes, string tradeToken, string? nickname = null, string? avatarHash = null) {
ArgumentNullException.ThrowIfNull(bot);
ArgumentNullException.ThrowIfNull(webBrowser);

View File

@@ -58,7 +58,7 @@ internal sealed class AnnouncementRequest {
[JsonProperty(Required = Required.Always)]
private readonly string TradeToken;
internal AnnouncementRequest(Guid guid, ulong steamID, string tradeToken, IReadOnlyList<Asset> inventory, IReadOnlyCollection<Asset.EType> matchableTypes, bool matchEverything, byte maxTradeHoldDuration, string? nickname = null, string? avatarHash = null) {
internal AnnouncementRequest(Guid guid, ulong steamID, string tradeToken, IReadOnlyCollection<AssetForListing> inventory, IReadOnlyCollection<Asset.EType> matchableTypes, bool matchEverything, byte maxTradeHoldDuration, string? nickname = null, string? avatarHash = null) {
if (guid == Guid.Empty) {
throw new ArgumentOutOfRangeException(nameof(guid));
}
@@ -83,22 +83,10 @@ internal sealed class AnnouncementRequest {
throw new ArgumentNullException(nameof(matchableTypes));
}
uint index = 0;
ulong previousAssetID = 0;
Guid = guid;
SteamID = steamID;
TradeToken = tradeToken;
HashSet<AssetForListing> assetsForListing = new(inventory.Count);
foreach (Asset asset in inventory) {
assetsForListing.Add(new AssetForListing(asset, index++, previousAssetID));
previousAssetID = asset.AssetID;
}
Inventory = assetsForListing.ToImmutableHashSet();
Inventory = inventory.ToImmutableHashSet();
MatchableTypes = matchableTypes.ToImmutableHashSet();
MatchEverything = matchEverything;
MaxTradeHoldDuration = maxTradeHoldDuration;

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -45,7 +45,7 @@ using ArchiSteamFarm.Web.Responses;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
private const byte MaxAnnouncementTTL = 180; // Maximum amount of minutes we can wait before the next Announcement
private const byte MaxAnnouncementTTL = 60; // Maximum amount of minutes we can wait if the next announcement doesn't happen naturally
private const byte MinAnnouncementTTL = 5; // Minimum amount of minutes we must wait before the next Announcement
private const byte MinHeartBeatTTL = 10; // Minimum amount of minutes we must wait before sending next HeartBeat
private const byte MinItemsCount = 100; // Minimum amount of items to be eligible for public listing
@@ -58,6 +58,9 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
Asset.EType.TradingCard
);
// We access this collection only within a semaphore, therefore there is no need for concurrent access
private readonly Dictionary<ulong, uint> AnnouncedItems = new();
private readonly Bot Bot;
private readonly Timer? HeartBeatTimer;
private readonly SemaphoreSlim MatchActivelySemaphore = new(1, 1);
@@ -205,6 +208,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
// We require to fetch whole inventory as a list here, as we need to know the order for calculating index and previousAssetID
List<Asset> inventory;
try {
@@ -225,8 +229,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
// This is actual inventory
if (inventory.Count(item => item.Tradable && acceptedMatchableTypes.Contains(item.Type)) < MinItemsCount) {
if (inventory.Count < MinItemsCount) {
// We're not eligible, record this as a valid check
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false;
@@ -234,6 +237,41 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
uint index = 0;
ulong previousAssetID = 0;
HashSet<AssetForListing> assetsForListing = new();
uint tradableCount = 0;
foreach (Asset asset in inventory) {
if (acceptedMatchableTypes.Contains(asset.Type)) {
if (asset.Tradable) {
tradableCount++;
}
assetsForListing.Add(new AssetForListing(asset, index++, previousAssetID));
}
previousAssetID = asset.AssetID;
}
if (tradableCount < MinItemsCount) {
// We're not eligible, record this as a valid check
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false;
return;
}
if (ShouldSendHeartBeats && (assetsForListing.Count == AnnouncedItems.Count) && assetsForListing.All(item => AnnouncedItems.TryGetValue(item.AssetID, out uint amount) && (item.Amount == amount))) {
// There is nothing new to announce, this is fine, skip the request
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = false;
return;
}
if (!SignedInWithSteam) {
HttpStatusCode? signInWithSteam = await ArchiNet.SignInWithSteam(Bot, WebBrowser).ConfigureAwait(false);
@@ -255,10 +293,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
SignedInWithSteam = true;
}
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname, inventory.Count));
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname, assetsForListing.Count));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
BasicResponse? response = await Backend.AnnounceForListing(Bot, WebBrowser, inventory, acceptedMatchableTypes, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
BasicResponse? response = await Backend.AnnounceForListing(Bot, WebBrowser, assetsForListing, acceptedMatchableTypes, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
if (response == null) {
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
@@ -320,10 +358,18 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
ShouldSendAnnouncementEarlier = false;
ShouldSendHeartBeats = true;
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
AnnouncedItems.Clear();
foreach (AssetForListing item in assetsForListing) {
AnnouncedItems[item.AssetID] = item.Amount;
}
AnnouncedItems.TrimExcess();
} finally {
RequestsSemaphore.Release();
}
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
}
internal void TriggerMatchActivelyEarlier() {

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -43,6 +43,9 @@ using Newtonsoft.Json;
using NLog;
using NLog.Targets;
using SteamKit2;
#if !NETFRAMEWORK
using System.Net.Quic;
#endif
namespace ArchiSteamFarm;
@@ -539,7 +542,10 @@ internal static class Program {
ArgumentNullException.ThrowIfNull(e);
ArgumentNullException.ThrowIfNull(e.Exception);
await ASF.ArchiLogger.LogFatalException(e.Exception).ConfigureAwait(false);
// TODO: Remove conditionally ignoring QuicException once https://github.com/dotnet/runtime/issues/80111 is resolved
if ((e.Exception.InnerExceptions.Count == 0) || e.Exception.InnerExceptions.All(static exception => exception is not QuicException)) {
await ASF.ArchiLogger.LogFatalException(e.Exception).ConfigureAwait(false);
}
// Normally we should abort the application, but due to the fact that unobserved exceptions do not have to do that, it's a better idea to log it and try to continue
e.SetObserved();

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>5.4.2.0</Version>
<Version>5.4.2.2</Version>
</PropertyGroup>
<PropertyGroup>
@@ -56,6 +56,7 @@
<Using Include="JustArchiNET.Madness.HttpRequestExceptionMadness.HttpRequestException" Alias="HttpRequestException" />
<Using Include="JustArchiNET.Madness.OperatingSystemMadness.OperatingSystem" Alias="OperatingSystem" />
<Using Include="JustArchiNET.Madness.PathMadness.Path" Alias="Path" />
<Using Include="JustArchiNET.Madness.QuicExceptionMadness.QuicException" Alias="QuicException" />
<Using Include="JustArchiNET.Madness.RandomMadness.Random" Alias="Random" />
<Using Include="JustArchiNET.Madness.SHA256Madness.SHA256" Alias="SHA256" />
<Using Include="JustArchiNET.Madness.SHA512Madness.SHA512" Alias="SHA512" />

View File

@@ -13,9 +13,9 @@
<PackageVersion Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageVersion Include="NLog.Web.AspNetCore" Version="5.2.1" />
<PackageVersion Include="SteamKit2" Version="2.4.1" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.5.0" />
<PackageVersion Include="System.Composition" Version="7.0.0" />
<PackageVersion Include="System.Composition.AttributedModel" Version="7.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
@@ -27,7 +27,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<PackageVersion Include="JustArchiNET.Madness" Version="3.9.0" />
<PackageVersion Include="JustArchiNET.Madness" Version="3.10.0" />
<PackageVersion Include="Microsoft.AspNetCore.Cors" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />

2
wiki

Submodule wiki updated: 79da627b6e...708dedda60