mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-24 10:16:49 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6e82e19bd | ||
|
|
289e539c38 | ||
|
|
91f4e47ff6 | ||
|
|
18cd12040f | ||
|
|
55f7235a32 | ||
|
|
45d434e64e | ||
|
|
0261076021 | ||
|
|
39650c6a4d | ||
|
|
a29c73e38f | ||
|
|
adfaf1e2f4 | ||
|
|
656e98944c | ||
|
|
84be0f8077 | ||
|
|
8cc705feff | ||
|
|
e248948002 | ||
|
|
a3ba0b680d | ||
|
|
ac5cd5c08b |
2
.github/workflows/docker-ci.yml
vendored
2
.github/workflows/docker-ci.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/docker-publish-latest.yml
vendored
2
.github/workflows/docker-publish-latest.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/docker-publish-main.yml
vendored
2
.github/workflows/docker-publish-main.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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
2
ASF-ui
Submodule ASF-ui updated: d4efcd325e...80b91db274
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
2
wiki
Submodule wiki updated: 79da627b6e...708dedda60
Reference in New Issue
Block a user