mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-06 17:10:13 +00:00
Closes #515
This commit is contained in:
@@ -459,6 +459,15 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsBlacklistedFromTrades(ulong steamID) {
|
||||
if (steamID != 0) {
|
||||
return BotDatabase.IsBlacklistedFromTrades(steamID);
|
||||
}
|
||||
|
||||
ArchiLogger.LogNullError(nameof(steamID));
|
||||
return false;
|
||||
}
|
||||
|
||||
internal bool IsMaster(ulong steamID) {
|
||||
if (steamID == 0) {
|
||||
ArchiLogger.LogNullError(nameof(steamID));
|
||||
@@ -607,6 +616,8 @@ namespace ArchiSteamFarm {
|
||||
return await Response2FAConfirm(steamID, true).ConfigureAwait(false);
|
||||
case "!API":
|
||||
return ResponseAPI(steamID);
|
||||
case "!BL":
|
||||
return ResponseBlacklist(steamID);
|
||||
case "!EXIT":
|
||||
return ResponseExit(steamID);
|
||||
case "!FARM":
|
||||
@@ -660,6 +671,20 @@ namespace ArchiSteamFarm {
|
||||
return await ResponseAddLicense(steamID, args[1]).ConfigureAwait(false);
|
||||
case "!API":
|
||||
return ResponseAPI(steamID, args[1]);
|
||||
case "!BL":
|
||||
return await ResponseBlacklist(steamID, args[1]).ConfigureAwait(false);
|
||||
case "!BLADD":
|
||||
if (args.Length > 2) {
|
||||
return await ResponseBlacklistAdd(steamID, args[1], args[2]).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ResponseBlacklistAdd(steamID, args[1]);
|
||||
case "!BLRM":
|
||||
if (args.Length > 2) {
|
||||
return await ResponseBlacklistRemove(steamID, args[1], args[2]).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ResponseBlacklistRemove(steamID, args[1]);
|
||||
case "!FARM":
|
||||
return await ResponseFarm(steamID, args[1]).ConfigureAwait(false);
|
||||
case "!INPUT":
|
||||
@@ -2108,6 +2133,168 @@ namespace ArchiSteamFarm {
|
||||
return GetAPIStatus(Bots.Where(kv => bots.Contains(kv.Value) && kv.Value.IsMaster(steamID)).ToDictionary(kv => kv.Key, kv => kv.Value));
|
||||
}
|
||||
|
||||
private static async Task<string> ResponseBlacklist(ulong steamID, string botNames) {
|
||||
if ((steamID == 0) || string.IsNullOrEmpty(botNames)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames));
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<Bot> bots = GetBots(botNames);
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return IsOwner(steamID) ? FormatStaticResponse(string.Format(Strings.BotNotFound, botNames)) : null;
|
||||
}
|
||||
|
||||
ICollection<string> results;
|
||||
IEnumerable<Task<string>> tasks = bots.Select(bot => Task.Run(() => bot.ResponseBlacklist(steamID)));
|
||||
|
||||
switch (Program.GlobalConfig.OptimizationMode) {
|
||||
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
|
||||
results = new List<string>(bots.Count);
|
||||
foreach (Task<string> task in tasks) {
|
||||
results.Add(await task.ConfigureAwait(false));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
List<string> responses = new List<string>(results.Where(result => !string.IsNullOrEmpty(result)));
|
||||
return responses.Count > 0 ? string.Join("", responses) : null;
|
||||
}
|
||||
|
||||
private string ResponseBlacklist(ulong steamID) {
|
||||
if (steamID != 0) {
|
||||
return IsMaster(steamID) ? FormatBotResponse(string.Join(", ", BotDatabase.GetBlacklistedFromTradesSteamIDs())) : null;
|
||||
}
|
||||
|
||||
ArchiLogger.LogNullError(nameof(steamID));
|
||||
return null;
|
||||
}
|
||||
|
||||
private string ResponseBlacklistAdd(ulong steamID, string targetsText) {
|
||||
if ((steamID == 0) || string.IsNullOrEmpty(targetsText)) {
|
||||
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(targetsText));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!IsMaster(steamID)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] targets = targetsText.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
HashSet<ulong> targetIDs = new HashSet<ulong>();
|
||||
foreach (string target in targets) {
|
||||
ulong targetID;
|
||||
if (!ulong.TryParse(target, out targetID) || (targetID == 0)) {
|
||||
return FormatBotResponse(string.Format(Strings.ErrorParsingObject, nameof(targetID)));
|
||||
}
|
||||
|
||||
targetIDs.Add(targetID);
|
||||
}
|
||||
|
||||
if (targetIDs.Count == 0) {
|
||||
return FormatBotResponse(string.Format(Strings.ErrorIsEmpty, nameof(targetIDs)));
|
||||
}
|
||||
|
||||
BotDatabase.AddBlacklistedFromTradesSteamIDs(targetIDs);
|
||||
return FormatBotResponse(Strings.Done);
|
||||
}
|
||||
|
||||
private static async Task<string> ResponseBlacklistAdd(ulong steamID, string botNames, string targetsText) {
|
||||
if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetsText)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetsText));
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<Bot> bots = GetBots(botNames);
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return IsOwner(steamID) ? FormatStaticResponse(string.Format(Strings.BotNotFound, botNames)) : null;
|
||||
}
|
||||
|
||||
ICollection<string> results;
|
||||
IEnumerable<Task<string>> tasks = bots.Select(bot => Task.Run(() => bot.ResponseBlacklistAdd(steamID, targetsText)));
|
||||
|
||||
switch (Program.GlobalConfig.OptimizationMode) {
|
||||
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
|
||||
results = new List<string>(bots.Count);
|
||||
foreach (Task<string> task in tasks) {
|
||||
results.Add(await task.ConfigureAwait(false));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
List<string> responses = new List<string>(results.Where(result => !string.IsNullOrEmpty(result)));
|
||||
return responses.Count > 0 ? string.Join("", responses) : null;
|
||||
}
|
||||
|
||||
private static async Task<string> ResponseBlacklistRemove(ulong steamID, string botNames, string targetsText) {
|
||||
if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetsText)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetsText));
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<Bot> bots = GetBots(botNames);
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return IsOwner(steamID) ? FormatStaticResponse(string.Format(Strings.BotNotFound, botNames)) : null;
|
||||
}
|
||||
|
||||
ICollection<string> results;
|
||||
IEnumerable<Task<string>> tasks = bots.Select(bot => Task.Run(() => bot.ResponseBlacklistRemove(steamID, targetsText)));
|
||||
|
||||
switch (Program.GlobalConfig.OptimizationMode) {
|
||||
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
|
||||
results = new List<string>(bots.Count);
|
||||
foreach (Task<string> task in tasks) {
|
||||
results.Add(await task.ConfigureAwait(false));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
List<string> responses = new List<string>(results.Where(result => !string.IsNullOrEmpty(result)));
|
||||
return responses.Count > 0 ? string.Join("", responses) : null;
|
||||
}
|
||||
|
||||
private string ResponseBlacklistRemove(ulong steamID, string targetsText) {
|
||||
if ((steamID == 0) || string.IsNullOrEmpty(targetsText)) {
|
||||
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(targetsText));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!IsMaster(steamID)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] targets = targetsText.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
HashSet<ulong> targetIDs = new HashSet<ulong>();
|
||||
foreach (string target in targets) {
|
||||
ulong targetID;
|
||||
if (!ulong.TryParse(target, out targetID) || (targetID == 0)) {
|
||||
return FormatBotResponse(string.Format(Strings.ErrorParsingObject, nameof(targetID)));
|
||||
}
|
||||
|
||||
targetIDs.Add(targetID);
|
||||
}
|
||||
|
||||
if (targetIDs.Count == 0) {
|
||||
return FormatBotResponse(string.Format(Strings.ErrorIsEmpty, nameof(targetIDs)));
|
||||
}
|
||||
|
||||
BotDatabase.RemoveBlacklistedFromTradesSteamIDs(targetIDs);
|
||||
return FormatBotResponse(Strings.Done);
|
||||
}
|
||||
|
||||
private static string ResponseExit(ulong steamID) {
|
||||
if (steamID == 0) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
@@ -30,6 +31,9 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class BotDatabase {
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentHashSet<ulong> BlacklistedFromTradesSteamIDs = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private readonly object FileLock = new object();
|
||||
|
||||
internal string LoginKey {
|
||||
@@ -80,6 +84,28 @@ namespace ArchiSteamFarm {
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||
private BotDatabase() { }
|
||||
|
||||
internal void AddBlacklistedFromTradesSteamIDs(HashSet<ulong> steamIDs) {
|
||||
if ((steamIDs == null) || (steamIDs.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
if (BlacklistedFromTradesSteamIDs.AddRange(steamIDs)) {
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<ulong> GetBlacklistedFromTradesSteamIDs() => BlacklistedFromTradesSteamIDs;
|
||||
|
||||
internal bool IsBlacklistedFromTrades(ulong steamID) {
|
||||
if (steamID != 0) {
|
||||
return BlacklistedFromTradesSteamIDs.Contains(steamID);
|
||||
}
|
||||
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static BotDatabase Load(string filePath) {
|
||||
if (string.IsNullOrEmpty(filePath)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(filePath));
|
||||
@@ -108,6 +134,17 @@ namespace ArchiSteamFarm {
|
||||
return botDatabase;
|
||||
}
|
||||
|
||||
internal void RemoveBlacklistedFromTradesSteamIDs(HashSet<ulong> steamIDs) {
|
||||
if ((steamIDs == null) || (steamIDs.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(steamIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
if (BlacklistedFromTradesSteamIDs.RemoveRange(steamIDs)) {
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Save() {
|
||||
string json = JsonConvert.SerializeObject(this);
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nito.AsyncEx;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class ConcurrentHashSet<T> : ICollection<T> {
|
||||
internal sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ISet<T> {
|
||||
public int Count {
|
||||
get {
|
||||
using (Lock.ReaderLock()) {
|
||||
@@ -41,6 +42,12 @@ namespace ArchiSteamFarm {
|
||||
private readonly HashSet<T> HashSet = new HashSet<T>();
|
||||
private readonly AsyncReaderWriterLock Lock = new AsyncReaderWriterLock();
|
||||
|
||||
public bool Add(T item) {
|
||||
using (Lock.WriterLock()) {
|
||||
return HashSet.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
using (Lock.WriterLock()) {
|
||||
HashSet.Clear();
|
||||
@@ -59,21 +66,82 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
public void ExceptWith(IEnumerable<T> other) {
|
||||
using (Lock.WriterLock()) {
|
||||
HashSet.ExceptWith(other);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator() => new ConcurrentEnumerator<T>(HashSet, Lock);
|
||||
|
||||
public void IntersectWith(IEnumerable<T> other) {
|
||||
using (Lock.WriterLock()) {
|
||||
HashSet.IntersectWith(other);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsProperSubsetOf(IEnumerable<T> other) {
|
||||
using (Lock.ReaderLock()) {
|
||||
return HashSet.IsProperSubsetOf(other);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsProperSupersetOf(IEnumerable<T> other) {
|
||||
using (Lock.ReaderLock()) {
|
||||
return HashSet.IsProperSupersetOf(other);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSubsetOf(IEnumerable<T> other) {
|
||||
using (Lock.ReaderLock()) {
|
||||
return HashSet.IsSubsetOf(other);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSupersetOf(IEnumerable<T> other) {
|
||||
using (Lock.ReaderLock()) {
|
||||
return HashSet.IsSupersetOf(other);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Overlaps(IEnumerable<T> other) {
|
||||
using (Lock.ReaderLock()) {
|
||||
return HashSet.Overlaps(other);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(T item) {
|
||||
using (Lock.WriterLock()) {
|
||||
return HashSet.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetEquals(IEnumerable<T> other) {
|
||||
using (Lock.ReaderLock()) {
|
||||
return HashSet.SetEquals(other);
|
||||
}
|
||||
}
|
||||
|
||||
public void SymmetricExceptWith(IEnumerable<T> other) {
|
||||
using (Lock.WriterLock()) {
|
||||
HashSet.SymmetricExceptWith(other);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnionWith(IEnumerable<T> other) {
|
||||
using (Lock.WriterLock()) {
|
||||
HashSet.UnionWith(other);
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection<T>.Add(T item) => Add(item);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
internal void Add(T item) {
|
||||
internal bool AddRange(IEnumerable<T> items) {
|
||||
using (Lock.WriterLock()) {
|
||||
HashSet.Add(item);
|
||||
// We use Count() and not Any() because we must ensure full loop pass
|
||||
return items.Count(item => HashSet.Add(item)) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +152,13 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
internal bool RemoveRange(IEnumerable<T> items) {
|
||||
using (Lock.WriterLock()) {
|
||||
// We use Count() and not Any() because we must ensure full loop pass
|
||||
return items.Count(item => HashSet.Remove(item)) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ReplaceIfNeededWith(ICollection<T> items) {
|
||||
using (AsyncReaderWriterLock.UpgradeableReaderKey readerKey = Lock.UpgradeableReaderLock()) {
|
||||
if (HashSet.SetEquals(items)) {
|
||||
|
||||
@@ -177,9 +177,16 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Always accept trades from SteamMasterID
|
||||
if ((tradeOffer.OtherSteamID64 != 0) && Bot.IsMaster(tradeOffer.OtherSteamID64)) {
|
||||
return new ParseTradeResult(tradeOffer.TradeOfferID, tradeOffer.ItemsToGive.Count > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : ParseTradeResult.EResult.AcceptedWithoutItemLose);
|
||||
if (tradeOffer.OtherSteamID64 != 0) {
|
||||
// Always accept trades from SteamMasterID
|
||||
if (Bot.IsMaster(tradeOffer.OtherSteamID64)) {
|
||||
return new ParseTradeResult(tradeOffer.TradeOfferID, tradeOffer.ItemsToGive.Count > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : ParseTradeResult.EResult.AcceptedWithoutItemLose);
|
||||
}
|
||||
|
||||
// Always deny trades from blacklistem steamIDs
|
||||
if (Bot.IsBlacklistedFromTrades(tradeOffer.OtherSteamID64)) {
|
||||
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's donation trade
|
||||
|
||||
Reference in New Issue
Block a user